読者です 読者をやめる 読者になる 読者になる

non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

Windowsで公式のOCamlをいれて、utop動かすところまで出来た

おはようございます。GW初日は、奥さんが子供たちを連れたお台場の日本科学未来館に行って来てくれ、その間、自由時間を過ごすことができたkjunichiです。

TL;DR

エラーメッセージを読んで、それに対応する。

背景

.opamフォルダを消す

やり直すには、.opamフォルダをとりあえず消す。

Windows10だとCygwinの設定を手動でやる必要がある

インストーラーではCygwinのインストールをやってくれない。

Note: on Windows 8.1 and above, the OCaml installer will fail to launch Cygwin's setup.exe. In that case, launch it manually (it has been downloaded to your desktop).

と書かれていた、だから先走って入れたChocolatyのCygwinしかなかったのかw。

そんなわけで、自分はChocolateyで入れたCygwinで環境構築することにして、以下の作業を行った。

まずは、ChocolateyのCygwinのセットアッププログラム(C:\tools\cygwin\cygwinsetup.exe)を起動して、 ドキュメントに掲載されたCygwinのパッケージを入れる。

opam init前の作業

環境変数をいったん無効化

ほかにも、前回のインストール作業で設定されてるが、これらは面倒だから放置した。

unset OCAMLLIB
unset CAML_LD_LIBRARY_PATH
unset CAMLP4LIB

環境変数OCAMLLIBを設定する

このOCAMLLIBが曲者だったw

公式のドキュメントではsqlite3のビルドではWindows表記にしろと書いてあるが、 少なくともそれまでの作業では以下のようななんとなくUNIXスタイル?でないとダメ。

多分この設定がocamlfindコマンドに埋め込まれる模様。

export OCAMLLIB=C:/OCaml/lib

opam init実行

これまでの手順で、opam initはうまくいく。 もっとも、前回の記事の際もこれはうまくできていた。

再び、環境変数

source ~/.bashrc

して戻す。この際に、OCAMLLIBの設定も.bashrcに書いておいても 良いかも。

最初の難関

depext-cygwinportsのインストール これ、

という理由と思われるが、とにかくopam installできない。

出来ないが、一旦は

opam install depext-cygwinports

を実行する。これで、必要なファイルが展開された状態になる。

opamで展開されたconfigureを編集しても、次回のopam install時に 戻されてしまう。

なので、手動でやる。展開されているディレクトリに移り、opamファイルの記述を参考に

cd ~/.opam/system/build/depext-cygwinports.0.0.6/
vi configure # アーキテクチャのチェック箇所をコメントアウト
if [ "$mingw_arch" != "mingw64" ] && [ "$mingw_arch" != "mingw" ] ; then
    echo "unsupported mingw_arch: '$mingw_arch'" >&2
    #exit 2
fi
./configure && make all && make wrappers && make install

本来のopamインストールが何をやるのか分からないので、 以降の追加作業を行った。

depext-cygwin.confのコピー

mkdir ../etc/depext-cygwinports
cp depext-cygwinports.conf ../etc/depext-cygwinports

depext-cygwinports.confの修正

アーキテクチャの設定箇所が改行を修正しておく。

(*  your mingw-toolchain: mingw32 or mingw64 *)
mingw_arch = "mingw64"

pkg-config.exeの無効化

/usr/local/binに入れられたpkg-config.exeを無効にしておく

mv /usr/local/bin/pkg-config.exe /usr/local/bin/pkg-config.exe.bak

これで、たぶんdepext-cygwinportsが入ったことになる。

utopのインストール

今回の目標のutopのインストールで少しハマった。

lambda-term問題

公式のドキュメントにも別のパッケージを例に解決方法が出ていた。

rm ~/.opam/repo/default/packages/lambda-term/lambda-term.1.10.1/files/lambda-term.install

あれこれやって発見したが、lambda-termは1.11系はflexlinkが「-g」オプションに対応しておらず、 インストールできない。opam install utopでなく、直接lambda-tarm等を指定するとこれが原因で 上手くいかない。

まとめ

まぁ、エラーメッセージを読んでそれに対処すれば、UNIXの経験があれば、 何とかなるっぽい。

https://pbs.twimg.com/media/C-5hFLHXkAAUEtb.jpg:large

関連記事

10年前の記事

Juliaでaobenchを使って並列処理を試した その1

