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

외부 DTD 파일에 <?xml version ... ?> 같은 XML 파일임을 나타내는 PI가 들어있으면 xmerl_scan:(file|string)에서는 다음과 같은 에러를 내면서 parsing이 안된다 (java 쪽에서는 별 문제가 없었던 DTD 파일이다).

error msg:
1066- fatal: {invalid_target_name," version=\""}
** exception exit: {fatal,{{invalid_target_name," version=\""},
                           {file,"/path/to/dtd.dtd"},
                           {line,6},
                           {col,18}}}
     in function  xmerl_scan:fatal/2
     in call from xmerl_scan:scan_ext_subset/2
     in call from xmerl_scan:scan_decl_sep/2
     in call from xmerl_scan:scan_ext_subset/2
     in call from xmerl_scan:scan_decl/2
     in call from xmerl_scan:fetch_and_parse/3
     in call from xmerl_scan:fetch_DTD/2
     in call from xmerl_scan:scan_doctype2/3

간편 해결책: DTD 들이 있는 디렉토리에서 다음을 실행해주자 (DTD 파일이 여러개일때...)
$ sed -i -r "/<\?xml .*\?>/s/.*//" *.dtd      # remove xml PI stuff.
$ sed -i '/./,/^$/!d' *.dtd                   # remove leading blank line(s).

happy hackin'
ko:
성능을 향상 시키는 방법:
  1. 메모리 사용량을 낮게 유지한다.
  2. CPU 사용률을 높게 유지한다.
  3. 한계를 넘어서지 않는 한 많은 수의 worker 를 동작시킨다. (2번을 실제 적용하는 유용한 방법중의 하나).
  4. 실행 흐름을 동기화가 필요하지 않은 방향으로 설계한다 (spawn후에 잊어버리기 전략. 3번과 일맥상통).

en:
to improve performance of concurrent program:
  1. always keep small footprint of memory usage.
  2. high CPU utilization.
  3. run workers as many as possible (of course, under limit). one of good methods for #2.
  4. design program flow to avoid synchronization. use spawn and forget strategy if possible.

happy hackin'

[FUN] Spiral Array

함수형 언어/Erlang 2008. 8. 13. 18:11 by manywaypark
여기에서 호기심을 조금 느꼈는데, 링크된 여기를 보고는 완전 몰입.

문제를 푸는 것자체는 그다지 어렵지 않았으나, 멋있게 풀어보려고, 오늘 출근길 지하철에서 타블렛에 좀 끄적였다.
W by H 행렬이라 보고, top left에서, 시계방향, 반시계방향 Spiral Array를 출력해주는 것을 만들었다.
(물론 요즘은 erlang에 심취해있으므로,  구현언어는 당연히 erlang이다.)

요지는 조건 검사 같은 것을 하는 것이아니라, 수열을 사용한다.
즉, 동일한 상태 이동의 반복 회수가 수열이다. 연속된 transition의 개수를 구하는 함수를 f(x)라 하면,
f(x) = f(x - 2) - 1

x가 2보다 크면 무조건 성립이고, x = 1, 2 일때의 값은 clockwise, counterclockwise에 따라 W 또는 H로 조금 달라지기는 하지만 중요한 요점은 수열을 이용해 계산으로 구한다는것이다. 자세한 건 코드 참조!

성능은 1000 x 1000의 결과 구하는데 3초정도 걸리는 것같다.

실행예:
(emacs@desktop)2> sa:do(5,4).
   1    2    3    4    5
  14   15   16   17    6
  13   20   19   18    7
  12   11   10    9    8
ok
(emacs@desktop)3> sa:do(4,5).
   1    2    3    4
  14   15   16    5
  13   20   17    6
  12   19   18    7
  11   10    9    8
ok
(emacs@desktop)5> element(1, timer:tc(sa,solve, [1000,1000])) / 1000000.
3.126565

code listing:

2008-08-18 : 거의 동일한 방법으로 푼 사람이 이미 있었다. 맨앞에 몇개와 끝부분의 erlang 버전만 확인하고서 획기적인 방법이라고 좋아라하고 있었다니.... Orz. 그래도 high order function을 사용해서 functional에 걸맞는 멋진 프로그램이라고 나 자신에게 조금은 구차한(?) 최면을 거는 중이다.

happy hackin'

일단 eunit으로 테스트를 하는 것을 가정한다.

