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'



problem:

rebar(엄밀히 말하면 rebar2)에서 rebar3로 업그레이드를 진행중인데, sqerl에서 아래와 같은 오류가 났다.

===> Compiling project

===> Compiling path/to/file.erl failed

path/to/file.erl:none: error in parse transform 'sqerl_gobot': {function_clause,

                                         [{lists,map,

                                           [#Fun<sqerl_gobot.1.114344583>,

                                            undefined],

                                           [{file,lists.erl},{line,1237}]},

                                          {sqerl_gobot,who_types_the_untyped,

                                           1,

                                           [{file,

                                             /path/to/project/_build/default/lib/sqerl/src/sqerl_gobot.erl},

                                            {line,81}]},

                                          {sqerl_gobot,parse_transform,2,

                                           [{file,

                                             /path/to/project/_build/default/lib/sqerl/src/sqerl_gobot.erl},

                                            {line,51}]},

                                          {compile,

                                           '-foldl_transform/2-anonymous-2-',

                                           2,

                                           [{file,compile.erl},{line,932}]},

                                          {compile,foldl_transform,2,

                                           [{file,compile.erl},{line,934}]},

                                          {compile,

                                           '-internal_comp/4-anonymous-1-',2,

                                           [{file,compile.erl},{line,295}]},

                                          {compile,fold_comp,3,

                                           [{file,compile.erl},{line,321}]},

                                          {compile,internal_comp,4,

                                           [{file,compile.erl},

                                            {line,305}]}]}


root cause:

사실 제법 많은 시간을 헤맸는데, 원본 파일이 컴파일 되지 않는 것이었다. 아래 라인을 소스 파일에서 제거하고 돌려보면 컴파일 에러(include 파일을 찾지 못함)가 났다.

-compile({parse_transform, sqerl_gobot}).

rebar2와 rebar3(정확히는 rebar3의 release)의 디렉토리 구조가 달라서 아예 컴파일이 안되는 것이 었다. 

AST구성후 parse transform후에 컴파일을 진행하게 되므로 상기 에러와 같은 이상한 에러가 나온다. 

직접적인 원인은 include가 되지 않아 정상적인 AST가 생성되지 않았는데 그 AST를 조작질(parse trasform)하려니깐 문제가 생긴 것인데... 에러 메시지만으로 알아보기 힘들었다.


solution:

include path 정확히 설정해 준다. release의 root에 rebar.config 파일이 있다면 아래처럼 설정한다 (사실 이거말고 다른 방법도 몇개 존재한다).

{erl_opts, [debug_info

           ,{parse_transform, lager_transform}

           ,{i, "apps/project"}]}.

요점은 parser transform을 요하는 소스 파일이라해도 적용전의 형태에서 컴파일은 되어야만 한다는 것. 

parser transform 관련해서 문제 생기면 transform을 disable하고 컴파일 테스트해보는 것을 추천하고 싶다.


happy hackin'



대량의 동시 접속 처리하기 위한 설정들 모음

ref: http://emqtt.io/docs/v2/tune.html


erlang string to term or expr

함수형 언어/Erlang 2015. 4. 7. 16:41 by manywaypark

string to term:

ErlTerms = "{a,b,c,d}.".

{ok,Tokens,_} = erl_scan:string(ErlTerms).

{ok,Term} = erl_parse:parse_term(Tokens).

Term -> {a,b,c,d}.


string to expression (and eval):

StrTerm = "fun() -> result_atom end.".

{ok,Tokens,_} = erl_scan:string(StrTerm).

{ok,[Expr]} = erl_parse:parse_exprs(Tokens).

erl_eval:expr(Expr,[]).

