Pkg of julia

非常に暑いんで、みんな図書館に涼みに行ってるせいか、大混雑。さっさと借りてきた。 「衰退産業でも稼げます」田舎にぴったりの本かと思ったら、そうでもなかった。

京都の米販売店の復興、京都のねぎ農家、和傘屋さんの若旦那の発想の転換。 老舗と言って、安心していては駄目。時代に置いていかれる。某家に伝わる家訓。

『心は変えずに形を変えよ』

確かにそうだね。

そして、勿論、田舎の企業の話も出てくる。広島の熊野町にある、筆屋さん。伝統の筆を 作っていたけど、衰退ムード。そこで考え付いたのは、無限のキャンパスを相手にすれば いいって発想。

女性の顔は日本に限らず、世界中にある。しかも留まる事を知らず。ならば、このキャンパス 用の筆を作っちゃえ。かくして化粧専用の筆の誕生。面白いなあ。

juliaの型の事について調べていたんだ。そしたら型のTopに君臨してるのはAnyだよって説明されてた。これから派生して色々な型が生まれて行くのね。まるで、生物の進化の世界みたいだな。

型をクラスに置き換えても成り立ちそうだけど、どうやら、juliaの作者の方々は、何でもオブジェクト(クラス)って世界が嫌いなようだ。オイラーと同じ方向を向いているな。まあ出目がlispなんで、CLOSは敬遠しました、そしたら、clojureとそっくりになっちゃいましたって所が真相のような気がするけど。

んな訳で、Anyからどんな進化の幹が出来ているか、表層を探ってみる。例によって結果をLOGしたいので、コマンドラインからの実行です。

(base) cent:tmp$ julia -E 'subtypes(Any)' > LOG
ERROR: UndefVarError: subtypes not defined
Stacktrace:
 [1] top-level scope at none:0

で、早速妨害されましたよ。repl上では上手くいくんだけどね。

(base) cent:tmp$ julia -q
julia> @which subtypes
InteractiveUtils

しょうがないので、subtypesの出目を調べます。こういう時は、whichのマクロを使うのさ。

(base) cent:tmp$ julia -e 'using InteractiveUtils; for e in subtypes(Any) println(e); end' > LOG
(base) cent:tmp$ wc LOG
 398  398 8381 LOG

repl上での結果と等しい事を確認の上、unixのコマンドを駆使。Pkgに従属してる型が有るので、それを少し考慮しましょ。

(base) cent:tmp$ cut -d. -f1 LOG | uniq -c | sort -nr
    101 Core
     87 Base
     42 LibGit2
     37 Pkg
     17 Markdown
     13 REPL
     11 Distributed
      8 Dates
      7 FileWatching
      6 Random
      5 Test
      3 LinearAlgebra
      2 Sockets
      2 SHA
      2 Profile
      1 WeakRef
      1 VersionNumber
      :

やっぱり、Coreパッケージ内がダントツ。次はBase内。gitが幅を利かせているなあ。OSSのソースをGitに預けてしまうのは、多様性の観点から、いかがなものかと。

julia> subtypes(Number)
2-element Array{Any,1}:
 Complex
 Real

julia> subtypes(Real)
4-element Array{Any,1}:
 AbstractFloat
 AbstractIrrational
 Integer
 Rational

julia> subtypes(AbstractFloat)
4-element Array{Any,1}:
 BigFloat
 Float16
 Float32
 Float64

少し数の幹を辿ってみました。Complexに進化させたのは、誰でしたっけ? オイラーさんより前の人だったよな。2次方程式の解法あたりからの発明品だったような。。。。

(base) cent:tmp$ egrep '^REPL' LOG
REPL.AbstractREPL
REPL.LineEdit.CompletionProvider
REPL.LineEdit.HistoryProvider
REPL.LineEdit.InputAreaState
REPL.LineEdit.KeyAlias
REPL.LineEdit.MIState
REPL.LineEdit.ModeState
REPL.LineEdit.TextInterface
REPL.Options
REPL.REPLBackend
REPL.REPLBackendRef
REPL.REPLCompletions.Completion
REPL.TerminalMenus.AbstractMenu

常日頃お世話になってるREPL族のそれ。丹念に見ていったら面白いだろうね。

まてまて、もっと大きな獲物が居るよ。

llvm

LLVMを始めよう! 〜 LLVM IRの基礎はclangが教えてくれた・Brainf**kコンパイラを作ってみよう 〜

LLVM

知っておいて損はない「コンパイラ最適化」の数々

