2014년 4월 24일 목요일

C++ 에서 QuantLib-SWIG 와 Thread-Safe 한 Observer Pattern

원문출처

http://hpcquantlib.wordpress.com/2012/02/27/quantlib-swig-and-a-thread-safe-observer-pattern-in-c/

QuantLib은 사실 Thread-Safe 하지 않습니다. 멀티코어나 병렬환경에서의 성공적인 사용은 여러 프로세스간의  message passing에 의해서 보다는 shared memory 와 multi threading 에 의해서 이루어 집니다. 만약 서로다른 thread 가 서로 다른 object에서 작동을 한다면 QuantLib 또한 Multi threading 환경에서 사용될수 있습니다.(QL_ENABLE_SESSIONS 를 정의 하는 것은 singleton을 thread에 종속적이게 만듭니다.)

만약 당신이 QuantLib을 SWIG를 통하여 Java나 Scala에서 사용한다면 설령 메인 루틴이 싱글스레드 일지라도 QuantLib 루틴은 자동적으로 multi threading 환경에서 실행되어집니다.
JVM의 가비지 컬렉터는 보통 다른 thread에서 돌고 있습니다. 이것은 QuantLib에 구현되어 있는 Observer Pattern 과 결합하여 심각한 문제를 초래 할수 있습니다. 즉, 아래의 간단한 single thread Scala 코드는 멀티코어 컴퓨터에서 짧은 시간에 충돌이 일어날수 있습니다.

import org.quantlib.{Array => QArray, _}
object ObserverTest {
    def main(args: Array[String]) : Unit = {
        System.loadLibrary("QuantLibJNI");
        val aSimpleQuote = new SimpleQuote(0)

        while (true) {
            (0 until 10).foreach(_ => {
                new QuoteHandle(aSimpleQuote)
                aSimpleQuote.setValue(aSimpleQuote.value + 1)
            })
            System.gc
        }
    }
}
같은 객체가 동일한 시점에 aSimpleQuote.setValue 함수에 의해 update 함수가 호출될때 가비지 콜렉터는 observer의 소멸자를 호출합니다.(이 내용에 대한 QuantLib Mailing list는 여기에서 확인 할수 있습니다.). greenfield projects에서 [2]의 저자는 C++에서의 적당한 해답을 제시합니다. 안타깝게도 해당 솔루션은 QuantLib에 적용될 수 없었습니다. 해당 솔루션은 Observer pattern의 interface에 많은 변화를 주어야 하고 obsever pattern의 interface의 변경은 QuantLib library의 아주 많은 변화를 초래하기 때문이었습니다.

가장 중요한 문제는 Observer 가 Destructor가 작용하기 전에 사용불능 상태가 되는것입니다. 이것은 이론적으로 boost::shared_ptr의 새로운 instance 마다 특수한 "삭제자(Deleter)"를 추가하는 것이지만 이것 또한 library의 아주 많은 수정을 초래합니다.

전처리 지시자 BOOST_SP_ENABLE_DEBUG_HOOKS 와 함게 컴파일을 하면 boost library는 boost의 smart pointer의 소멸자가 호출되기전에 callback hook하는 것을 추가하게 된다. 이 hook은 observer의 소멸자가 호출되기전에 observer를 사용할수 없게 하는데 사용한다. 추가적으로 boost::signals2 library [3]은 간단하고 thread-safe한 공지 메커니즘을 제공한다.

원래의 QuantLib의 observer/Observable interface에 맞춰 수정된 thread-safe 한 구현은 여기서 찾을수 있다. 모든 소스파일에  전처리지시자 BOOST_SP_ENABLE_DEBUG_HOOKS를 set 한다. QuantLib project에 observable.hpp 와 observable.cpp 파일을 교체 혹은 추가하고 QuantLib library와 QuantLib-SWIG 모듈을 다시 컴파일 한다.

[1] Simplified Wrapper and Interface Generator, SWIG
[3] Douglas G., Mori Hess F., Boost.Signals2











2014년 4월 22일 화요일

Multi-Threading 과 Quantlib

원문출처

http://hpcquantlib.wordpress.com/2013/07/26/multi-threading-and-quantlib/

QuantLib 자체로는 Thread-Safe 하지 않다. 하나이상의 코어에서 몇개의 독립적인 프로세스를 만드는 것이 표준이다. Ricacardo의 thread-safe 한 singleton 패치는 서로다른 스레드가 명시적으로 객체를 공유하지 않으면 Quantlib을 Multi-threading 응용프로그램에서 사용할수 있습니다. 사실 이 패치는 싱글턴 패턴을 각 스레드 로컬한 싱글턴 패턴으로 바꿔줍니다.

이패치의 사용사례중 하나는 test-suite를 Muliti-threading 환경에서 테스트해보는 것입니다. 예를들어 i7 3.2Ghz 쿼드코어에 하이퍼스레딩 코어 4개를 합한 환경에서 약 8분이 걸리던 작업이 2분정도 걸리게 됩니다.

QuantLib을 Java/Scala/C# or F# 응용프로그램에서 SWIG Layer를 통하여 사용하는 것은 multi-threading 요구사항을 위반하는 것입니다. 왜냐하면 가비지 컬랙터가 다른 스레드에서 실행되고 QuantLib 객체가 서로 다른 쓰레드간에 공유되기 때문이다. 이것은 QuantLib 의 Observer pattern 구현에서 문제를 야기한다 이에 관한 자세한 얘기는 다음에서 다룬다.

