どう書くにまた投げた:コード中の文字の頻度分析
http://ja.doukaku.org/comment/6822/
入出力のバッファリングが必要なサイズの処理に行き当たったのは、いい経験だった。
binary_to_listを実行すると、いきなりすごい量のheap領域を確保しようとしてメモリ不足で死んだりもした。そこで、40KBぐらいをバイナリデータから切り出して、それをbinary_to_listしてから処理した。
以下、シンプルバージョン(富豪バージョンとも言う)
#!/usr/bin/env escript main(_) -> loop(io:get_chars('',1)). loop(eof) -> show_histgram(lists:sort(get())); loop(Chr) -> incr(Chr), loop(io:get_chars('',1)). incr(Chr) -> case Count = get(Chr) of undefined -> put(Chr,1); _ -> put(Chr,Count + 1) end. show_histgram([H|[]]) -> {K,V} = H, io:format("~p,~p~n",[K, V]); show_histgram([H|L]) -> {K,V} = H, io:format("~p,~p~n",[K, V]), show_histgram(L).
このコードでもプロセス辞書(get, putしているもの、ハッシュだと思えばいい)を使っているが、writevのシステムコールが頻発しているのが気に入らない。
これはワークメモリ上で完結する処理にできないものか?
$ strace -c ./hist1.erl < 小さなテストデータ "\t",160 "\n",1000 " ",3201 "!",7 "\"",130 "#",2 "%",802 "&",1 "'",254 "(",422 ")",422 ",",682 "-",3885 ".",215 "/",166 "0",75 "1",75 "2",62 "3",25 "4",9 "5",4 "6",2 "7",2 "8",6 ":",407 ";",76 "<",10 "=",132 ">",201 "?",63 "A",66 "B",10 "C",160 "D",136 "E",314 "F",147 "G",3 "H",135 "I",177 "K",12 "L",114 "M",82 "N",53 "O",346 "P",238 "R",121 "S",292 "T",235 "U",79 "V",146 "W",6 "X",7 "Y",4 "Z",1 "[",118 "]",118 "_",1388 "a",999 "b",126 "c",746 "d",433 "e",2990 "f",453 "g",336 "h",157 "i",1137 "j",15 "k",62 "l",939 "m",343 "n",971 "o",1526 "p",1020 "q",2 "r",1786 "s",1148 "t",1802 "u",341 "v",184 "w",114 "x",66 "y",449 "z",10 "{",81 "|",8 "}",81 % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 74.77 0.293033 8 35419 writev 6.88 0.026954 9 2845 clock_gettime 6.86 0.026880 10 2807 poll 3.16 0.012374 128 97 read 2.25 0.008801 677 13 8 execve 1.53 0.005979 38 159 60 open 0.99 0.003885 22 175 61 stat64 0.73 0.002868 27 106 close 0.39 0.001526 127 12 futex 0.39 0.001510 94 16 munmap 0.37 0.001459 58 25 getcwd 0.37 0.001443 72 20 mprotect 0.33 0.001299 38 34 fstat64 0.25 0.000999 38 26 fcntl64 0.16 0.000616 123 5 3 ioctl 0.14 0.000551 6 93 mmap2 0.14 0.000542 7 81 rt_sigaction 0.13 0.000516 516 1 sigaltstack 0.13 0.000503 5 101 53 access 0.04 0.000151 38 4 2 waitpid 0.00 0.000007 0 19 brk 0.00 0.000003 1 5 set_thread_area 0.00 0.000001 0 31 rt_sigprocmask 0.00 0.000000 0 3 time 0.00 0.000000 0 1 getpid 0.00 0.000000 0 5 pipe 0.00 0.000000 0 2 dup2 0.00 0.000000 0 1 getppid 0.00 0.000000 0 1 getpgrp 0.00 0.000000 0 11 gettimeofday 0.00 0.000000 0 1 readlink 0.00 0.000000 0 2 sigreturn 0.00 0.000000 0 2 clone 0.00 0.000000 0 5 uname 0.00 0.000000 0 4 _llseek 0.00 0.000000 0 1 vfork 0.00 0.000000 0 3 getrlimit 0.00 0.000000 0 1 getuid32 0.00 0.000000 0 1 getgid32 0.00 0.000000 0 1 geteuid32 0.00 0.000000 0 1 getegid32 0.00 0.000000 0 8 getdents64 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 1 set_robust_list 0.00 0.000000 0 1 socket 0.00 0.000000 0 1 bind 0.00 0.000000 0 1 getsockname 0.00 0.000000 0 3 setsockopt 0.00 0.000000 0 2 getsockopt ------ ----------- ----------- --------- --------- ---------------- 100.00 0.391900 42158 187 total