ABCLをちょっと触る
Scalaから何らかのLisp方言に乗り換える場合にはJVMのライブラリ関連があるからClojureを使うのが普通の流れな気がするが、Common LispにもJVMで動くABCLという処理系があるので試してみた。
Armed Bear Common Lisp (ABCL) - Common Lisp on the JVM
Docker使うととりあえず動く。
docker run -it easye/abcl
REPLが立ち上がるのでQuicklispを入れる。
(load "http://beta.quicklisp.org/quicklisp.lisp") (quicklisp-quickstart:install)
GitHub - fukamachi/clack: Web server abstraction layer for Common Lisp
とりあえずhunchentootとclackを入れて、Usageにあるサンプルを動かしてみる。
(ql:quickload '(:hunchentoot :clack)) (defvar *handler* (clack:clackup (lambda (env) (declare (ignore env)) '(200 (:content-type "text/plain") ("Hello, ABCL!")))))
UsageにはWebブラウザで http://localhost:5000/ にアクセスしろ、とあるがdocker内で動作しているからdexadorで試す。
(ql:quickload :dexador) (dex:get "http://localhost:5000/")
動いた。
"Hello, ABCL!" 200 #<EQUAL HASH-TABLE 4 entries, 11 buckets {33B1D2E7}> #<QURI.URI.HTTP:URI-HTTP http://localhost:5000/> #<TWO-WAY-STREAM {1A6F263C}>
HelixキーボードのhexファイルをUbuntuのavrdudeで書き込む
Helix キーボードキット | 遊舎工房 のドキュメントにはLinuxでの書き込み方が書いておらず、Releases · qmk/qmk_toolbox · GitHub のLinux版も動かなかったので、コマンドラインから実行したメモ
# USBを接続する stty -F /dev/ttyACM0 ospeed 1200 ispeed 1200 stty -F /dev/ttyACM0 speed 115200 # Helixのリセットボタンを押す avrdude -p atmega32u4 -c avr109 -P /dev/ttyACM0 -U flash:w:helix_rev2_default.hex
Nextremer退職
2018年6月で株式会社Nextremerを退職しました。理由はお察し下さい。
1年半チョットの在籍中、LEGOを動かしたり、ホビーロボを組み合わせて動かしたり ( ディープラーニングで「うまい棒」と「都こんぶ」を仕分けるマシン 20万回の訓練でつかむ位置まで正確に学習 - ねとらぼ)、ロボットシミュレーションの為にxml書いたりしていた。 後、機械学習でPythonも少し書いてた。
結果的に、遥か昔に辞めたはずのロボット開発に戻ってきたのは不思議な感じだった。何でもやっておくと役に立つもんだなあ。 そんなに深くやったわけではないけど、20年位前のロボット開発と比べて思うのは、色々パーツとかキットが抱負になったのと、3Dプリンターが安価になって使われてることか。
次の会社では再び職業Common Lisperになる予定 (2年ぶり2回目)
Graph 500のコードを動かしてみた
Graph 500 | large-scale benchmarks
Graph 500というスパコンベンチがあって、これのコードは公開されているので触ってみた。 スパコン持ってないので、実験機材は普通のノートPCにUbuntu 16.04が入ったもの。
まずはv3.0.0のコードをもらってくる。 https://github.com/graph500/graph500/archive/graph500-3.0.0.tar.gz
mpi関連をインストールする。
apt install mpich
展開する。
tar xzf graph500-3.0.0.tar.gz cd graph500-graph500-3.0.0/
このままビルドするとリンクでエラーになるので、Makefile内のコンパイル引数に指定されている -lpthread
とか -lm
を後ろに持っていく。
ビルドする。
make
ビルド結果としては4つの実行ファイルが出来上がるが、名前に reference
と付いている方は実行可能で、 custom
と付いている方は動かない(本来の目的である、自分の実装をするためのものなので)。
ローカルでmpiの4並列実行してみる。
time mpiexec -n 4 ./graph500_reference_bfs 20
結果は長いので最後だけ抜粋。
SCALE: 20 edgefactor: 16 NBFS: 64 graph_generation: 4.61012 num_mpi_processes: 4 construction_time: 1.36205 bfs min_time: 0.277266 bfs firstquartile_time: 0.283024 bfs median_time: 0.291698 bfs thirdquartile_time: 0.302793 bfs max_time: 0.349763 bfs mean_time: 0.295806 bfs stddev_time: 0.0167295 min_nedge: 16775818 firstquartile_nedge: 16775818 median_nedge: 16775818 thirdquartile_nedge: 16775818 max_nedge: 16775818 mean_nedge: 16775818 stddev_nedge: 0 bfs min_TEPS: 4.79634e+07 bfs firstquartile_TEPS: 5.54037e+07 bfs median_TEPS: 5.75108e+07 bfs thirdquartile_TEPS: 5.92735e+07 bfs max_TEPS: 6.05044e+07 bfs harmonic_mean_TEPS: ! 5.67123e+07 bfs harmonic_stddev_TEPS: 404095 bfs min_validate: 1.18584 bfs firstquartile_validate: 1.21473 bfs median_validate: 1.22582 bfs thirdquartile_validate: 1.26528 bfs max_validate: 1.44657 bfs mean_validate: 1.24752 bfs stddev_validate: 0.0512569 real 1m50.265s user 6m41.675s sys 0m25.753s
なんとなく動いた。
Complete Results | Graph 500 を見るとパソコンレベルの1ノード構成でも1GTEPSくらいは出るみたいなので、max 0.06GTEPSはかなり遅い気がする。
reference
だとそんなもんなんだろうか?
Common Lispで最速のfizzbuzzを実装した話
Kazuho氏のblogにこういうのがあったのでCommon Lispでやってみた。
Common Lispで実装する。
(defmacro fizzbuzz (n) (format nil "~{~a ~}" (loop for i from 1 below n collect (cond ((= 0 (mod i 15)) "fizzbuzz") ((= 0 (mod i 5)) "buzz") ((= 0 (mod i 3)) "fizz") (t i))))) (defun main () (print (fizzbuzz 100)))
* (disassemble #'main) ; disassembly for MAIN ; Size: 33 bytes. Origin: #x100195397C ; 7C: 498B4C2460 MOV RCX, [R12+96] ; no-arg-parsing entry point ; thread.binding-stack-pointer ; 81: 48894DF8 MOV [RBP-8], RCX ; 85: 488B15A4FFFFFF MOV RDX, [RIP-92] ; "1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz " ; 8C: B902000000 MOV ECX, 2 ; 91: FF7508 PUSH QWORD PTR [RBP+8] ; 94: B8D8213620 MOV EAX, #x203621D8 ; #<FDEFN PRINT> ; 99: FFE0 JMP RAX ; 9B: CC10 BREAK 16 ; Invalid argument count trap NIL
文字列をprintするだけのmain関数が生成された。
Pythonのmultiprocessingおよびpipe実行時間
Pythonのmultiprocessingおよびpipeの実行時間計測。
multiprocessing
code
#!/usr/bin/env python # # see also : http://docs.python.jp/2.7/library/multiprocessing.html from sys import stdout from time import time from multiprocessing import Process, Pipe NUMBER = 1000 def measurement(f): time_start = time() for n in range(NUMBER): f() time_end = time() return time_end - time_start def dummy(): pass def create_process(): Process() def start_process(): Process().start() def create_pipe(): Pipe() def join_process(): process = Process() process.start() process.join() def null_process(pipe1, number): for n in range(number): pipe1.recv() def measurement_simplex_pipe(): time_start = time() pipe0, pipe1 = Pipe() process = Process(target=null_process, args=(pipe1, NUMBER)) process.start() for n in range(NUMBER): pipe0.send(n) process.join() time_end = time() return time_end - time_start def echo_process(pipe1, number): for n in range(number): pipe1.send(pipe1.recv()) def measurement_duplex_pipe(): time_start = time() pipe0, pipe1 = Pipe() process = Process(target=echo_process, args=(pipe1, NUMBER)) process.start() for n in range(NUMBER): pipe0.send(n) pipe0.recv() process.join() time_end = time() return time_end - time_start stdout.write("pass, %f\n" % measurement(dummy)) stdout.write("create process, %f\n" % measurement(create_process)) stdout.write("start process, %f\n" % measurement(start_process)) stdout.write("join process, %f\n" % measurement(join_process)) stdout.write("create pipe, %f\n" % measurement(create_pipe)) stdout.write("simplex pipe, %f\n" % measurement_simplex_pipe()) stdout.write("duplex pipe, %f\n" % measurement_duplex_pipe())
Python 2.7
処理 | 実行時間 (ms) |
---|---|
pass | 0.000079 |
create process | 0.003357 |
start process | 0.245117 |
join process | 0.976598 |
create pipe | 0.011329 |
simplex pipe | 0.003099 |
duplex pipe | 0.011246 |
Python 3.5
処理 | 実行時間 (ms) |
---|---|
pass | 0.000067 |
create process | 0.003868 |
start process | 0.415079 |
join process | 1.492507 |
create pipe | 0.035219 |
simplex pipe | 0.007089 |
duplex pipe | 0.047015 |
pipe
code
#!/usr/bin/env python # # see also : http://docs.python.jp/2.7/library/multiprocessing.html # http://docs.chainer.org/en/stable/tutorial/basic.html from sys import stdout from time import time from multiprocessing import Process, Pipe from chainer import Chain, ChainList from chainer.links import Linear NUMBER = 1000 def measurement(f): time_start = time() for n in range(NUMBER): f() time_end = time() return time_end - time_start def null_process(pipe1, number): for n in range(number): pipe1.recv() def measurement_simplex_pipe(klass): time_start = time() pipe0, pipe1 = Pipe() process = Process(target=null_process, args=(pipe1, NUMBER)) process.start() for n in range(NUMBER): pipe0.send(klass) process.join() time_end = time() return time_end - time_start def echo_process(pipe1, number): for n in range(number): pipe1.send(pipe1.recv()) def measurement_duplex_pipe(klass): time_start = time() pipe0, pipe1 = Pipe() process = Process(target=echo_process, args=(pipe1, NUMBER)) process.start() for n in range(NUMBER): pipe0.send(klass) pipe0.recv() process.join() time_end = time() return time_end - time_start class MyChain(Chain): def __init__(self): super(MyChain, self).__init__( l1=Linear(784, 100), l2=Linear(100, 100), l3=Linear(100, 10) ) def __call__(self, x): h1 = relu(self.l1(x)) h2 = relu(self.l2(h1)) return self.l3(h2) class MyChainList(ChainList): def __init__(self): super(MyChainList, self).__init__( Linear(784, 100), Linear(100, 100), Linear(100, 10) ) def __call__(self, x): h1 = relu(self[0](x)) h2 = relu(self[1](h1)) return self.l3(h2) classies = [Chain, ChainList, MyChain, MyChainList] for k in classies: stdout.write("create instance %s, %f\n" % (k, measurement(lambda: k()))) for k in classies: stdout.write("simplex pipe %s, %f\n" % (k, measurement_simplex_pipe(k))) for k in classies: stdout.write("duplex pipe %s, %f\n" % (k, measurement_duplex_pipe(k)))
Python 2.7
処理 | 実行時間 (ms) |
---|---|
create instance Chain | 0.003006 |
create instance ChainList | 0.001593 |
create instance MyChain | 3.788916 |
create instance MyChainList | 3.780761 |
simplex pipe Chain | 0.005608 |
simplex pipe ChainList | 0.005627 |
simplex pipe MyChain | 0.006494 |
simplex pipe MyChainList | 0.006871 |
duplex pipe Chain | 0.029776 |
duplex pipe ChainList | 0.034982 |
duplex pipe MyChain | 0.033020 |
duplex pipe MyChainList | 0.035376 |
Python 3.5
処理 | 実行時間 (ms) |
---|---|
create instance Chain | 0.002134 |
create instance ChainList | 0.001779 |
create instance MyChain | 4.150180 |
create instance MyChainList | 4.152344 |
simplex pipe Chain | 0.013076 |
simplex pipe ChainList | 0.013038 |
simplex pipe MyChain | 0.013047 |
simplex pipe MyChainList | 0.010454 |
duplex pipe Chain | 0.065646 |
duplex pipe ChainList | 0.070427 |
duplex pipe MyChain | 0.076342 |
duplex pipe MyChainList | 0.079283 |
ZenBook3のベンチマーク
SysBenchを使ってZenBook3のベンチマークを取ってみた。
インストール
apt install sysbench
ファイルIO
準備する。
cd /tmp sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw prepare
sysbench 0.4.12: multi-threaded system evaluation benchmark 128 files, 24576Kb each, 3072Mb total Creating files for the test...
ランダム読み書き
helpにあったとおりにベンチマークを実行する。
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw run
sysbench 0.4.12: multi-threaded system evaluation benchmark Running the test with following options: Number of threads: 16 Extra file open flags: 0 128 files, 24Mb each 3Gb total file size Block size 16Kb Number of random requests for random IO: 10000 Read/Write ratio for combined random IO test: 1.50 Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing random r/w test Threads started! Done. Operations performed: 6013 Read, 4009 Write, 12805 Other = 22827 Total Read 93.953Mb Written 62.641Mb Total transferred 156.59Mb (16.71Mb/sec) 1069.46 Requests/sec executed Test execution summary: total time: 9.3711s total number of events: 10022 total time taken by event execution: 0.0953 per-request statistics: min: 0.00ms avg: 0.01ms max: 5.05ms approx. 95 percentile: 0.01ms Threads fairness: events (avg/stddev): 626.3750/185.14 execution time (avg/stddev): 0.0060/0.00
全然読み方がわからないけど、これ3GB指定してるけど3GBアクセスしてない?なんか読み書きのサイズ調整が必要なのか? とりあえずスレッド数を変更してたら数字が良かったのが8192。
sysbench --num-threads=8192 --test=fileio --file-total-size=3G --file-test-mode=rndrw run
sysbench 0.4.12: multi-threaded system evaluation benchmark Running the test with following options: Number of threads: 8192 Extra file open flags: 0 128 files, 24Mb each 3Gb total file size Block size 16Kb Number of random requests for random IO: 10000 Read/Write ratio for combined random IO test: 1.50 Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing random r/w test Threads started! Done. Operations performed: 4091 Read, 6009 Write, 11916 Other = 22016 Total Read 63.922Mb Written 93.891Mb Total transferred 157.81Mb (448.62Mb/sec) 28711.73 Requests/sec executed Test execution summary: total time: 0.3518s total number of events: 10100 total time taken by event execution: 275.5066 per-request statistics: min: 0.00ms avg: 27.28ms max: 148.04ms approx. 95 percentile: 134.86ms Threads fairness: events (avg/stddev): 1.2329/4.82 execution time (avg/stddev): 0.0336/0.04
56MB/sくらい。 本当に8192スレッドで実行してるんだろうか。
シーケンシャル読み
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=seqrd run
sysbench 0.4.12: multi-threaded system evaluation benchmark Running the test with following options: Number of threads: 16 Extra file open flags: 0 128 files, 24Mb each 3Gb total file size Block size 16Kb Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing sequential read test Threads started! FATAL: Too large position discovered in request! Done. Operations performed: 196607 Read, 0 Write, 0 Other = 196607 Total Read 3Gb Written 0b Total transferred 3Gb (16.015Gb/sec) 1049527.74 Requests/sec executed Test execution summary: total time: 0.1873s total number of events: 196607 total time taken by event execution: 2.5037 per-request statistics: min: 0.00ms avg: 0.01ms max: 41.00ms approx. 95 percentile: 0.00ms Threads fairness: events (avg/stddev): 12287.9375/3411.79 execution time (avg/stddev): 0.1565/0.04
2GB/sくらい。 仕様上PCIe 3.0 x4接続でバスの片道理論性能が4GB/sだから、実効性能限界出てるかはわからないけどそれなりのオーダで計れてそうなのは分かった。
シーケンシャル書き
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=seqwr run
sysbench 0.4.12: multi-threaded system evaluation benchmark Running the test with following options: Number of threads: 16 Extra file open flags: 0 128 files, 24Mb each 3Gb total file size Block size 16Kb Periodic FSYNC enabled, calling fsync() each 100 requests. Calling fsync() at the end of test, Enabled. Using synchronous I/O mode Doing sequential write (creation) test Threads started! Done. Operations performed: 0 Read, 196608 Write, 128 Other = 196736 Total Read 0b Written 3Gb Total transferred 3Gb (581.51Mb/sec) 37216.69 Requests/sec executed Test execution summary: total time: 5.2828s total number of events: 196608 total time taken by event execution: 25.3832 per-request statistics: min: 0.00ms avg: 0.13ms max: 48.05ms approx. 95 percentile: 0.03ms Threads fairness: events (avg/stddev): 12288.0000/1694.04 execution time (avg/stddev): 1.5864/0.01
73MB/sくらい。
片付け
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw cleanup
結論
これ真面目に色々やらないと正しい値が取れないな。。。