type t (* void *)

ソフトウエアのこととか

きつね: キツネ村にいくぞ!!!

keenさんと話していたやつ

https://www.amazon.co.jp/%E3%81%8D%E3%81%A4%E3%81%AD%E3%81%95%E3%82%93%E3%81%A7%E3%82%82%E3%82%8F%E3%81%8B%E3%82%8BLLVM-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%82%AC%E3%82%A4%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E6%9F%8F%E6%9C%A8-%E9%A4%85%E5%AD%90/dp/4844334158/ref=sr_1_1?ie=UTF8&qid=1518180267&sr=8-1&keywords=LLVM

  • 直近の知り合い2ホイップくらいで旅行にいきたいですねーーー
  • 3月にやります、知り合いっぽい人は声かけるので是非ご参加下さい
  • 東北大学工学部の最終講義もある(3/9、外山先生が退官される)

やること

  • 日程決め(3/9から2泊にするか)
  • インターネットがあって小会議室が予約できるホテル(蔵王の近くで)
  • 好きそうな知り合いに声をかける

C++: 返り値として自分自身を返すメソッドにshared_ptrを使う

#include <vector>
#include <memory>
#include <utility>

class A {
public:
    int x;
    A(int x) : x(x) {}

    std::shared_ptr<A> f() {
        return std::shared_ptr<A>(this);
    }
};

int main() {
    auto a = std::shared_ptr<A>(new A(123));
    auto v = std::vector<std::shared_ptr<A>>();
    v.push_back(a->f());
    v.push_back(a->f());
    return v.size();
}

*** Error in./a.out': free(): invalid pointer: 0x00007ffcc80eb1cc ***`という素敵なメッセージとともに異常終了する。

教えていただいた方法で試してみる。

#include <vector>
#include <memory>
#include <utility>

class A : public std::enable_shared_from_this<A> {
public:
    int x;
    A(int x) : x(x) {}

    std::shared_ptr<A> f() {
        return shared_from_this();
    }
};

int main() {
    auto a = std::make_shared<A>(A(123));
    auto v = std::vector<std::shared_ptr<A>>();

    v.push_back(a->f());
    v.push_back(a->f());
    return v.size();
}

これは正常に終了する。めでたしめでたし。 ただしこれ、必ずthisがshared_ptrにより管理されていなければならず、そうでない場合にはエラーが発生するっぽいのでなかなかこわい。 例えば上の例ならばmainの中にauto b = new A(256); b->f();という行があったならば、

terminate called after throwing an instance of 'std::bad_weak_ptr'
what():  bad_weak_ptr

といってしんでしまう。

OCaml: 型変数の雑い話

これはMLアドベントカレンダーの1日目の記事です。 今年で3年目のアドベントカレンダーですが、あまり埋めるということは意識せず、MLユーザが記事を書いてワイワイするという目的でやっていければいいな、という感じです。

adventar.org

1日目なのでゆるくOCamlコンパイラの型周りの実装の話をしたいと思います。 最近あまり体調が良くなく、小ネタみたいな形です(すみません)。 どこかで喋った覚えもあるので聞いたことがある人がいたらすみません。


OCamlでは型変数は基本的に整数のidで表されています。 それにレベルという概念を導入して、どのネストのletで導入された型変数なのかをわかるようにしている、というのは以前書いたとおりです。

github.com

また型変数がgeneralizeされているかどうを表すためにも利用されていて、Btype.generic_level = 100000000と定義されています。まぁ常識的にこの深さのネストとかやらんやろということで再利用しているんだと思います。

気になるのは、型変数をidという形で整数で表してしまうと、idが衝突するのではないのかということです。例えばcmiファイルからロードする際に他のファイルから型をインポートするときに混じったりということが考えられます。

この手の情報は手軽に見ることができます。compiler-libsさまさまです。 utopかなにかで読み込んで、プリティープリントさせてみましょう。

// 前やったときはできたと思うんですが、なんか今はできませんでした。 // utopまわりで色々変わったのかもしれません、すみません

utop[0]> #require "compiler-libs";;
utop[1]> read_cmi

これを見ると、cmiの世界の中では型変数のidはマイナスの数になっていることがわかります。 これを自分たちの、いまコンパイルしようとしている世界にむけてidを差し替えます。それには型とかモジュールを表すデータ構造をあれそれ置き換えるためのモジュールSubstを利用します。

Subst.typexp: Subst.t -> Types.type_expr -> Types.type_exprは型を表すデータ構造をトラバースして、型変数を見つけたら置き換える関数です.

(* Similar to [Ctype.nondep_type_rec]. *)
let rec typexp s ty =
  let ty = repr ty in
  match ty.desc with
    Tvar _ | Tunivar _ as desc ->
      if s.for_saving || ty.id < 0 then
        let ty' =
          if s.for_saving then newpersty (norm desc)
          else newty2 ty.level desc
        in
        save_desc ty desc; ty.desc <- Tsubst ty'; ty'
      else ty
......

idが負であれば何やら怪しい方法でコピーしています。 for_savingは普通の場合ではfalseです。 ちなみにこのfor_savingというのはこの逆で、型変数のidを外に書き出したりするときにtrueになる変数です。newperstyidを負になるように置き換えます。

上のようなことが起きるのは、下の関数の中身くらいでです。

read_signature
  read_pers_struct
    acknowledge_pers_struct
      components_of_module'

ちなみにOcamlコンパイラの中身ではモジュールの並び順的にあとのモジュールに入っている関数を利用するために関数のrefみたいなものをたくさん作っており、'がつくものはその印です。

