manywaypark's Blog
개발, 검색, 함수

Erlang NIF 최적화

함수형 언어/Erlang 2017. 3. 20. 10:30 by manywaypark

첨부 문서(원본 소실에 대비해 첨부)는 오래 걸리는 nif function call에 관해 심도있게 고찰한 문서이다.


간단히 요약한다.


0. 전제

NIF의 제약 사항은 아주 빨리 처리를 끝내야한다는 것이다 (보통 1~2 ms)

이유는 native code를 처리할 때는 ERTS의 scheduler가 block되므로 다종다양한, 파악조차 힘든 문제를 겪을 수 있다.

(대표적으로 여러 노드가 통신하는 상황이면 60초 timeout에 걸릴 수 있는데, 처음 경험하면 아주 난감한 상황이 될 것이다)

참고로 function call의 처리가 끝나는 시점은 return value를 받는 시점이다.


1. chunking

말 그대로 조금씩 잘라서 처리하는 것이다. 


2. enif_schedule_nif (+ enif_consume_timeslice)

chunking을 좀더 편하게 해주는 API가 추가된 것이다.


3. dirty schedulers:

task의 성격에 따라 schedule 정책을 달리하는(?) 것이다.

기본적으로 ERTS에 포함되지 않았으므로 이렇게 ERTS compile:

configure --enable-dirty-schedulers

사용:

ErlNifFunc 정의에서 ERL_NIF_DIRTY_JOB_CPU_BOUND, ERL_NIF_DIRTY_JOB_IO_BOUND 등의 flag를 준다.



4. thread 사용(어디서 읽었는데 이 문서는 아닌듯)

nif function은 caller pid 정도만 저장하고 바로 return한다.

worker thread가 오래 걸리는 작업을 처리한 후에 enif_send로 caller process에 전달한다. caller process는 receive해서 결과를 받는다.


14115736879341vinoskioptnativecode.pdf



원본: http://www.erlang-factory.com/static/upload/media/14115736879341vinoskioptnativecode.pdf


happy hackin'



nif(c/c++ shared object)를 erlang runtime에 올려서 쓰다보면 gdb를 사용할 일이 생긴다.

/usr/bin/erl은 shell script다.

그 내용을 보고 환경변수만 맞추어주면 된다. 아래처럼 한다.

# (emacs라면, M-x gdb 후에)

gdb --annotate=3 /usr/lib/erlang/erts-5.8.5/bin/beam.smp

......

(gdb) set environment ROOTDIR /usr/lib/erlang

(gdb) set environment BINDIR /usr/lib/erlang/erts-5.8.5/bin

(gdb) set environment EMU beam

(gdb) set environment LD_LIBRARY_PATH /path/to/lib:/usr/local/lib:/usr/lib  # optional, 은밀한(?) 곳에 so가 있다면 설정.

(gdb) cd /path/to/working/dir    # optional, 보통 beam.smp가 있는 곳으로 cwd가 바뀌므로 다시 설정한다.

(gdb) r -- -root /usr/lib/erlang -progname erl -- -home /path/to/home -- -sname optional-node-short-name -pa ./ebin

......

주의할 점은, erlang REPL에 들어가고 나면 마땅히 break point를 설정할 방법이 없으므로 REPL 진입전에 break point를 설정해야 한다는 것이다.


happy hackin'


2014-12-22 추가: 

참고 링크(이게 더 간단한가?) http://blog.dizzyd.com/blog/2009/12/18/running-erl-in-a-debugger/ 

요점은 bin/erl을 이렇게 바꾸고 실행한다.

if [ ! -z "$USE_GDB" ]; then gdb $BINDIR/erlexec --args $BINDIR/erlexec ${1+"$@"} else exec $BINDIR/erlexec ${1+"$@"} fi


1 ~ 2 글자로 만든 이유는?
자주 쓸 것이라 예상했기 때문이다.

f()
forget - shell의 모든 binding을 없앤다.
f(Foo) forget Foo - Foo에대한 binding을 없앤다.
c(module) compile - 모듈 compile. c(module, {d, debug}) 과 같은 형식으로 컴파일 타임에 설정을 추가하면, -ifdef(debug). 등에서 활용가능하다.
l(module) load - load (compiled) module.
q() quit - shell 끝내기.
rr("record-file.hrl") read record (from file) - read record information.
rf(record) forget record - record 정보 제거, tuple로 보이게 만든다.

보일때 마다 정리를 하고 있었는데...
help()가 있었다... Orz.


happy hackin'
1 
분류 전체보기 (306)
잡담 (20)
함수형 언어 (65)
emacs (16)
java (18)
tips & tricks (154)
사랑 (1)
가사 (0)
독서 (4)
mobile (6)
비함수형 언어 (2)

공지사항

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

03-29 16:00