2011. 1. 4. 16:24

정신이 맛갔을 때 작성한 코드

template < class T>
inline void copyCArrayToVector( const T* src, const size_t length, std::vector<T>& dst ) {
    if( dst.size() < length ) dst.resize( length );
    std::copy_n( src, length, dst.begin() );
}

그 코드를 보고 수정한 코드


template < class T >
inline std::vector<T> copyArrToVector( const T* src, const size_t length )
    std::vector<T> dst;
    dst.resize( length );
    std::copy( src, src + length, dst.begin() );

    return dst;
}

살펴보다가 발견한 이전에 작성한 코드

template <typename T>
inline vector<T> copyArrToVec( T* carray, size_t length ) {
    return vector<T>( carray, carray + length );
}




Posted by newpolaris
2011. 1. 4. 02:52
까먹고 찾고 외우고 또 까먹고의 무한 loop

많이 들어봤을 꺼다. 

"VC는 디버그 모드에서는 메모리 할당시 0xcdcd... 이런 값으로 가득 채운다.
왜냐면 release 모드에서 부팅 후 사용되지 않은 메모리를 접근할 경우 0으로 되어 잇다.
이 상황에서 잘돌아간다고 계속 작업하면 나중에 프로그램이 기존에 사용한 메모리를 읽을 시
쓰레기 값을 읽게되고 프로그램이 하늘로 가기 때문이다"

이글은 위의 사항을 까먹고 수행한 뻘짓의 기록이다.

발견한 문제는 다음과 같다.

release 모드의 openCV library를 사용하면 문제가 없는데,
debug 모드의 openCV library를 사용하면 일부 테스트가 죄다 망가지네?

뭥미 이거 왜이래?

상황은...
1. 더러운 세상 class화도 안된 openCV 1.0을 쓰라니요? boost도 안된다고 할까봐 대충 c스럽게 작성
2. 아따 노트북 느리다. 매번 테스트 코드 작성할때 마다 테스트 수행시간이 너무 걸린다.
   openCV 는 내가 작성한게 아니니까 release 모드의 library로 빨리 실행하고 테스트해야지.

이렇게 코드를 계속 작성하고 있다가 메모리 릭이 검사가 안되는 것을 발견 ->
relase mode의 library는 (간단한)VC의 메모리 릭 검사 루틴을 생깐다는 사실을 처음 알게됨 ->
debug 모드의 openCV library로 빌드하고 테스트 수행 ->
몇몇 테스트 루틴이 실패함 -> 패닉

원인:
할당한 메모리 초기화를 안하고 그냥 사용하여 쓰레기 값(visutal studio의 0xcdcdcd)을 사용
무식
무식함 ( 200m 짜리 데이터를 처리하고 matlab에서 나온 값과 비교 )


ps. 5일동안 재부팅안하고 200m 짜리 데이터를 1분에 한번씩 불러와서 처리하고 비교하는데
      어째서 한번도 테스트 실패가 안난걸까?


Posted by newpolaris
2011. 1. 3. 23:35
배울때 설마 내가 저런 짓(실수)를 하겠냐고 생각하고 흘러넘긴 것이

"실제로 일어 났습니다"

이로서 컴퓨터 프로그램 실수로 일어난 사고 목록 탑 1,2 를 모두 실제로 겪은 것인데
(나머지 하나는 overflow)

핑계를 들자면 로직 생각하기 바뻐서 생각도 못했다.

정수 계열인 경우 예외를 던지지만

부동 소수점의 경우 IEEE spec에 따라
정해진 값을 표시하며 VS는 1.#INF000 를 결과로 보여준다.




Posted by newpolaris
2011. 1. 3. 15:34
c++ 자체가 개객기 라서 그렇습니다

컴파일러가 함수의 프로토 타입을 선언 한 것이라 보기 때문입니다.

그니까

class MyClass {
public:
   MyClass() {};
};

MyClass hello; //  hello 라는 객체를 선언합니다.
MyClass helloWorld(); // MyClass를 리턴하는 인자가 없는  helloWorld 함수의 프로토타입을 선언합니다.

이것을 함수 안에서  쓴다면 함수안에서 선언이 안되는 언어기에
prototyped function not called (was a variable definition intended?) 라고 컴파일러가 경고를 해줍니다.