LLVMをちょっと調べてみた

なんか、大きすぎる話題で、さっと通り過ぎる事は出来ないな。

せいぜい、OpenBSDにでもllvmのパッケージを入れて、lli,llc,optあたりを試してみますかね。それとも先にdebianあたりに入れてみようか。> 入れたら、llvm 7.0.1-8 が来たぞ。最新の8.0では、webassmblerってかjavascriptを最終ターゲットに出来るようですよ。

低レイヤを知りたい人のためのCコンパイラ作成入門

コンパイルの事を深く知りたいなら、これお勧め。著者を何となく知っているぞ。

Pkg

(base) cent:~$ ls .julia/
compiled/  conda/  environments/  logs/  packages/  prefs/  registries/

juliaも御多分に漏れず、ユーザー毎にpkgを管理出来る仕組みになってる。compiled内は、llvmの中間コードが入ってる。何故最終コードまで落としておかないかは非常に疑問。packagesの中は、それぞれのsrcとかの類が入ってる。registriesの中は、世に公開されてるpkgのカタログが入ってる。ざっと数えると、その数3000。まだまだpythonには追い付かない。

世にどんなのが公開されてるかは、registriesの中を見れば一発なんだけど、やっぱり食べログとかミシュランみたいに人気パッケージを使ってみたい。

Julia Observer

を見れば、カテゴリー別に、人気が分かる。IjuliaやFluxが不動の人気を集めている所を見れば、客層が分かるってもんです。

非常に美味しそうなパッケージが見つかった。

Julia - PackageCompiler.jl を使って Plots.jl を早くする

あのグラフを書くまでの待ち時間が激減するらしい。これで、juliaもoctaveに少しは近づくかな。早速やってみよう。

 @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:524
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
ERROR: LoadError: LoadError: ArgumentError: Package VisualRegressionTests [34922c18-7c2a-561c-bac1-01e79b2c4c92] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.
 :
Stacktrace:
 [1] _require(::Base.PkgId) at ./loading.jl:929
 [2] require(::Base.PkgId) at ./loading.jl:858

ERROR: failed process: Process(`/usr/local/julia/bin/julia
  --sysimage=/home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/backup/native/sys.so
  --output-o=sys.a --track-allocation=none --code-coverage=none
  --history-file=yes --inline=yes --math-mode=ieee --compile=yes
  --track-allocation=none --sysimage-native-code=yes
  --sysimage=/usr/local/julia/lib/julia/sys.so --compiled-modules=yes
  --optimize=2 /home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/run_julia_code.jl`
, ProcessExited(1)) [1]
  :

見事に失敗。雰囲気から、Pkgになってるの(含むPlots)を事前にネイティブコードまで落として、そいつをsys.soに押し込めちゃえって方針みたいだ。そうすれば、コンパイルが全く必要無くなる。丁度CommonLispとかのsys-dumpの思想だな。

残念ながら、望みはかなわなかったけど、生暖かく見守って、ほとぼりが冷めた頃、再チャレンジしてみますかね。

Static Data Image

こういう方法も有るのか。

Gnuplot

上の方法が上手くいかないので、繋ぎとしてGnuplotを入れてみるか。ランキングでは過疎ってるけど、老舗だよな。組み合わせて使うUnix流だもの。それに引き換え上のように車輪の再発明をするのは、いかがなものかと。

まてまて、これも時流の要求でしょうがない。Unixなんて知らないとか、ジュピターみたいにブラウザーにさっと張り付いて欲しいって要求に答えるのは難しいだろうからね。

で、過去にgnuplot + julia を動かそうとして、色々と苦労した覚えがある。そんな訳でちょいと下調べしたよ。そしたらgnuplotが新し目な奴を要求してる事が分かった。

ターゲットは一応CentOSなんで、入ってるやつを確認したら、ぎりぎりで要求を満たしていない。そこで、下記を参照して新しいgnuplotに取り換えた。

centos gnuplot ビルド

パッケージは、すんなり入ったぞ。unix職人さんが細々と技術を伝承しててくれたのね。有り難い事です。で、早速動作確認。