resulted in: {value,#Fun,[]}


refs:

https://github.com/skruger/Surrogate/issues/3

http://stackoverflow.com/questions/1974236/string-to-abstract-syntax-tree

http://stackoverflow.com/questions/2008777/convert-a-string-into-a-fun


happy hackin'

rebar - release node 생성

함수형 언어/Erlang 2014. 11. 26. 11:34 by manywaypark

자주하는 작업이 아니다보니 할 때마다 좀 헷갈리네.

일단 이렇게 해서 rel 디렉토리에 기본적인 파일 생성한다.

$ cd path/to/prj

$ mkdir rel ; cd $_

$ rebar create-node nodeid=myapp_node


그리고 아래처럼 library, version 등을 설정한다(diff 임)

diff --git a/rel/reltool.config b/rel/reltool.config

index 9260933..354b925 100644

--- a/rel/reltool.config

+++ b/rel/reltool.config

@@ -1,10 +1,10 @@

 %% -*- mode: erlang -*-

 %% ex: ft=erlang

 {sys, [

-       {lib_dirs, []},

+       {lib_dirs, ["../deps"]},

        {erts, [{mod_cond, derived}, {app_file, strip}]},

        {app_file, strip},

-       {rel, "myapp_node", "1",

+       {rel, "myapp_node", "0.0.1",

         [

          kernel,

          stdlib,

@@ -24,7 +24,7 @@

                            "^erts.*/bin/(dialyzer|typer)",

                            "^erts.*/(doc|info|include|lib|man|src)"]},

        {excl_app_filters, ["\.gitignore"]},

-       {app, myapp_node, [{mod_cond, app}, {incl_cond, include}]}

+       {app, myapp_node, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}

       ]}.

 

 {target_dir, "myapp_node"}.


이제는 rebar generate로 어디든 deploy할 수 있는 node를 생성할 수 있다. 멋지지 않은가?


happy hackin'

복잡할 것없고 그냥 환경 변수 설정한다.

rebar.config에서 설정하려고 많이 검색했네... Orz.

ERL_FLAGS="-name foo@127.0.0.1 -setcookie bar" rebar skip_deps=true eunit


ref: http://stackoverflow.com/questions/10307575/passing-runtime-arguments-to-erlang-when-running-rebar-eunit


happy hackin'

kerl - erlang installer

함수형 언어/Erlang 2014. 5. 22. 17:59 by manywaypark

아주 간편한 erlang 설치 방법이 있었다. 이걸 여태껏 모르고 있었다니... Orz

kerl이라는 utility를 사용하면 source에서 build하는 것은 누워서 떡먹기다.

또한 여러 버전을 깔고 activate/deactivate 할 수 있다. two thumbs up!!


받기 및 실행권한 주기:

curl -O https://raw.githubusercontent.com/spawngrid/kerl/master/kerl

chmod a+x kerl

kerl이 있는 곳을 PATH에 추가한다 (optional).


아래 내용으로 ~/.kerlrc 파일 생성 (64bit Mac OS X의 경우):

KERL_CONFIGURE_OPTIONS="--disable-hipe --enable-smp-support --enable-threads

                        --enable-kernel-poll  --enable-darwin-64bit"


R15B01 버전 build하기:

./kerl build R15B01 r15b01


설치 및 활성화하기:

./kerl install r15b01 ~/erlang/r15b01

. ~/erlang/r15b01/activate


비활성화:

kerl_deactivate


refs: 

http://docs.basho.com/riak/latest/ops/building/installing/erlang/

https://github.com/spawngrid/kerl


2014-07-15 추가: erlang의 build 환경이 제대로 갖추어지지 않았다면 이렇게...

$ sudo apt-get  build-dep erlang

ref: http://askubuntu.com/questions/21379/how-do-i-find-the-build-dependencies-of-a-package


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


erlang name clash

함수형 언어/Erlang 2014. 1. 15. 10:29 by manywaypark

code:clash()를 쓰면 이름 충돌에 관한 정보가 나온다.

code:get_path(), code:add_patha(), code:add_pathz() 등으로 조회, 추가 등을 할 수 있다.

erl 수행시 -pa, -pz  등의 옵션을 쓰는 방법도 있다.


ref: http://erlang.org/pipermail/erlang-questions/2012-February/064179.html


happy hackin'

[펌] Erlang BIF 만들기

함수형 언어/Erlang 2013. 11. 9. 22:33 by manywaypark

steps

1. run configure
2. add your bifs to erts/emulator/beam/bif.tab

bif re:grep/2 bif re:compile/1

3. create a C file

erts/emulator/beam/erl_bif_re.c

4. add your C file to erts/emulator/<arch>/Makefile

RUN_OBJS = $(OBJDIR)/erl_bif_re.o \

5. implement your bifs by stealing bits from existing erl_bif_*.c files
1
2
3
4
5
BIF_RETTYPE re_grep_2(BIF_ALIST_2){
  Eterm result;
  result = magic_function();
  BIF_RET(result);
}
6. run make; make install

notes

  • steps 0-3 need only be done once.
  • note that if you add
1
bif re:grep/2

to bif.tab there should be a erl_bif_re.c that implements

1
BIF_RETTYPE re_grep_2(BIF_ALIST_2);


from: https://erlangcentral.org/wiki/index.php/Adding_my_own_BIF


happy hackin'

1 2 3 4 
분류 전체보기 (306)
잡담 (20)
함수형 언어 (65)
Scheme (5)
Lisp (14)
Erlang (31)
R (3)
Elixir (11)
emacs (16)
java (18)
tips & tricks (154)
사랑 (1)
가사 (0)
독서 (4)
mobile (6)
비함수형 언어 (2)

공지사항

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

04-26 13:43