그러나 전역 범위에서 쓴다면 경고도 안뛰워줍니다.

.... 보고 까먹고 또 찾고 보고 까먹고 또 찾고. c++은 너무 복잡혀...
Posted by newpolaris
2010. 12. 17. 00:22



void myPCA( CvMat* A, CvMat* U2 ) {
 CvMat* U  = ::cvCreateMat( A->rows, A->cols, A->type );
 CvMat* S  = ::cvCreateMat( A->cols, A->cols, A->type );
 functionFillMatrixUandS( A, S, U );

 // GOAL: Efficent way copy data from U to U2, Just like crop matrix U as size of U2
 // Matlab:  [ uy, ux ] = size(U);
 //              U2 = U( 1:uy, 1:ux ); % simple isn't it?
 
  // 1. Create header only matrix, if you give null matrix it cause error
 CvMat* header = ::cvCreateMatHeader( U2->width, U2->height, U2->type );
  // 2. Fill matrix 'header' with pointers which pointing each row start position in U element
  //    accessing matrix element are restricted width small size(resized matrix width),
  //    accessing next row restricted with U's step
  //    header matrix has U's step, U2's width
 ::cvGetSubRect( U, header, cvRect( 0, 0, U2->width, U2->height ) );
  // 3. Need hard copy, to survie without U matrix
 ::cvCopy( header, U2 );

 ::cvReleaseMat( &U );
 ::cvReleaseMat( &header );
 ::cvReleaseMat( &S );
}

note:

// Selects sub-array (no data is copied)
CV_IMPL  CvMat*
cvGetSubRect( const CvArr* arr, CvMat* submat, CvRect rect )
{
    /*
    int* refcount = mat->refcount;

    if( refcount )
        ++*refcount;

    cvDecRefData( submat );
    */
    submat->data.ptr = mat->data.ptr + (size_t)rect.y*mat->step +
                       rect.x*CV_ELEM_SIZE(mat->type);
    submat->step = mat->step;
    submat->type = (mat->type & (rect.width < mat->cols ? ~CV_MAT_CONT_FLAG : -1)) |
                   (rect.height <= 1 ? CV_MAT_CONT_FLAG : 0);
    submat->rows = rect.height;
    submat->cols = rect.width;
    submat->refcount = 0;
    res = submat;

    return res;
}

 

Posted by newpolaris
2010. 12. 16. 22:12


병신 같은 for문 처리 속도 빼문에 matlab이 느리다고 생각하게 되는데요,
( 그외로 여러가지 약점이 있지만...)

128,000 x 300 matrix를 서로 곱하여 봅시다.

openCV 나름대로 요즘 올라오는거 보면
"Blas 적용했음. 20% 속도 향상 기대함여" 등등이 있는데요,
  -  Matrix multiplication now is done by blocks resulting
90      in better cache utilization => better performance.
91      Optionally, gemm from Intel MKL can be used. (beta 4)
... 대충 코드 위치로 볼때 gemm에 blas 적용은 안된것 같음..


matlab ... 상용 라이브러리 + ublas + 미친듯한 튜닝 으로 0.7 sec를 보여줍니다.

테스트도 쉽습니다. 인터프리터에 rand 하고 * 기호 써서 곱합니다. 그걸 tic;toc으로 감싸주시면 됩니다.
>> tic; AtA = T'*T;toc;
Elapsed time is 0.557990 seconds.
>> tic;T = rand(128*1000, 300); AtA = T'*T; toc;
Elapsed time is 1.167132 seconds.
.....single으로 감싸도 별반 차이없습니다.

openCV 우선 한숨부터 쉬고...

프로젝트 만들고 인클루드하고
우선 timer용으로 쓸 함수 include 하고
openCV 세팅하고
결과를 보기위해 컴파일하고

돌립니다!

    enum { DESC = 128, NUM_DESC = 1000, NUM_PIC = 300 };
    CvMat* M = ::cvCreateMat( DESC * NUM_DESC, NUM_PIC, CV_32FC1 );

    my_pca::randn( M, 100, 20 );

    CvMat* AtA = ::cvCreateMat( NUM_PIC, NUM_PIC, CV_32FC1 );
    ::cvGEMM( M, M, 1.0, NULL, 0.0, AtA, CV_GEMM_A_T );

    ::cvReleaseMat( &M );
    ::cvReleaseMat( &AtA );