読んでみた感想なのですが、OCamlの型検査周りの実装というのは本当に複雑で、色々手に終えないです。型付けのためのデータ構造が効率のため一時的にしか現れないはずもの(Tlink, Tsubstなど)、といったものなどもありかなり複雑で、やはり関数型言語で書けば可読性が上がるなどといった話は嘘なんだなと強く確信がもてます(この手の話では関数型言語Haskell、それもGHCしか指さないという話もありますが)。 気づいたらocaml/typingの中に素敵なことにHACKING.adocというファイルができていました。

https://github.com/ocaml/ocaml/blob/trunk/typing/HACKING.adoc

これは本当に素晴らしいことで、突然開発者が交通事故にあっても大丈夫なようにOSSといえども実装をドキュメントとして残していく必要があります。 ソースコードに全て書いてあるなどと言うのは開発者の怠慢で後で読む人に一生懸命考古学させる、ドキュメントを書きましょう。。。

最後に今年の振り返りですが、今年のOCaml活動はコンパイラの同人誌をOCamlで書いたこと・ML勉強会を一応開催できたことは良かったです。 あまり最近OCamlをかけていないのですが、来年度はドンドンやっていきたいと思います!

nomaddo.booth.pm ml-lang.connpass.com

次はポケバさん@pocketberserkerさんです。

一般の話: 技術書典3で追記部分

技術書典3お疲れ様でした!
取り急ぎ、今回入稿した文の修正分についてお知らせします。

今回入稿したデータが間違っていたのか、印刷所が間違えたのか、私の追記部分が抜けて落ちております。 そのため最適化の部分だけPDFをアップロードしますので是非御覧ください。
電子書籍版では既にアップロード済みです。

nomaddo.booth.pm

www.dropbox.com

一般の話: 転職します

実は8月の頭が最終出社日で、8月で今の会社を退社します。
今週から東京に引っ越しています。
東京の北の方に御用の際はぜひお立ち寄りください。

今の会社では開発環境整備とか、製品の開発を行っていました。 色々苦労してcvsからgitにした話は名古屋のLTで話した感じです。 色々あって山奥もきつくなってきたのと、誘われた話が面白そうだったので転職することにしました。

次は9月からidein.jpにジョインします。
今いる人達はすごいエンジニアばかりですが、 コンパイラマンとしていい仕事が出来るように頑張ります。

プログラミング: Jetson TX2上でのarmclangの評価

この前魔が差してJetson TX2を買っていたので評価ができる~。
が、割りと意味分からない感じだったので誰か教えてくれ。

続きを読む

Jetson TX2: CUDA_sampleが動作するまで

こんなオタクデバイスを買ったのだけど、サンプルを動かすまで割とハマったのでメモしておく。
何一つ新しい情報はないけどまぁ他の人の時間が節約されて欲しい。。。。

Jetpackのインストー

Jetson TX2は買った状態で何かしらのUbuntuがはいっているけども、これを上書きしてALL in OneのパッケージであるJetpackを入れるのが正規の手段らしい。

developer.nvidia.com

最初困ったのはこのWEBページを見てもドキュメントがどこにあるのかわからないこと。
じつは「Release Noteはここだよ!」って書いてあるリンクの先がドキュメントになっている(???????????

基本的にインストールのガイダンスに従うだけでOKなのだけど、en設定のUbuntuをホストにして書き込みを行わないといけなかった。
JP設定のUbuntuでは中途半端な状態でインストールが終了してしまい、必要なツールが入っていない状態で異常終了してしまいます。

CUDAのサンプル実行

cuda-install-samples-8.0.shを実行するとサンプルプログラムが展開される。
なんとCUDAサンプルはそのままでは動かない(???????
霊感でエイヤと修正が必要。

commonの設定

下のリンクに書いてあるパッチを当てる。

https://devtalk.nvidia.com/default/topic/999381/jetpack-compiling-oceanfft-on-tx2/

libGL.soがなんか変

5_simulatorとかのサンプルを動かそうとするとリンクエラーでビルドできない。
主にlibGL周りの関数への未定義参照。

おそらく/usr/lib/aarchi64-linux-gnu/などにあるlibGL.soが腐っており、-L /usr/lib/aarch64-linux-gnu/tegraが必要。

おまけ:性能

nbody --benchmark --numbodies=256000で色々なGPUで性能を測った記事があったので同じサンプルプログラムを動作させてみた。

nvidia@tegra-ubuntu:~/sample/NVIDIA_CUDA-8.0_Samples/5_Simulations/nbody$ ./nbody --benchmark --numbodies=256000 --device=0
Run "nbody -benchmark [-numbodies=<numBodies>]" to measure performance.
        -fullscreen       (run n-body simulation in fullscreen mode)
        -fp64             (use double precision floating point values for simulation)
        -hostmem          (stores simulation data in host memory)
        -benchmark        (run benchmark to measure performance)
        -numbodies=<N>    (number of bodies (>= 1) to run in simulation)
        -device=<d>       (where d=0,1,2.... for the CUDA device to use)
        -numdevices=<i>   (where i=(number of CUDA devices > 0) to use for simulation)
        -compare          (compares simulation results running once on the default GPU and once on the CPU)
        -cpu              (run n-body simulation on the CPU)
        -tipsy=<file.bin> (load a tipsy model file for simulation)

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
gpuDeviceInit() CUDA Device [0]: "GP10B
> Compute 6.2 CUDA device: [GP10B]
number of bodies = 256000
256000 bodies, total time for 10 iterations: 36523.914 ms
= 17.943 billion interactions per second
= 358.866 single-precision GFLOP/s at 20 flops per interaction
nvidia@tegra-ubuntu:~/sample/NVIDIA_CUDA-8.0_Samples/5_Simulations/nbody$

qiita.com

まとめ

サンプル動作をテストしてから出荷してくれ。