지돌이의 블로그 입니다!

https://github.com/jc-lab/node-app

 

jc-lab/node-app

Embed node.js application with VFS(Virtual File System) - jc-lab/node-app

github.com

삽질의 결과!ㅠㅠ

결과는 간단한데 과정이 힘들었음..

Comment +0

될줄 알았죠?

안돼요...ㅠㅠ

이 글을 보면 해결책이 있을줄 알았죠?

없어요...^^ 최소한 C++ 자체 라이브러리 안에서는....ㅠㅠ

아래와 같이 따로 만들면은 됩니다!

#include <iostream>
#include <memory>
#include <functional>
#include <tuple>

class Caller {
public:
	virtual void run() = 0;
};

template<typename F, typename Tuple>
class Binder : public Caller
{
protected:
	F f_;
	std::size_t args_count_
		= std::tuple_size<typename std::remove_reference<Tuple>::type>::value;
	Tuple tuple_;

public:
	Binder(F f, Tuple&& tuple) : f_(f), tuple_(std::move(tuple)) {
		std::cout << "args_count_ : " << args_count_ << std::endl;
	}
	
	template<typename F, typename Tuple, size_t ...S >
	void run_impl(F&& fn, Tuple&& t, std::index_sequence<S...>)
	{
		return std::forward<F>(fn)(std::get<S>(std::forward<Tuple>(t))...);
	}

	void run() override {
		std::size_t constexpr tSize
			= std::tuple_size<typename std::remove_reference<Tuple>::type>::value;

		run_impl(std::forward<F>(f_),
			std::forward<Tuple>(tuple_),
			std::make_index_sequence<tSize>());
	}
};

template<class F, class... Args>
std::unique_ptr<Caller> mybind(F&& f, Args ... args) {
	return std::make_unique<Binder<F, std::tuple<Args...>>>(f, std::make_tuple(std::forward<Args>(args)...));
}

int main()
{
	std::unique_ptr<std::string> temp(new std::string("TEST1234"));

	std::unique_ptr<Caller> caller = mybind([](std::unique_ptr<std::string> temp, int a, int b) {
		std::cout << *temp << std::endl;
		}, std::move(temp), 10, 20);

	caller->run();

	return 0;
}

Comment +0

테스트코드

#include <iostream>
#include <memory>
#include <functional>
#include <ctime>

std::function<int(int,int)> temp_s;
std::unique_ptr<std::function<int(int,int)>> temp_u;

void test_1()
{
    for(int i=0; i<1000000; i++) {
        std::function<int(int,int)> copy = temp_s;
        copy(10, 20);
    }
}

void test_2()
{
    for(int i=0; i<1000000; i++) {
        temp_s(10, 20);
    }
}

void test_3()
{
    for(int i=0; i<1000000; i++) {
        (*temp_u)(10, 20);
    }
}

int main()
{
    temp_s = [](int a, int b) -> int { return a + b; };
    temp_u = std::make_unique<std::function<int(int,int)>>([](int a, int b) -> int { return a + b; });
    {
        const clock_t start = clock();
        test_1();
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "with copy: " << secs << " secs.\n";
    }
    {
        const clock_t start = clock();
        test_2();
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "without copy: " << secs << " secs.\n";
    }
    {
        const clock_t start = clock();
        test_3();
        const double secs = (clock()-start) / double(CLOCKS_PER_SEC);
        std::cout << "using unique_ptr: " << secs << " secs.\n";
    }
    
    return 0;
}

결과 :

with copy: 0.088981 secs.                                                                                                                      

without copy: 0.028533 secs.                                                                                                                   

using unique_ptr: 0.046483 secs. 

Comment +0

 그냥 오늘 개발하면서.. spring-boot프로젝트 한번 켜고 테스트하는데 파일몇개 안되는 프로젝트인데도 40초(빌드제외)가 걸려서.. 너무 답답해서 속도를 올리기 위한 삽질을 좀 해봤습니다.

 

1. .gradle디렉터리를 램디스크 바꿈.

https://jsty.tistory.com/180

위는 제 블로그인데요 여기서 소개한 램디스크를 썼습니다.

램디스크 생성하고 꺼질 때 자동저장되게 해서 10GB의 용량을 잡아주었습니다. (덕분에 컴퓨터끄는시간이 3분정도 더 걸립니다...ㄷㄷ)

그리고 Users/name/.gradle 파일을 복사하고 정션으로 링크해주었습니다.

(오우.. 기존 파일 옮기는데만 20분이 걸렸습니다.. 용량은 7GB정도.. 윈도 탐색기복사가 넘 느려서 FastCopy란 프로그램을 썼습니다. (큐랑 버퍼사이즈 키워야 빠름))

 