10 sec 나왔네요 감사합니다.

randn은 openCV rand함수 감싼건데요 단독으로 400ms 나옵니다.


ㅅㅂ......

결론 :  상용 library와 최적화로 무장한 matlab의 행렬 곱 연산은
           openCV에서 새롭게 적용된 blas 적용 곱하기에 비해 디지게 빠릅니다.



I think its because you are trying to multiply two matrices, which
is speciality of matlab. Its made for matrix operations, and its one
thing its is extremely difficult to beat matlab at.

matlab achieves this speed with matrices by using platform
customized packages for libear algebra namely blas and lapack and of
course lot of intelligent tweaks. If you look in matlab bin
directory you will find files like altas_PIII.dll, atlas_PIV.dll and
mkl_PIV.dll etc. these are the 3rd party packages matlab uses.

atlas is Automatically Tuned Linear Algebra Subroutines - it
contains blas and lapack. It is opensource project.

mkl is Maths Kernal Library which is again optimized implementation
of blas and lapack but is developed by intel so supposedly better.
but mkl is not free.

Now to be fair to opencv I would recommend you try some highlevel
function for example canny. Then you will know the speed difference.

-Saurabh

Posted by newpolaris
2010. 12. 9. 16:56

1번은 동시에(simultaneous)를 어떻게 처리해야 할지 모르것다.

해외 답을 봐도 '동시'에 실행하는 답은 없는 것 같은데 먼가 내가 핀트를 잘못잡고 있는듯,

머 어짜피 atomic이라 해도 erlang 내부에서 말이지, chapter 20.1을 보면
"등록된 프로세스를 만들때 마다 우리는 잠재적인 순차적 병목을 만들고 있다" 라고 적힌것을 보면 erlang 내부에서 적당히 처리해주는 것 같다. IO 쪽에서 이 내용이 나오느데 이걸 하드에도 기록하나;

머 하여간 2번 문제는 적당히 풀었다. 

코드가 병렬화 되어 있지 않습니다. 수정한 버전은 나중에 올리겠습니다.

-module(erl8p2).
-export([main/2]).

makeRing(N) ->
    Pids = for(1,N, fun ringNode/0),
    LastElm = lists:last(Pids),
    [LastElm | Pids].

destroyRing(RingElmPids) ->
    [_|T] = RingElmPids,
    lists:foreach(fun(Pid) -> Pid ! die end, T).

ringNode() ->
    spawn(fun loop/0).

loop() ->
    receive
        {ring, [], _Request, Dest, _Result} ->
            % io:format("Last Node:~p ~p~n",[ring, Msg, pid_to_list(self())]);
            Dest ! {ring,_Result},
            loop();
        {ring, [H|T], Request, _Dest, _Result} ->
            % io:format("Received:~p to ~p~n",[ring, Msg, pid_to_list(H)]),
            H ! {ring, T, Request, _Dest, _Result},
            loop();
        die -> void
    end.          

for(N,N,Fun) -> [Fun()];
for(I,N,Fun) -> [Fun()|for(I+1,N,Fun)].
   
sendRingMsg(RingElmPids, Msg) ->
    [H|T] = RingElmPids,
    H ! {ring, T, Msg, self(), []},
    receive
        {ring, Results} -> Results
    end.                          

stopWatch(Fun) ->
    statistics(wall_clock),
    statistics(runtime),
    Fun(),
    {_, Time1} = statistics(wall_clock),
    {_, Time2} = statistics(runtime),
    [Time1, Time2].

main(N,M) ->
    RingElmPids = makeRing(N),
    [Time1, Time2] = stopWatch(fun() -> for(1,M, fun() -> sendRingMsg(RingElmPids, "Hello World") end) end),
    io:format("Ring benchmark tim = ~p (~p) ms~n", [Time1, Time2]),
    destroyRing(RingElmPids).
    
;; 결과는 아래와 같다.                    
21> erl8p2:main(10000,10).
Ring benchmark tim = 7894 (6896) ms

fun이 local function 보다는 느리고 apply보다는 빠른 연산이라고 하는데,
"2.1  Myth: Funs are slow"
http://www.erlang.org/doc/efficiency_guide/myths.html
나중에 fun이나 바꿔야할 것 같다.