我が家は週末になるとセロハンテープがなくなります。主に次男がやたらと工作した車や剣などにベタベタ張るのが原因です。長男は無駄遣いすることはほとんどないようですが、大好きなスポーツカーをたくさんつくるので、消費量は多いです。kjunichiです。

背景

去年Juliaで並列処理が意外と簡単にできることがわかり、aobenchのjulia版を作り、

という記事を書いて、並列処理もその続きに書こうとはしていたものの、すっかり忘れていたのと、 昨年末自作PCをXeonの8コアにしたので、マルチコアの恩恵がより受けられる環境が身近になったのもあり記事にした。

簡単な並列化

単純にJuliaに用意されている並列処理のキーワードを追加して、 並列処理させる。

addprocsでプロセス数を設定する。

addprocs(4)

複数のプロセスから参照する変数に@everywhereキーワードをつける。

@everywhere hoge

非同期処理は@async、@syncキーワードで囲むことでJavaなどのjoin的な動きになる。

@sync begin
 @async remotecall_wait(p, render, fimg,img, WIDTH, HEIGHT, NSUBSAMPLES)
end

成果物

# original code:
# https://github.com/syoyo/aobench/blob/master/ao.c
addprocs(7)

@everywhere WIDTH        =512
@everywhere HEIGHT       =512
@everywhere NSUBSAMPLES  =2
@everywhere NAO_SAMPLES =8

@everywhere type Vec
    x::Float64
    y::Float64
    z::Float64
end

@everywhere type Isect
    t::Float64
    p::Vec
    n::Vec
    hit::Int64
end

@everywhere type Sphere
    center::Vec
    radius::Float64
end

@everywhere type Plane
    p::Vec
    n::Vec
end

@everywhere type Ray
    org::Vec
    dir::Vec
end

@everywhere function vdot(v0, v1)
    v0.x * v1.x + v0.y * v1.y + v0.z * v1.z
end

@everywhere function vcross(v0, v1)
    Vec(v0.y * v1.z - v0.z * v1.y,
               v0.z * v1.x - v0.x * v1.z,
                 v0.x * v1.y - v0.y * v1.x)
end

@everywhere function vnormalize(c)

    length = sqrt(vdot(c, c))

    if (abs(length) > 1.0e-17)
        c.x /= length
        c.y /= length
        c.z /= length
    end
end

@everywhere function ray_sphere_intersect(isect, ray, sphere)

    rs = Vec(ray.org.x - sphere.center.x,
                     ray.org.y - sphere.center.y,
                       ray.org.z - sphere.center.z)

    B = vdot(rs, ray.dir)
    C = vdot(rs, rs) - sphere.radius * sphere.radius
    D = B * B - C

    if (D > 0.0)
        t = -B - sqrt(D)

        if ((t > 0.0) && (t < isect.t))
            isect.t = t
            isect.hit = 1

            isect.p.x = ray.org.x + ray.dir.x * t
            isect.p.y = ray.org.y + ray.dir.y * t
            isect.p.z = ray.org.z + ray.dir.z * t

            isect.n.x = isect.p.x - sphere.center.x
            isect.n.y = isect.p.y - sphere.center.y
            isect.n.z = isect.p.z - sphere.center.z

            vnormalize(isect.n)
        end
    end
end

@everywhere function ray_plane_intersect(isect, ray, plane)

    d = -vdot(plane.p, plane.n)
    v = vdot(ray.dir, plane.n)

    if (abs(v) < 1.0e-17)
     return
    end

    t = -(vdot(ray.org, plane.n) + d) / v;

    if ((t > 0.0) && (t < isect.t))
        isect.t = t
        isect.hit = 1

        isect.p.x = ray.org.x + ray.dir.x * t
        isect.p.y = ray.org.y + ray.dir.y * t
        isect.p.z = ray.org.z + ray.dir.z * t

        isect.n = plane.n
    end
end

@everywhere function orthoBasis(basis, n)

    basis[3] = n
    basis[2].x = 0.0; basis[2].y = 0.0; basis[2].z = 0.0

    if (n.x < 0.6) && (n.x > -0.6)
        basis[2].x = 1.0
    elseif ((n.y < 0.6) && (n.y > -0.6))
        basis[2].y = 1.0
    elseif ((n.z < 0.6) && (n.z > -0.6))
        basis[2].z = 1.0
    else
        basis[2].x = 1.0
    end

    basis[1] = vcross(basis[2], basis[3])
    vnormalize(basis[1])

    basis[2] = vcross(basis[3], basis[1])
    vnormalize(basis[2])