julia> @time using Gnuplot
[ Info:   Gnuplot version: 5.2.0
  2.576322 seconds (2.35 M allocations: 129.211 MiB, 4.06% gc time)

julia> @time Gnuplot.@gp 1:10
[ Info: Creating session default...
[ Info:   Gnuplot version: 5.2.0
GNUPLOT (default) -> wxt
GNUPLOT (default) -> 0 enhanced
  1.668579 seconds (3.72 M allocations: 183.929 MiB, 3.44% gc time)

julia> @time Gnuplot.@gp 1:10
  0.001052 seconds (117 allocations: 4.969 KiB)

これなら、大してストレスなく使えるな。で、今更ながら気づいたんだけど、MobaXterm内蔵のXからしか、上記は動かんかった。まあ、しょうがないか。

A Julia interface to Gnuplot.

これを見れば、ほとんどgnuplotのコマンドを知ってるだけで、扱える事が分かる。脳への負担削減は切実な問題ですからねぇ。

compile

上で見つけておいた、部分的にコンパイルする方法で、Plotsの組み込みにチャレンジ。

julia> PackageCompiler.compile_incremental( :Plots, force = false)

forceがfalseになってるのは、既存の物を保護する目的。

 @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:524
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
ERROR: LoadError: LoadError: ArgumentError: Package UnicodePlots [b8865327-cd53-5732-bb35-84acbb429228] is required but does not seem to be installed:
 - Run `Pkg.instantiate()` to install all recorded dependencies.

で、こんなエラーが出て来るのよね。アドバイスに従って、Pkg.instantiate()するも、さっぱり依存関係を解決してくれない。この関門をくぐり抜ける方法は、上の例だと、UnicodePlotsを入れる事。こんな調子で、Images,ImageMagic,LaTex等、ありとあらゆるパッケージを要求されるのさ。依存地獄は、juliaでも健在だな。地獄はHaskellだけかと思っていたのにね。

方針転換して、Gnuplotを組み込んでみる事にする。上手くいったら、遅いi386なマシンにも 適用してあげる事にする。

julia> using PackageCompiler
julia> compile_incremental(:Gnuplot)
  :
[ Info: used 358 out of 358 precompile statements
┌ Info: activating new environment at ~/.julia/packages/PackageCompiler/CJQcs/packages/Project.toml.
└ @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Pkg/src/API.jl:524
  Updating registry at `~/.julia/registries/General`
  Updating git-repo `https://github.com/JuliaRegistries/General.git`
┌ Info:   Gnuplot version: 5.2.0
└ @ Gnuplot /home/sakae/.julia/packages/Gnuplot/GkEY3/src/Gnuplot.jl:111
Build shared library "/home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/sys.so":
  `cc -shared '-DJULIAC_PROGRAM_LIBNAME="/home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/sys.so"' -o /home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/sys.so -Wl,--whole-archive /home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/sys.a -Wl,--no-whole-archive -std=gnu99 -I/usr/local/julia/include/julia -DJULIA_ENABLE_THREADING=1 -fPIC -L/usr/local/julia/lib -Wl,--export-dynamic -Wl,-rpath,/usr/local/julia/lib -Wl,-rpath,/usr/local/julia/lib/julia -ljulia -m64 -O3`
("/home/sakae/.julia/packages/PackageCompiler/CJQcs/sysimg/sys.so", "/usr/local/julia/lib/julia/sys.so")

組み込むに先立ち、Gnuplotのテストが行われちゃんと動くか確認の後、組み込み用の環境が用意される。そして、コンパイルと、新たなsys.soファイルが作成される。

sys.soってのは、julia語で書かれた(Core,Base,stdlib,そしてGnuplot.jl)やつを、ネイティブコードに落としたやつだ。

(base) cent:~$ cd .julia/packages/PackageCompiler/CJQcs/
(base) cent:CJQcs$ ls -ltr
total 32
-r--r--r--. 1 sakae sakae  1170 Aug  2 06:13 LICENSE.md
drwxrwxr-x. 2 sakae sakae   172 Aug  2 06:13 src/
-r--r--r--. 1 sakae sakae  7626 Aug  2 06:13 juliac.jl
drwxrwxr-x. 2 sakae sakae    54 Aug  2 06:13 examples/
-r--r--r--. 1 sakae sakae 14644 Aug  2 06:13 README.md
-r--r--r--. 1 sakae sakae  1027 Aug  2 06:13 Project.toml
drwxrwxr-x. 4 sakae sakae    98 Aug  2 06:13 test/
drwxrwxr-x. 2 sakae sakae    54 Aug  2 06:13 deps/
drwxrwxr-x. 4 sakae sakae   133 Aug  5 05:31 packages/
drwxrwxr-x. 2 sakae sakae    58 Aug  5 05:35 sysimg/
(base) cent:CJQcs$ ls packages/
Gnuplot/       Plots/        incremental_precompile.jl
Manifest.toml  Project.toml  precompile_tmp.jl
(base) cent:CJQcs$ ls sysimg/
run_julia_code.jl  sys.a  sys.so*

作業は、PackageCompiler内のpackagesとsysimgが使われる。これらは作業が済めば不要なんで、消してもかまわない。

(base) cent:sysimg$ sudo cp sysimg/sys.so /usr/local/julia/lib/julia/sysGP.so

出来上がったほやほやのsys.soをsysGP.soって名前で、既存の場所に置いておく。

(base) cent:~$ cd /usr/local/julia/
(base) cent:julia$ ls -l lib/julia/sys*
-rwxr-xr-x. 1 1337 1337 162148664 May 16 14:44 lib/julia/sys.so*
-rwxr-xr-x. 1 root root 160067064 Aug  5 06:14 lib/julia/sysGP.so*

Gnuplotを組み込んだんだから、既存の物より大きくなると思うんだけど、何故か小さくなってるお。まさか真夏の怪談じゃなかろうね。

(base) cent:julia$ cat bin/pj
#!/bin/sh
julia -J /usr/local/julia/lib/julia/sysGP.so $@

新しいやつで起動するためのラッパーを書いた。$@は、引数を展開するための常套手段。

(base) cent:~$ pj -q
[ Info:   Gnuplot version: 5.2.0
julia> @time using Gnuplot
  0.000384 seconds (328 allocations: 17.875 KiB)

julia> @time @gp 1:100
[ Info: Creating session default...
[ Info:   Gnuplot version: 5.2.0
GNUPLOT (default) -> wxt
GNUPLOT (default) -> 0 enhanced
  0.272682 seconds (383.79 k allocations: 20.065 MiB)

julia> @time @gp 1:50 "w l"
  0.219728 seconds (294.46 k allocations: 14.799 MiB, 2.07% gc time)

おお、ストレス無く動くな。しめしめ。

at i386

i386なdebian機でも試してみる。

julia> versioninfo()
Julia Version 1.1.1
Commit 55e36cc308 (2019-05-16 04:10 UTC)
Platform Info:
  OS: Linux (i686-pc-linux-gnu)
  CPU: Intel(R) Celeron(R) CPU          900  @ 2.20GHz

  WORD_SIZE: 32
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, penryn)

やっぱり32Bit機なのね。で、最初は普通な環境

julia> @time using Gnuplot
[ Info:   Gnuplot version: 5.2.0
  5.244270 seconds (2.29 M allocations: 78.880 MiB, 15.37% gc time)

julia> @time using Gnuplot
  2.791364 seconds (1.37 M allocations: 42.408 MiB, 1.79% gc time)

julia> @time using Gnuplot
  0.000182 seconds (289 allocations: 11.336 KiB)

julia> @time @gp 1:10
[ Info: Creating session default...
[ Info:   Gnuplot version: 5.2.0
GNUPLOT (default) -> wxt
GNUPLOT (default) -> 0 enhanced
  3.446899 seconds (3.48 M allocations: 120.369 MiB, 8.58% gc time)

julia> @time @gp 1:10
  0.000209 seconds (117 allocations: 3.191 KiB)

2段階でスピードが速くなるって、どゆ事? usingもコンパイルの類が動いてる?

今度は、Gnuplotをブレンドした環境

debian:~$ pj -q
[ Info:   Gnuplot version: 5.2.0
julia> @time using Gnuplot
  0.014986 seconds (328 allocations: 12.969 KiB)

julia> @time using Gnuplot
  0.000214 seconds (325 allocations: 12.781 KiB)

julia> @time @gp 1:10
[ Info: Creating session default...
[ Info:   Gnuplot version: 5.2.0
GNUPLOT (default) -> wxt
GNUPLOT (default) -> 0 enhanced
  0.581988 seconds (383.15 k allocations: 14.190 MiB, 2.04% gc time)

julia> @time @gp 1:10
  0.000204 seconds (116 allocations: 2.988 KiB)

これぐらいなら、遅い石でも意志を持って使えるな。

こちらは、真夏の怪談話はありません。

debian:julia$ ls -l sys*
-rwxr-xr-x 1 root root 129196272 Aug  5 16:26 sysGnuplot.so*
-rwxr-xr-x 1 1337 1337 124228184 May 16 15:03 sys.so*

でも、Gnuplotのブレンドで5M近く増えてるって、そんなに大きいやつなのかな。外のgnuplotとの間にpipeを施設するだけなんだろうに。