...언제나 느끼는 것이지만 짧은 영어 실력에서 나오는 변수명은 참 눈물난다.
그 때문에 짧은 설명은 붙이자면,
makeRing, destoryRing은 ringNode라 불리는 (뒷부분에선 ringElm로 개명한다..?!)
각 ring을 구성하는 element들의 집합으로 구성되는데,
(나중에 고쳐야될 것 같지만) 1->2->3->1 로 끝부분이 이어지도록 구성된다.

끝부분이 이어진다고 먼가 좋은 것이 있는 것은 아니고 그 덕분에 함수 성질에따라
H를 날리거나 그대로 이용한다.
destoryRing은 같은 element를 2번 지우면 안되니까 Head를 뺀 2, 3, 4, 1을 삭제하고,
sendRingMsg은 Head 로 메시지를 보내 다시 Head로 돌아오도록 만들때 이용한다.

loop는 각 element가 실제로 일을 처리하는 넘인데,
Request에 따라 일을 처리하고 Response에 결과를 추가하고 다음 elements(Pids의 Head)로 전송하는 역활을 한다.
여기서는 하는 일이 없으니 걍 Msg 받고 다음 elements로 메시지를 보내는 역활만 한다.
 {ring, Pids, _Request, Dest, _Result}  는 대충 {ID, next Element Pids, Requtest, 마지막 결과 받을넘, 각노드의 결과}를 나타낸 Msg이다.

그니까
        {ring, [], _Request, Dest, _Result} ->
            Dest ! {ring,_Result},

next elemets Pids가 바닥난 한바퀴 돈 상황에서
Dest로 Results를 발신하고

그제서야 전체 Ring에 Request 를 보내 한바퀴 일 시키신
sendRingMsg께서는 결과를 받아보시고 종료한다.

------------------------------------------------------------------------------------------
수정본: spawn 한다음에 작업 마칠때 까지 기다려주려나? 메시지 통신으로 직접 알아야 하나?

-module(erl8p2).
-export([main/2]).

constructRing(N) ->
    Pids = for(1,N, fun ringNode/0),
    LastElm = lists:last(Pids),
    [LastElm | Pids].

destructRing(RingElmPids) ->
    [_|T] = RingElmPids,
    lists:foreach(fun(Pid) -> Pid ! die end, T).

ringNode() ->
    spawn(fun loop/0).

loop() ->
    receive
        {ring, [], _Request, Dest, _Result} ->
            % io:format("Last Node:~p ~p~n",[ring, Msg, pid_to_list(self())]);
            Dest ! {ring,_Result},
            loop();
        {ring, [H|T], Request, _Dest, _Result} ->
            % io:format("Received:~p to ~p~n",[ring, Msg, pid_to_list(H)]),
            H ! {ring, T, Request, _Dest, _Result},
            loop();
        die -> void
    end.          

for(N,N,Fun) -> [Fun()];
for(I,N,Fun) -> [Fun()|for(I+1,N,Fun)].
   
sendRingMsg(RingElmPids, Msg) ->
    [H|T] = RingElmPids,
    H ! {ring, T, Msg, self(), []},
    receive
        {ring, Results} -> Results
    end.                          

timer(start) ->
    statistics(wall_clock),
    statistics(runtime);

timer(stop) ->
    {_, Time1} = statistics(wall_clock),
    {_, Time2} = statistics(runtime),
    [Time1, Time2].

messageRing(RingElmPids) ->
    spawn(fun() -> sendRingMsg(RingElmPids, "Hello World") end).
 
main(N,M) ->
    RingElmPids = constructRing(N),
    timer(start),
    for(1, M, fun() -> messageRing(RingElmPids) end),
    [Time1, Time2] = timer(stop),
    io:format("Ring benchmark tim = ~p (~p) ms~n", [Time1, Time2]),
    destructRing(RingElmPids).

49> erl8p2:main(10000,1000).
Ring benchmark tim = 281 (297) ms

sendRingMsg(RingElmPids, Msg) ->
    [H|T] = RingElmPids,
    H ! {ring, T, Msg, self(), []},
    receive
        {ring, Results} -> Results
    end.    

Posted by newpolaris
2010. 12. 5. 20:29

msys의 bash는 뭐 알아서 잘해주더라 그런 이야기다.
/usr/bin/에 env.exe란 파일로 존대한다. 그러므로