end

@everywhere function drand48()
  rand()
end

@everywhere function ambient_occlusion(isect)

    ntheta = NAO_SAMPLES
    nphi   = NAO_SAMPLES
    eps = 0.0001;

    p =Vec(
             isect.p.x + eps * isect.n.x,
               isect.p.y + eps * isect.n.y,
                     isect.p.z + eps * isect.n.z)

    basis = [Vec(0.0,0.0,0.0),Vec(0.0,0.0,0.0),Vec(0.0,0.0,0.0)]
    orthoBasis(basis, isect.n)

    occlusion = 0.0

    for j = 0:ntheta-1
        for i = 0:nphi-1
            theta = sqrt(drand48())
            phi   = 2.0 * pi * drand48()

            x = cos(phi) * theta
            y = sin(phi) * theta
            z = sqrt(1.0 - theta * theta)

            # local . global
             rx = x * basis[1].x + y * basis[2].x + z * basis[3].x
             ry = x * basis[1].y + y * basis[2].y + z * basis[3].y
             rz = x * basis[1].z + y * basis[2].z + z * basis[3].z

            ray = Ray(p,Vec(rx,ry,rz))

            occIsect = Isect(1.0e+17,Vec(0.0,0.0,0.0),Vec(0.0,0.0,0.0),0)

            ray_sphere_intersect(occIsect, ray, spheres[1])
            ray_sphere_intersect(occIsect, ray, spheres[2])
            ray_sphere_intersect(occIsect, ray, spheres[3])
            ray_plane_intersect(occIsect, ray, plane)

            if occIsect.hit != 0;
             occlusion += 1.0
            end

        end
    end

    occlusion = (ntheta * nphi - occlusion) / Float64(ntheta * nphi)
    Vec(occlusion, occlusion, occlusion)
end

@everywhere function clamp(f::Float64)
  i = Int64(floor(f * 255.5))

  if (i < 0) i = 0;end
  if (i > 255) i = 255;end
  Cuchar(i);
end

@everywhere function render(fimg::SharedArray,img, w, h, nsubsamples)

  # find startx,starty
  idx = indexpids(fimg)
  @show idx
  if idx == 0
    startx = 0
    starty = 0
  else
    nchunks = length(procs(fimg))
    unitsize = round(Int, WIDTH*HEIGHT*3/nchunks)
    startpos = unitsize * (idx-1)
    @show nchunks, unitsize, startpos
    starty = floor(Int,startpos/(WIDTH*3))
    startx = startpos % WIDTH
  end
  @show startx, starty
  iidx = 0
  for y = starty:h-1
      for x = startx:w-1

          for v = 0:nsubsamples-1
              for u = 0:nsubsamples-1
                  px = (x + (u / Float64(nsubsamples)) - (w / 2.0)) / (w / 2.0);
                  py = -(y + (v / Float64(nsubsamples)) - (h / 2.0)) / (h / 2.0);

                  ray = Ray(Vec(0.0,0.0,0.0),Vec(px,py,-1.0))

                  vnormalize(ray.dir)

                  isect = Isect(1.0e+17,Vec(0.0,0.0,0.0),Vec(0.0,0.0,0.0),0)

                  ray_sphere_intersect(isect, ray, spheres[1]);
                  ray_sphere_intersect(isect, ray, spheres[2]);
                  ray_sphere_intersect(isect, ray, spheres[3]);
                  ray_plane_intersect(isect, ray, plane);

                  if isect.hit != 0
                      col = ambient_occlusion(isect);

                      fimg[3 * (y * w + x) + 1] += col.x;
                      fimg[3 * (y * w + x) + 2] += col.y;
                      fimg[3 * (y * w + x) + 3] += col.z;
                  end
              end
          end

          fimg[3 * (y * w + x) + 1] /= Float64(nsubsamples * nsubsamples);
          fimg[3 * (y * w + x) + 2] /= Float64(nsubsamples * nsubsamples);
          fimg[3 * (y * w + x) + 3] /= Float64(nsubsamples * nsubsamples);

          img[3 * (y * w + x) + 1] = clamp(fimg[3 *(y * w + x) + 1]);
          img[3 * (y * w + x) + 2] = clamp(fimg[3 *(y * w + x) + 2]);
          img[3 * (y * w + x) + 3] = clamp(fimg[3 *(y * w + x) + 3]);
          iidx+=3
          if(iidx>unitsize)
            return
          end
      end
  end