빌드 및 dependency관련 속도가 빨라졌습니다.

 

근데 프로젝트시작하는데 40초가 걸리는건 마찬가지..

 

2. spring boot프로젝트의 프로퍼티에 debug=true 추가하고 실행하면 콘솔에 Conditional 매치 결과등이 나옵니다. 거기서 사용하지 않아도 되는 것들을 찾아서 dependency에서 지워줍니다. dependency에서 지울 수 없다면 프로퍼티에서 enabled=false으로 해당 기능을 정지시킵니다.

 

몇가지 없앴더니 20초대로 줄어들었습니다.

좀 낫습니다.

 

 

그런데 이보다 더 빠르게 하고싶은데..

소스를 뜯어고칠 차례인가 봅니다..

 

3. Visual Studio 활용법

 

CPU성능은 좋은데.. 빌드할 때 CPU성능을 100%활용하지 못하더라구요.. IO병목현상이라 생각되었습니다.

 

C:\Users\(이름)\AppData\Local\Temp 을 램디스크로 정션을 만들고 빌드했더니

 

모든 코어 100%로 사용하면서 빌드가 됩니다! 빌드 속도도 눈에띄게 향상되었네요~

(물론 컴파일옵션에서 /MP (멀티쓰레드 컴파일)을 설정해야합니다.)

 

 

지난번 쓴 글에 램디스크관련 글이 있습니다.

https://jsty.tistory.com/180

 

Dataram RAMDisk 속도측정/비교

컴파일 속도 향상을 위해 Ramdisk를 찾다가.. Dataram RAMDisk 이라는 것이 있어서 설치 및 테스트를 해 보았다. CDM으로 테스트한 결과이고 아래는 작업관리자에서 본 평균응답시간이다. 설명처럼 좌측의 결과..

ablog.jc-lab.net

사용한 램디스크 :

datagram 홈페이지 가기

Comment +0

#include <iostream>

class input_buf : public std::streambuf
{
public:
    char read_buf_[32];
    int read_pos_;
    int read_limit_;

    input_buf()
    {
        int i;
        for (i = 0; i < 32; i++) {
            if(i < 26)
                read_buf_[i] = 'a' + i;
            else
                read_buf_[i] = 'A' + (i - 26);
        }

        read_pos_ = 0;
        read_limit_ = 32;
    }

    int_type underflow() override
    {
        // 읽을 데이터가 없으면 EOF를 알린다
        int_type ret = traits_type::eof();

        // istream에서 더이상 버퍼에서 읽을게 없으면(setg로 설정한 포인터에 대해 읽기가 끝났으면) 호출됨

        std::cout << "underflow() called" << std::endl;

        if (read_pos_ < read_limit_) {
            // 읽을 데이터가 있으면

            // 읽을 버퍼 주소를 설정해준다.
            // setg(first, next, end)
            this->setg(&read_buf_[read_pos_], &read_buf_[read_pos_], &read_buf_[read_pos_ + 8]);

            // The character at the current position of the controlled input sequence, as a value of type int.
            // 현재 위치의 값을 리턴함
            ret = read_buf_[read_pos_];

            read_pos_ += 8;
        }

        return ret;
    }

};

int main()
{
    input_buf buf;
    std::istream is(&buf);
    int i;


    for (i = 0; i < 100; i++) {
        char c;
        if (!(is >> c))
            break;
        printf("read byte : %c\n", c);
    }

    std::cout << "\nDONE\n";

    return 0;
}
underflow() called
read byte : a
read byte : b
read byte : c
read byte : d
read byte : e
read byte : f
read byte : g
read byte : h
underflow() called
read byte : i
read byte : j
read byte : k
read byte : l
read byte : m
read byte : n
read byte : o
read byte : p
underflow() called
read byte : q
read byte : r
read byte : s
read byte : t
read byte : u
read byte : v
read byte : w
read byte : x
underflow() called
read byte : y
read byte : z
read byte : A
read byte : B
read byte : C
read byte : D
read byte : E
read byte : F
underflow() called

DONE

Comment +0

https://gist.github.com/jc-lab/773d809053184529b52a4089aab72a9e

 

EjbcaConnector.java

EjbcaConnector.java. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

별건 아니구 EjbcaWS 연결할 때 인증서 검증 및 클라이언트 인증서 필요한데 Keystore파일이 아닌 KeyStore객체에서 가져오도록 한 것.

 

물론 좀더 수정 필요

Comment +0

C++ & AFX(MFC) 환경에서 사용자 정의 메세지 사용하면서 SendMessage으로 메세지 호출할 떄...

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

위와 같은 오류가 났던 경우가 있었습니다.