unit test - makefile에서...
make file에 다음과 같은 부분을 추가한 후에, make test 하면 간편하게 명령행에서 unit test를 수행할 수있다.
(makefile 뼈대는 Programming Erlang을 기초로 했다.)

......
MODS = doc str_util db i18n tiny_scan
......

test: compile test_subdirs
    rm -rf Mnesia.nonode@nohost # removes previous mneisa db (optional).
    @for m in ${MODS};\
    do \
        echo "testing $$m";\
        ${ERL} -noshell -pz "subdir1" -pz "subdir2" -s $$m test -s init stop;\
    done

test_subdirs:
    cd subdir1; make test
    cd subdir2; make test

unit test, coverage test - 개발중 REPL(distel 또는 erl prompt) 에서...
REPL을 사용해서 (멋지게) 코딩-테스트를 반복중이라면, 다음과 같은 모듈을 하나 디렉토리에 넣어서 test:unit() 또는 test:cover() 를 실행시켜서 unit test 및 coverage test를 시시때때로 수행해 볼 수 있다.


테스트는 아무리 강조해도 지나치지 않다.
경험상 대부분의 버그는 테스트되지 않거나, 적절하지 못한 테스트(셋)들을 통과한 코드에 기생한다.

happy hackin'



해당 version: R12B-3

xmerl을 사용하여 다량의 xml 파일들을 파싱하는 도중에 특정 파일에서 CPU/메모리사용량이 치솟고 다음과 같은 에러메시지와 함께 erlang이 죽어버렸다.

eheap_alloc: Cannot allocate xxxxx bytes of memory (of type "heap").

특정 파일 하나에서만 이 현상이 생겼는데, 파일을 열어보니 복잡한 테이블과, entity들을 많이 사용한 xml이었다. 조금 복잡하긴 했지만 정상적인 xml이었다.

검색한 결과 xmerl_scan의 버그임이 밝혀졌다.
(R12B-4 에서는 패치된 버전이 포함될 것이라고 한다).

링크에 나와있는대로 한줄만 고쳐주면 에러없이 잘 동작한다.



happy hackin'

erlang build 하기

함수형 언어/Erlang 2008. 7. 29. 23:22 by manywaypark
압축풀고 README에 있는 프로그램들 깔려있는지 확인하고,
$ ./configure --enable-hipe --enable-threads
$ make
$ sudo make install