end

@everywhere function saveppm(fname,  w,  h, img)
    open(fname, "w") do fp
      write(fp, "P6\n");
      write(fp, "$w $h\n");
      write(fp, "255\n");
      write(fp, img)
    end
end

fimg = SharedArray(Float64,WIDTH * HEIGHT * 3);
zeros(fimg)

img = SharedArray(Cuchar,WIDTH * HEIGHT * 3)

# init_scene
@everywhere spheres =[
                Sphere(Vec(-2.0,0.0,-3.5),0.5),
              Sphere(Vec(-0.5,0.0,-3.0),0.5),
                Sphere(Vec(1.0,0.0,-2.2),0.5)]
@everywhere plane = Plane(Vec(0.0,-0.5,0.0),Vec(0.0,1.0,0.0))
@sync begin
  for p in procs(fimg)
    @async remotecall_wait(render,p, fimg,img, WIDTH, HEIGHT, NSUBSAMPLES)
  end
end
#render(fimg,img, WIDTH, HEIGHT, NSUBSAMPLES);

saveppm("ao.ppm", WIDTH, HEIGHT, img);

ほんとに速くなったのか

以下、ao.jlがシングルコア版、aop.jlがマルチプロセス版

C:\Users\kjw_j\Documents\work\julia
λ  Measure-Command {julia .\ao.jl}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 26
Milliseconds      : 479
Ticks             : 264795917
TotalDays         : 0.000306476755787037
TotalHours        : 0.00735544213888889
TotalMinutes      : 0.441326528333333
TotalSeconds      : 26.4795917
TotalMilliseconds : 26479.5917



C:\Users\kjw_j\Documents\work\julia
λ  Measure-Command {julia .\aop.jl}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 28
Milliseconds      : 862
Ticks             : 288628742
TotalDays         : 0.000334061043981481
TotalHours        : 0.00801746505555555
TotalMinutes      : 0.481047903333333
TotalSeconds      : 28.8628742
TotalMilliseconds : 28862.8742



C:\Users\kjw_j\Documents\work\julia
λ

マルチプロセス版の方がおそい!

考察

レンダリングした画像を全プロセス共有している領域に保持しているので、 計算結果を格納する際の排他制御のコストが高く、これが影響している模様。

関連記事

WindowsにOCaml入れようとしてocamlfindが動かない件

おはようございます。長男、次男とも無事に念願のトランスフォーマースピードチェンジシリーズのお目当てのキャラを手に入れました。kjunichiです。

公式のガイドに従ってやってるつもり。

しかし、

opam install depext-cygwinports

The following actions will be performed:
  - install config-file        1.2                              [required by depext-cygwinports]
  - install depext-cygwinports 0.0.6
===== 2 to install =====
Do you want to continue ? [Y/n]

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[config-file: ./configure C:\tools\cygwin\home\kjw_j\.opam\system] Command started
[config-file: make all] Command started
[ERROR] The compilation of config-file failed at "make all".
[config-file: ocamlfind remove] Command started

#=== ERROR while compiling config-file.1.2 ====================================#
# opam-version         1.3.0~dev2 (d4f7e01216dbb44af4e7cc6539a1b0afa9be9d2c)
# os                   win32
# command              bash -c make all
# path                 C:\tools\cygwin\home\kjw_j\.opam\system\build\config-file.1.2
# exit-code            2
# env-file             C:\tools\cygwin\home\kjw_j\.opam\system\build\config-file.1.2\config-file-4352-1872ec.env
# stdout-file          C:\tools\cygwin\home\kjw_j\.opam\system\build\config-file.1.2\config-file-4352-1872ec.out
# stderr-file          C:\tools\cygwin\home\kjw_j\.opam\system\build\config-file.1.2\config-file-4352-1872ec.err
### stdout ###
# /home/kjw_j/.opam/system/bin/ocamlfind ocamlc   -c config_file.mli
### stderr ###
# ocamlfind: C:OCamlib\ld.conf: No such file or directory
# make: *** [master.Makefile:45: config_file.cmi] エラー 2



=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The following actions were aborted
  - install depext-cygwinports 0.0.6
The following actions failed
  - build config-file 1.2
No changes have been performed

関連記事