이틀동안 엄청 삽질했는데... 보통 이런경우 메모리가 꼬여서 (Overflow/일부 메모리 free등) 문제가 발생했었는데...

쨋든 이번에는 상속과 관련된 복잡한 문제였다.

일단 소스 구조는 아래와 같았다.

class ITestWindow {
public:
    virtual afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam) = 0;
};

class CTestWindow : public CFrameWnd, public ITestWindow
{
public:
    afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam) override { ... }
}

BEGIN_MESSAGE_MAP(CTestWindow, CFrameWnd)
    ON_MESSAGE(WM_MYMSG, OnMyMsg)
END_MESSAGE_MAP()

이런 상황에서

CTestWindow *wnd;
wnd->SendMessage(WM_MYMSG); // 이런 경우에...

wincore.cppCWnd::OnWndMsg 에서 해당 Run-time check error가 떴었다.

해당 함수는 지정한 MessageMap에서 해당 메서드를 콜백하는 부분인데..

좀 더 원인을 찾아보니 OnMyMsg가 아니라 완전 다른 메서드(~CTestWindow())가 호출되어버렸다...

(뭐야이게????)

암튼 결론은.. 아래와 같이

class ITestWindow {
public:
    // virtual afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam) = 0; 지워버림
};

class CTestWindow : public CFrameWnd, public ITestWindow
{
public:
    afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam) /* override 지움 */ { ... }
}

이렇게 virtual method를 사용하지 않음으로써 해결했다...

Comment +0

GQCS = GetQueuedCompletionStatus

비동기 처리 함수들 (WSARecv, WSASend, WriteFile, ReadFile 등)

  • 비동기 처리 개수만큼 GQCS 결과 발생

  • GQCS의 return이 FALSE일 경우에도 key 및 lpOverlapped가 NULL이 아닌 경우에는 해당 이벤트에 대한 처리가 필요함 (이런 경우에는 해당 핸들에 오류가 발생한 것으로 GetLastError으로 오류결과 받을 수 있고 해당 핸들에 대한 정리(Cleanup) 처리 등이 필요)

  • PostQueuedCompletionStatus로 비동기 처리에 대한 대체결과 Post가능 (이 경우 기존 작업 취소됨(?))

  • 예를 들어 비동기 WSARecv받는 중에 closesocket하면 GQCS의 return값이 FALSE가 나오면서 key와 ov는 해당 값이 들어감. 이런 경우 error=ERROR_CONNECTION_ABORT 임

  • 안전한 처리를 위해 Key및 Overlapped포인터에 대해 reference count로 관리 필요.
    비동기 처리시작시 count증가,
    GQCS결과 발생시 count감소.
    count == 0일 때 비로소 key객체 삭제 가능함

https://gpgstudy.com/forum/viewtopic.php?t=9075

Comment +0

저의 빌드 환경은 Windows x86 64bit , Visual Studio 2015 환경입니다.