boost::signals2 와 Riccardo의 Thread-safe singleton 패치에 기반한 observer pattern의 향상된 구현과 multi-threading test runner는 Github에서 다운 받을수 있다.

Linux/MacOS 환경에서의 사용시

./configure --enable-tss --enable-thread-safe-observer-pattern
thread-safe singleton 과 thread-safe observer pattern을 사용할수 있게 한다.

윈도우 환경에서는 다음에 상응하는 전처리기를 userconfig.hpp 에 명시되어 있습니다.

#define QL_ENABLE_TSS
#define QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN
boost::shared_ptr의 후크를 변화시키기 위해 다음 파일에서 전처리지시자 BOOST_SP_ENABLE_DEBUG_HOOKS 를 BOOST_SP_ENABLE_DEBUG_HOOKS_2 로 변경합니다.

boost/smart_ptr/detail/sp_counted_impl.hpp
배경 : 원래의 전처리지시자인 BOOST_SP_ENABLE_DEBUG_HOOKS 은 shared_ptr의 메모리 레이아웃을 변경하는 것이 다른 미리 컴파일된 shared_ptr을 사용하는 라이브러리와 문제를 일으킬수 있습니다.

이러한 작업의 이점은 Multi-threading 응용프로그램에서 서로다른 스레드 간에 SWIG/QuantLib 의 객체를 명시적으로 공유하지 않기때문에 Java/Scala/C#/F# and a thread local singleton implementation 을 위한 안정적인 SWIG Interface 입니다.

2014년 4월 17일 목요일

덧셈연산과 곱셈연산의 속도차이

평소에도 궁금하고 프로젝트의 성능을 좌지우지하는 중요한 사항이기때문에
테스트를 해봤습니다.

소스코드는 다음과 같습니다.
<<덧셈연산>>
#include <iostream>
#include <boost/chrono.hpp>

using namespace std;

int main()
{
double a = 1.0;
double b = 1.1;
boost::chrono::high_resolution_clock::time_point start, end;
start = boost::chrono::high_resolution_clock::now();

for(int i=1; i< 5001; i++)
{
a +=b;
}
end  = boost::chrono::high_resolution_clock::now();
cout<<end - start<<endl;

cout<< "value is "<< a << endl;

return 0;
}

<<곱셈연산>>
#include <iostream>
#include <boost/chrono.hpp>

using namespace std;

int main()
{
double a = 1.0;
double b = 1.1;
boost::chrono::high_resolution_clock::time_point start, end;
start = boost::chrono::high_resolution_clock::now();

for(int i=1; i< 5001; i++)
{
a *=b;
}
end  = boost::chrono::high_resolution_clock::now();
cout<<end - start<<endl;

cout<< "value is "<< a << endl;

return 0;
}


제 환경에서는 결과가 다음과 같습니다.
회차   덧셈 곱셈
1 4226 6943
2 4226 7244
3 4528 7245
4 4226 7244
5 4528 7244

덧셈이 빠른가 봅니다.. 이유는 멀까요? 부동소숫점 연산이라 곱셈이 빠를것 같았는데.. 
예상 외입니다.

2014년 4월 1일 화요일

토렌트 파일을 Direct link 로 변경하기

원글

http://www.mstoic.com/torrent-to-direct-link/


토렌트 파일을 Direct link로 변경하는 방법

1. 토렌트 파일을 다운 받습니다.
아무 유명한 토렌트 공유 사이트에서 (torrentz.eu 또는 kat.ph 그외에 주로가는곳) 토렌트 파일을 다운 받습니다. 토렌트 파일이 아니더라도 마그넷 주소를 얻어옵니다.

2. http://zbigz.com/ 을 방문합니다.
마그넷 주소를 얻어 왔다면 텍스트 박스에 마그넷 주소를 입력합니다. 토렌트 파일을 다운받았다면 Upload.torrent file 버튼을 클릭해서 다운 받은 파일을 선택합니다.

3. 다음 화면에서 당신은 Free 와 Premium의 옵션중 하나를 선택해야 합니다. 이름에서 알수 있듯이 premium은 금액을 지불하고 추가적인 편익을 보장합니다. Free는 지불금도 없고 이득도 없는... ㅎㅎ

4. 이제 토렌트가 캐싱될것입니다. 이작업은 몇초의 시간이 소요됩니다. zbigz 가 아주빠른속도로 캐싱을 하기 때문입니다.

5. 토렌트의 캐싱이 끝이 난다면 이제 zip 포멧을 파일을 다운받을수 있습니다. 이때에도 당신은 Free 혹은 Premium의 옵션중 하나를 선택해야 합니다. 선택후 Download 버튼을 클리하면 Direct Link에서 파일을 다운 받을수 있습니다.

무료회원(Free) 와 유료회원(Premium)의 차이
zbigz free premium model


torrent를 Direct link를 이용하여 다운하는 방법은 여러가지 이점이 있습니다. 당신이 평소에 사용하던 download manager를 사용할수 있습니다. 인터넷 환경의 최대속도를 누릴수 있습니다. 시드가 적더라도 빠른속도를 유지할수 있습니다.

http://zbigz.com/ 에 방문하세요 그리고 당신이 원하는 토렌트 파일을 Direct link로 모두 변경해보세요

예를 들어서 하나 써봤는데 ... 돈내기 귀찮아서 토렌트 그냥 써야지 ...