(odd) case error of
checking for C compiler default output file name... configure: error: C compiler cannot create executables
See `config.log' for more details.
-> install libc (apt-get install libc6-dev).
end.

2008-11-01: 간만에 새로 ubuntu를 설치한 박스에서 erlang을 build하려고 시도하니, 필요한 패키지가 정확하게 드러났다.
현재 최신의 OTP-R12B-4를 빌드할 때 모든 기능을 활성화 하기위한 패키지들은 다음과같다.
m4
autoconf
g++
libc6-dev
libncurses5-dev
unixodbc-dev
libssl-dev

happy hackin'
erlang의 one-time assignment를 이용한 간단한 리팩토링에 관해서 설명한다.

erlang에서의 변수 특성:
  1. erlang은 변수에 값(value)를 한번만 할당(assign)할 수 있다.
  2. 한번 값이 할당된 변수는 이전과 동일한 값을 할당하지 않으면 에러가 난다.

확인:
(emacs@desktop)54> Foo = 1.
1
(emacs@desktop)55> Foo = 1.
1
(emacs@desktop)56> Foo = 2.
** exception error: no match of right hand side value 2

리팩토링은 보통 코드의 결과는 그대로 유지하면서 내부를 개선하는 것으로 정의된다.

변수 특성을 이용한 리팩토링 절차:
  1. 리팩토링할 함수를 정한다.
  2. 함수의 결과값을 변수에 저장한다. (적절한 인자를 줄 수도 있다)
  3. 함수 리팩토링 & 컴파일
  4. 같은 변수에 새 함수의 결과값을 대입해본다.
  5. 에러 체크.

간단한 함수의 경우는 이 방법이 별 필요가 없을 수도 있지만, 수백 수천개의 list element들을 결과로 리턴하는 경우에는 꽤나 유용하다.

각각 다른 변수(Before, After)에 대입해서 =:= 연산자로 비교할 수도 있겠지만, 그냥 같은 변수에 대입해 보는 것이 조금 더 편하다. (자연스런 REPL loop + history 기능 활용)

물론 여기서 설명한 것은 간단히 빨리 테스트해보아야할 경우를 위한 것이다. 실제 제품개발에는 eunit같은 unit test tool을 적용해 조직화된 테스트셋을 구성해야한다.

happy hackin'

xml 파일을 저장하기위해 다음과 같은 함수를 만들었다.
save_xml(Path, RootEl) ->
    {ok,IOF}=file:open(Path,[write]),
    Export=xmerl:export_simple([RootEl], xmerl_xml),
    io:format(IOF,"~s~n", [lists:flatten(Export)]),
    file:close(IOF).

에러가 났다.
83> foo:save_xml("/tmp/foo.xml", Root).
** exception exit: {badarg,[{io,format,
                                [<0.3348.0>,"~s~n",
                                 [[60,63,120,109,108,32,118,101,114,115,105,
                                   111,110,61,34,49,46,48,34|...]]]},
                            {erl_eval,do_apply,5},
                            {shell,exprs,6},
                            {shell,eval_exprs,6},
                            {shell,eval_loop,3}]}
     in function  io:o_request/2

이거 분명히 예전에 공부할 때 예제가 동작하는 것을 확인한 함수였는데....
binary로 써보기로했다.
84> Export=xmerl:export_simple([Root], xmerl_xml).
      ........
85> file:write_file("/tmp/1.xml", list_to_binary(lists:flatten(Export))).
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([60,63,120,109,108,32,118,101,114,115,105,
                                  111,110,61,34,49,46,48,34,63,62,60,111,108,
                                  100,114,103,112|...])

한글이 포함되어 안되는 것으로 짐작이 갔다.
99> list_to_binary([0, 1, 2]).
<<0,1,2>>
100> list_to_binary([0, 1, 2, 255]).
<<0,1,2,255>>
101> list_to_binary([0, 1, 2, 255, 256]).
** exception error: bad argument
     in function  list_to_binary/1
        called as list_to_binary([0,1,2,255,256])

결론은 list_to_binary가 255를 넘어가는 non-ascii를 제대로 처리하지 못해서였다.
102> list_to_binary(xmerl_ucs:to_utf8([0, 1, 2, 255, 256])).
<<0,1,2,195,191,196,128>>
103> file:write_file("/tmp/1.xml", list_to_binary(xmerl_ucs:to_utf8(lists:flatten(Export)))).
ok

맨 처음 함수는 이런 식으로 변경:
save_xml(Path, RootEl) ->
    {ok,IOF}=file:open(Path,[write]),
    Export=xmerl:export_simple([RootEl], xmerl_xml),
    io:format(IOF,"~s~n", [xmerl_ucs:to_utf8(lists:flatten(Export))]),
    file:close(IOF).

참고: http://intertwingly.net/blog/2007/09/14/ASCII-ISO-8859-1-UCS-and-Erlang

happy hackin'
esolr를 사용하려고 좀 만지작 거리다가, 버그를 하나 발견해서, 리포팅했다.
설명에 나온 기본 세팅으로 하면 잘 되는 것처럼 보이지만, select_url과 search_url 두개의 key가 Option을 설정할 때와 읽어올 때 혼동되게 되어있어서, solr의 URL을 정해주면 제대로 동작하지 않는 버그였다.
딸리는 영어지만 원작자의 페이지에 댓글을 달아두었다. ^^;

happy hackin'
version info:
os:
Windows XP (on Fujitsu Lifebook U1010)
emacs:
This is GNU Emacs 22.1.1 (i386-mingw-nt5.1.2600)
 of 2007-06-02 on RELEASE
distel:
revision 64


Distel을  make (base)로 설치시에 다음과 같은 오류가 나면서 멈추었다.

emacs -batch -f batch-byte-compile elisp/erlext.el
Cannot open load file: korea-util
make: *** [elisp/erlext.elc] Error 127

emacs 쪽에서 byte compile을 하다가 오류가 난거 같았는데, Makefile을 보니 좀 복잡했다.
그냥 혹시나 하는 마음에 앵무새짓거리 한번...
C:\home\hacking\erlang\distel>emacs -batch -f batch-byte-compile elisp/erlext.el

Loading subst-jis...
Loading subst-big5...
Loading subst-gb2312...
Loading subst-ksc...
Loading cl-extra...
Wrote c:/home/hacking/erlang/distel/elisp/erlext.elc

잉? 된건가?
C:\home\hacking\erlang\distel>make
make: Nothing to be done for `base'.

된거군!
(이유가 궁금하긴 하지만, Windows에서 일어난 일이므로 신경끈다.  ^^)

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)

공지사항

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

05-06 20:04