#!/usr/bin/env escript라 써도 잘해석하고 잘 해준다.
책에는 저자가 난 모르오 누군가 갈켜 주시오 그리 되어있는데 escript.exe도 존재하니
msys없이도 그냥 호출하면 될 듯하다.

옵션은 아래와 같이 먹일 수 있다고 하네;
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname factorial -mnesia debug verbose
http://www.erlang.org/doc/man/escript.html

평소에 자주쓰는 #! 구문은 도대체 무었인지 좀 찾아봤다.
그 녀석은 "Shebang" 으로 불리는데 (hashbang, hashpling, pound bang, or crunchbang)

#! 다음 부터는 program loader가 첫줄의 나머지 부분을 interpreter directive로 보고 파싱해서 그 해당하는 넘을 첫줄에 있는 옵션과 함께 잘 실행 시켜 준다고 한다.

(when it occurs as the first two characters in the first line of a text file. In this case, the program loader in Unix-like operating systems parses the rest of the first line as an interpreter directive and invokes the program specified after the character sequence with any command line options specified as parameters.) http://en.wikipedia.org/wiki/Shebang_(Unix)

그런대 왜 #! /usr/bin/env python도 동작 되느냐 하면, env라는 프로그램이 $PATH를 검사해서 python을 찾아준다고 한다.
( At least on the operating systems I have checked, #! must be followed by
the full pathname of a program. It does not search $PATH for it.
'/usr/bin/env python' searches $PATH for python and runs it.
(Usually env is used to set some environment variables for a program,
e.g. 'env PYTHONPATH=whatever python', but one need not specify any
environment variables
Since env is (almost?) always in /usr/bin, while python can be installed
God-knows-where, that is more portable than writing #!/local/bin/python
or #!/usr/bin/python or whatever..) http://www.velocityreviews.com/forums/t324727-what-does-usr-bin-env-python-do.html

가장 상세한 메뉴얼은 http://www.in-ulm.de/~mascheck/various/shebang/ 거 같은디
exec()가 수행한다고하네

      Some background.  When the UNIX kernel goes to run a program (one
      of the exec() family of system calls), it takes a peek at the
      first 16 bits of the file.  Those 16 bits are called a `magic
      number'.  First, the magic number prevents the kernel from doing
      something silly like trying to execute your customer database
      file.  If the kernel does not recognize the magic number then it
      complains with an ENOEXEC error.  It will execute the program only
      if the magic number is recognizable.

Posted by newpolaris
2010. 12. 5. 03:00

reference manual은,

( official )
http://erlang.org/doc/
( alternative )
http://erldocs.com/

이거고, 책에 예제 1줄 안비고 걍 넘어간 refernce는, 아래와 같따.

Refs

A ref (or reference) is a term which is unique, even across Erlang nodes. You can create a new ref by calling erlang:make_ref/0. A reference is only used as a unique tag or identifier. An Erlang reference should not be confused with a reference in C/C++.

2> erlang:make_ref().
#Ref<0.0.0.41>
Posted by newpolaris
2010. 12. 5. 02:56
함수 참조 (function reference)
그냥 module에 정의된 fuction을 사용할때 이렇게도 적을 수 있구나 정도로 받아들이면 되겠다.

fun LocalFunc/Arity

There are several ways to pass and call functions in erlang:

- to create a function closure (F) wrapping a segment of code in a erlang fun do:
F = fun(...Args...) -> ...Code... end

- or define a reference to a function:
F = foo/3
F = module:foo_function/2

- it is also possible to pass a function name or {module,function} tuple as mentioned in the article (although the tuple notation is only retained for backwards compatibility with ancient code).

To use a function reference one can simply call it as:

F = ...,
... = F(...),


or directly:

... = (fun(A) -> A * A end) (2),

... = (fun add/2) (2, 2),

... = (fun math:pow/2) (2, 2),

... = {math, pow} (2, 2),

Function and module names can be used the same way:

FunctionNameAtom = add,
... = FunctionNameAtom(2),

ModuleNameAtom = math,
FunctionNameAtom = pow,
... = ModuleNameAtom:FunctionNameAtom(2)


There are some rare cases when apply is useful, but it rare to see it in modern erlang code.


Posted by newpolaris