그리고 필요한 프로그램들은 (대략) 아래와 같습니다. (더 필요할 수 있음)

  • nasm (32bit/64bit 둘 다 따로 설치)

  • ActivePerl

  • D:\replace.bat (아래)

    @echo ON
    setlocal
    
    call :FindReplace %1 %2 %3
    
    exit /b 
    
    :FindReplace <findstr> <replstr> <file>
    set tmp="%temp%\tmp.txt"
    If not exist %temp%\_.vbs call :MakeReplace
    for /f "tokens=*" %%a in ('dir "%3" /s /b /a-d /on') do (
      for /f "usebackq" %%b in (`Findstr /mic:"%~1" "%%a"`) do (
        echo(&Echo Replacing "%~1" with "%~2" in file %%~nxa
        <%%a cscript //nologo %temp%\_.vbs "%~1" "%~2">%tmp%
        if exist %tmp% move /Y %tmp% "%%~dpnxa">nul
      )
    )
    
    del %temp%\_.vbs
    
    exit /b
    
    :MakeReplace
    >%temp%\_.vbs echo with Wscript
    >>%temp%\_.vbs echo set args=.arguments
    >>%temp%\_.vbs echo .StdOut.Write _
    >>%temp%\_.vbs echo Replace(.StdIn.ReadAll,args(0),args(1),1,-1,1)
    >>%temp%\_.vbs echo end with

32bit/64bit 개별적으로 빌드해야 합니다.

https://www.openssl.org/source/ 에서 openssl-fips-2.0.16.tar.gz와 openssl-1.0.2s.tar.gz (당시 최신버전, FIPS는 1.0.2tlflwmaks rksmd)을 다운받습니다.

그리고 압축을 풀어야 하는데 주의할 점은 내부에 파일들이 symbolic link으로 되어있는것들이 있기때문에 관리자 권한으로 압축을 풀어야 합니다.

저는 7-Zip을 관리자 권한으로 실행 후 압축을 풀었습니다.

32bit 용으로 빌드하기 위해 저는 아래의 위치에 압축을 풀었습니다.

D:\development\openssl-fips-2.0.16-x86_32

D:\development\openssl-1.0.2s-x86_32

VS2015 x86 native tools command prompt를 실행한 뒤 해당 위치로 이동합니다.

그리고 아래와 같이 환경을 설정 후 do_fips 실행합니다.

> cd D:\development\openssl-fips-2.0.16-x86_32
> set PATH=C:\Program Files (x86)\NASM;C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86;%PATH%
> set PROCESSOR_ARCHITECTURE=x86
> D:\replace.bat "/MD" "/MT" "util\pl\VC-32.pl"
> ms\do_fips.bat
...
***************************
****FIPS BUILD SUCCESS*****
***************************
(이러면 성공)

그럼 D:\usr\local\ssl\fips-2.0 가 생깁니다.

이제 OpenSSL를 빌드합니다.

> cd D:\development\openssl-1.0.2s-x86_32
> D:\replace.bat "/MD" "/MT" "util\pl\VC-32.pl"
> perl Configure VC-WIN32 fips --with-fipsdir=D:\usr\local\ssl\fips-2.0
...
Configured for VC-WIN32.
(이러면 성공)
> ms\do_nasm.bat
> nmake -f ms\ntdll.mak

이제 out32dll 에 빌드된 파일들이 있습니다.

D:\usr\local\ssl\fips-2.0와 out32dll을 따로 복사해 둡니다.

테스트합니다.
> out32dll\openssl version
OpenSSL 1.0.2s-fips
> out32dll\openssl md5 README
MD5(README)= 629ecea79d435f217d1a4b459797108a
> set OPENSSL_FIPS=1
> out32dll\openssl md5 README
Error setting digest md5
1724:error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips:.\fips\utl\fips_md.c:180:
(오류가 뜨면서 동작하지 않아야 정상입니다.)

64bit용을 빌드하기 위해 위와 같은 방법으로 빌드하되 환경만 조금 바꿔줍니다.

VS2015 x64 native tools command prompt를 실행한 뒤 해당 위치로 이동합니다.

> rmdir /s/q D:\usr\local\ssl\fips-2.0
> cd D:\development\openssl-fips-2.0.16-x86_64
> set PATH=C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64;C:\Program Files\NASM;%PATH%
> set PROCESSOR_ARCHITECTURE=AMD64
> D:\replace.bat "/MD" "/MT" "util\pl\VC-32.pl"
> ms\do_fips.bat

> cd D:\development\openssl-1.0.2s-x86_64
> D:\replace.bat "/MD" "/MT" "util\pl\VC-32.pl"
> perl Configure VC-WIN64A fips --with-fipsdir=D:\usr\local\ssl\fips-2.0
> ms\do_win64a.bat
> D:\replace.bat "SSL=ssleay32" "SSL=ssleay64" "ms\ntdll.mak"
> D:\replace.bat "CRYPTO=libeay32" "CRYPTO=libeay64" "ms\ntdll.mak"
> D:\replace.bat "SSLEAY32" "SSLEAY64" "ms\ssleay32.def"
> D:\replace.bat "LIBEAY32" "LIBEAY64" "ms\libeay32.def"

> nmake -f ms\ntdll.mak

이제 out32dll 에 빌드된 파일들이 있습니다.

D:\usr\local\ssl\fips-2.0와 out32dll을 따로 복사해 둡니다.

Comment +0

WindowsPE에서 cmd을 켜고 크래시 덤프를 만들기 위해 procdump을 사용하면 작동하지 않고 그냥 꺼져버립니다..

그 이유는 explorer에서 procdump을 실행해보면 이유를 알 수 있습니다.


explorer실행방법 : cmd에서 notepad열기 -> 파일열기 -> 모든파일 -> exe우클릭 실행!


그럼 pdh.dll이 없다고 나오는데 C:\Windows\System32\pdh.dll을 procdump와 같은 위치에 넣어주면 작동합니다!

'프로그래밍' 카테고리의 다른 글

안전한 IOCP 프로그래밍  (0) 2019.06.23
OpenSSL FIPS 빌드  (0) 2019.06.19
WindowsPE에서 디버깅하기  (0) 2018.11.07
libcef 멈춰버리는 문제 해결  (0) 2018.07.02
CodeVirtualizer 주의점 #1  (0) 2017.12.26
효율적인 그리고 안전한 소켓 통신 서버  (0) 2017.11.13

Comment +0