「 2012年12月 」一覧

QNAPのNASにSubversionを入れてみる


QNAP TS439にApacheとSubversionをインストールする

sshでログインして、以下のコマンドを実行します

apacheではなにやら問題があるようで、
「mod_ext_filter.so」が読み込めないと意味のエラーが出る。
そのためこのモジュールをロードしている部分を httpd.conf から見つけてコメントアウトする。

下記コマンドで設定ファイルを開く

というようにサーバー名とポート番号の部分を編集する。

これからWebインターフェースでapacheを動かすユーザーとリポジトリフォルダの作成を行う。

1. ユーザー nobody を作成する.
2. 共有フォルダ repos_svn を作成する。nobodyのこのフォルダへのアクセス権を読み書き可にしておく。

ここまで出来たら、一度Apacheを起動して、動作の確認をしておく。

サーバーのアドレスとポートをブラウザで開いて、”It Works!”と表示されれば正常に動いている。

SVNの設定を行う。
設定ファイルを開き、下記のように編集する。

ここでは適当にSVNリポジトリを作成して、動作テストを行ってみる。
下記のコマンドを実行して、テスト用リポジトリを作成する。
リポジトリはhttp経由(WebDAV)で操作することを考えて、ディレクトリの所有権を変更している。

http://nasaddress:8010/repos_svn/ をブラウザで開いてみて、SVNでの表示形式を見ることが出来たらここまでの設定はうまく出来ている。


(OpenGLの)シェーダーバイナリ(GLSL Binary)


そういえばOpenGL 4.xでシェーダーのコンパイル結果をバイナリとして取得、ロードできる機能が追加されたのですが、当時ドライバがまだ対応していなくて見送っていました。ようやくこれについて調べてみることが出来たので、ここに書いておこうと思います。

まず、DirectXではシェーダーをコンパイルすると各ベンダで共通なシェーダーアセンブリ状態になります。このアセンブリ仕様はDirectXで決められているためにベンダ間で共通データとなります。

OpenGLのGLSLをコンパイルした結果はどうなるのか、これが気になるポイントでした。
DirectXのようにベンダー間で共通のデータとなるようなら便利に使えそうです。また同機能ということでOpenGLがDirectXに追いついた!とも見えるのではと思います。

そこで手持ちの環境で同じシェーダーをコンパイルしてバイナリデータを記録してみました。
ここで用いたのは下記のシェーダーです。

このシェーダーをNVIDIA(Geforce)のボードが刺さっている環境、AMD(RADEON)のボードが刺さっている環境でそれぞれ実行してみました。

この部分はファイル先頭なのですが、この時点からして既に全く違います。
AMDのほうではシェーダーのソースがほぼ見えるのに対し、NVIDIAのほうはそんな様子はありません。
ファイルを適当に中間部分まで表示させてみると以下のようになります。

AMDのほうはよくわからないデータが入っているようです。一方NVIDIAのほうではシェーダーアセンブリっぽいものが格納されているのがわかります。

AMDのほうはバイナリファイルにELFという単語が見えますし、GLSLソースコードが入っていたりとあまりシェーダーバイナリっぽくありません。NVIDIAのほうもNVIDIA拡張のGLのシェーダーアセンブリとして書かれているようで、両者全く違うというのが明らかになったかと思います。

DirectXもシェーダーバイナリはいわゆるアセンブラなのでこの点を考えるとNVIDIAのやっている方が近い感じだと思います。コンパイルされてアセンブリになっているという点が一緒というわけです。
一方でAMDのほうはソースが入っているだけのようにしか見えません。

これらの結果からやはりOpenGLのシェーダーバイナリは実行環境でのシェーダーコンパイル結果のキャッシュデータとしての価値しかなさそうです。実行環境が決まらないようなプログラムではGLSLソースコードを保持しておくしか手がなさそうです。


DirectXとOpenGLのテクスチャ圧縮対応付け


最近のDirectXはDXT1,DXT3,DXT5 という言い方をしなくなりました。
これらはそれぞれBC1, BC2, BC3 と呼ぶようです。
そして、このBCのナンバリングは続いて BC7まであります。

このBC4からBC7までOpenGLではどのような拡張が対応付くのかを調べてみました。

BC4 GL_EXT_texture_compression_latc
BC5 GL_EXT_texture_compression_rgtc
BC6,BC7 GL_EXT_texture_compression_bptc

このようになっているようです。
OpenGLの拡張の中身を見ても、決してBC*の文字列が出てこないので対応付けはちょっとわかりにくいですね。DXTの頃はGLのトークンとしてDXT1,3,5が現れてきたのでわかりやすかったのですが。


JavaScriptをC++からのスクリプトとして使う(クラス編)


C++で定義してあるクラスをJavaScript側で使いたいことがあります。今回はその説明をしてJavaScript編を終了にしたいと思います。

こんな感じのJavaScriptを実行させて、C++側にあるPointというクラスを扱うことを考えていきたいと思います。

C++でクラスの定義

このようなクラスを作り、下記に示すようにメンバ変数へのアクセスを許可するための関数を作ります。

続いて、Pointクラスを生成・破棄するための関数も用意しておきます。生成時には破棄の時にどの関数で処理させるかを指定させています。

ここまででクラスの準備は整ったので、JavaScriptエンジンにこれらの関数群を登録します。
前回の関数の登録のときの処理と割と似ています。

あとはこれを実行させてみることにします。

今までと違い、最後の方で V8::IdleNotification() を呼び出してみました。これを実行するとその時点で不要となっているデータを回収する動作が入ります(GCですね)
今回は、スクリプトに書いてあるようにfoo=nullを入れているので、少なくともこのデータが回収されることを期待しています。ためしにDispose関数にブレークポイントを設定してみると、IdleNotification実行後に呼び出されていることを確認出来るかと思います。

まとめ

これで、JavaScriptから関数やクラスを扱うことが出来るようになりました。組込スクリプトとしてのLuaで出来ていたことの多くはこれでJavaScriptでも務まりそうな気がします。速度やメモリの点はもしかすると及ばないのかもしれませんが、今の時代JavaScriptは結構多くの場所で使われているイメージがあり、使える人は多いと思っています。この点から組込スクリプトとしてJavaScriptも悪くないかと考えています。

使い勝手をよくするためにはJavaScript-C++のバインダのプログラムは用意しないと手軽感はありませんが、自分で作るちょっとした何かのツールではスクリプトとしてJavaScript対応を考えてみたいなと思っているところです。


JavaScriptをC++からのスクリプトとして使う


前回にV8エンジンのライブラリビルドまで終わっているとして、今回はそのライブラリを用いて自分のC++プログラムからJavaScriptを実行させている風にします。

VisualStudio 2010を開いて、コンソールアプリケーションを1つ準備します。
そして、V8エンジンをビルドしてある場所を設定しておきます。

  • 追加のインクルードディレクトリ: testV8/v8/include
  • 追加のライブラリディレクトリ: testV8/v8/build/Debug(もしくはRelease)/lib

また、プロジェクトのコード生成は”マルチスレッドデバッグ(/MD)”や”マルチスレッド(/MT)”を設定しておきます。ここはV8エンジンのビルドで設定されているものに合わせておくことが必要です。

そして、下記のような簡単なプログラムを入力してビルドしてみます。
(基本的には https://developers.google.com/v8/get_startedにあるHello Worldのプログラムです)

実行すると、コンソール出力に Hello,Worldが表示されます。

JavaScriptからC++側に用意した関数を呼び出す

次にJavaScriptからC++側に用意した関数を呼び出してみます。
C++で関数を作り、エンジンのObjectTemplateを生成し、そこに関数を登録します。
このObjectTemplateを受け継ぐ形でコンテキストを生成したら、スクリプトで関数を呼べるようになるようです。

ソースコードは以下のようになります。

ちなみに上記のPlusMethodでは文字列来たときにはまずいため、以下のように変更もしてみました。これだと文字列の時には結合して結果が出るようになります。

C++側からJavaScriptに定義してある関数を呼び出す

今度は今までの逆にJavaScript側で定義される関数をC++側から呼び出してみます。
手順としては、JavaScript側で定義されている関数のポインタみたいなものを取り出してきて、そこに引数を準備して呼び出す形で行います。


JavaScriptをC++からのスクリプトとして使う(準備)


JavaScriptをLuaやSquirrelのように使いたいな~とふと思い立ったので、ちょっとやってみようと思います。
今回はそのための前準備としてV8エンジンの準備の記事です。

V8の準備

JavaScriptの実行エンジンとして google の V8 を使用します。
まずは git://github.com/v8/v8.git からエンジン本体をダウンロードして、
ライブラリを作成することが必要です。

現在では、2012/12/08現在ではコードのライセンスは New BSD License(修正BSD)となっており、組み込んで使う用途について使いやすいかと思います。
(必要なことが、著作権表示&ライセンス文章&無保証を書いたテキスト同梱くらいなので)

V8エンジンのビルド

ソースコードをダウンロードして、VisualStudio2010でライブラリをビルドすることとします。

この手順がちょっと一手間かかります。VisualStudioのプロジェクトが付属せず、GYPによってプロジェクトファイルを作成するところからやらなければならないためです。
また、下記の依存ツール群は必ず示している場所に配置されるようにしなければなりません。そうしないと、VisualStudioでライブラリをビルドする際に妙なエラーに悩まされることになります。(実際にやりました…。)

下記で説明しますが、配置後はこのようになっている必要があります。

GYPを取得

GYPをSVNから取得して、v8/buildの中に配置されるようにします。
http://gyp.googlecode.com/svn/trunk

cygwinとPythonを取得

これらをSVNから取得して、v8/third_partyの中に配置されるようにします。

http://src.chromium.org/svn/trunk/deps/third_party/cygwin (リビジョン:66844)
http://src.chromium.org/svn/trunk/tools/third_party/python_26 (リビジョン:89111)

このGYPはGoogleが用意しているマルチ開発環境向けのプロジェクト作成ツールのようです。cmake的な物と言っていいと思います。
ただ個人的に残念だったのが、cygwinとpythonと必要とすることでしょうか。

コマンドプロンプトを開いて、v8の場所で以下のコマンドを実行します。

すると、この場所に all.slnというソリューションファイルが出来るので、これを用いてVisualStudioでビルドします。

問題が無ければ、ビルドが正常終了するはずです。
もしビルドでエラーが出るようであれば、third_partyのフォルダ配置が間違っていないかを確認してみてください。

実行テスト

サンプルとして付属している build/Release/shell.exe を用いて動作確認してみます。
実行させると入力受付状態になるので下記のような感じで例のHello,worldを入力してみます。

ライブラリ

生成されるライブラリは4つのようです。

  • preparse_lib
  • v8_base
  • v8_nosnapshot
  • v8_snapshot

shellサンプルをみると、リンクされているのは下記のもののようです。

  • v8_snapshot
  • v8_base

これをつかえば、自分のC++プログラムからJavaScriptを実行するとか出来るようになりそうです。


デバッグビルドの速度差(C vs C++)


VisualStudioを使用していて、デバッグビルドとリリースビルドでの速度差が顕著なのは最適化の有無の点からも言うまでも無いですが、同じようなコードをC vs C++で書いたときにも何か差があるように感じてならないです。

どうしてこのような差が出てくるか調べてみたところ、1つはテンプレートの展開に関する部分が大きいのではないか、と感じました。
たとえば、STLはテンプレートの塊ですが、これを使用するとDebug/Releaseで速度差が大きいですし、よくDebugでは使用にも耐えない、と聞きます。

templateの展開はインラインに行われるため早い、とは聞きますが、インライン展開するかどうかはコンパイラが決めることなので、デバッグビルド時には展開されないことが多いです。__forceinline を付けてもデバッグビルドではアセンブリを見ると展開されていなかったりします。
デバッグしていてステップインをテンプレートの関数やメンバにしたときにも潜れるということは、展開されておらず単なる関数呼び出しになっている証拠です。同じような処理だからとローカルに書いてあったコードをテンプレートによる関数実装に切り替えた途端に速度の低下が起こると思われます。
実際に手元で型変換のためのテンプレートをCスタイルのキャストを使うように変更しただけで速度は向上しました…。あまり良くはないのですが、実装をテンプレートからマクロへ変更することも有効のように思います。

(手元の環境では20万回ほどの実行される箇所で、Cスタイルにしたことで70msほど速度向上しました。)

最後に、STLのデバッグで速度を求めるときには、_SECURE_SCL と _HAS_ITERATOR_DEBUGGING を設定してビルドするという手もあります。これらはテンプレートの展開有無ではなく、範囲チェックやイテレータの所有権チェック、同期オブジェクト使用してのアクセスチェックとかの有効/無効を切り替える仕組みとなっています。
これの注意点としては、使用するプログラム全体でこの定義を揃えたビルドを行う必要があります。間違えるとビルド失敗や妙なエラーに悩まされるんじゃないでしょうか。

※ 完全に無効化は困るので速度に関してだけちょっと恩恵を受けたい、という場合には _SECURE_SCL は1にしておくのが良さそうです。速度ペナルティは、_HAS_ITERATOR_DEBUGGING のほうが影響しているとのこと。


Low fragmentation heap と Look aside list heap


前回の日記で、Low fragmentation heapによって同じReleaseビルドでも挙動が変わる!という話をしましたが、こんなことWindows XPの時にはなかったような気がして、ちょっと調べてみました。

まず、Windows7の環境では以前の日記と同じく、デバッガが繋がっているときにはLFH(Low fragmentation heap)がONにならず、単独実行させたときにはLFHがONになるという状況でした。一方XPでは、このような挙動が起こるのかを調べてみると、デバッガの接続状態にかかわらずヒープの種類は変化しませんでした。このときのヒープの種類は Look aside listヒープというもののようです。

OS ヒープ デバッガ
Windows7 Regular Heap デバッガ有
Windows7 LFH デバッガ無
WindowsXP Look aside list Heap デバッガ有
WindowsXP Look aside list Heap デバッガ無

確かWindowsXPであれば、LFHを有効にも出来たはずなので、そのコードを埋め込んで再度テストしてみます。

OS ヒープ デバッガ
WindowsXP Look aside list Heap デバッガ有
WindowsXP LFH デバッガ無

予想通り、デバッガが繋がっているとLFHが有効になりません・・・。
そこで、ヒープデバッグを無効化する _NO_DEBUG_HEAP を “1”にセットして再度チャレンジしてみます。
念のため、この環境変数をユーザー環境変数としてセットして、再起動を行っておきます。

この状態で再度、先ほどと同じように LFHをプログラム内部で有効にして、ヒープ状態を取得してみます。

OS ヒープ デバッガ
WindowsXP LFH デバッガ有
WindowsXP LFH デバッガ無

この結果を見ると、Windows XP(SP3)の環境でもデバッガ有りの状態で LFHを有効化することができました!

まとめ

以上のことをまとめると、常にLow-fragmentation heapを使いたい場合には、_NO_DEBUG_HEAP=1をセットしておいて、WindowsXPのときにはLFHを有効にするコードを実装しておく、ということで対処できるようです。
ただ、_NO_DEBUG_HEAPをセットしての運用はちょっと怖いので、開発時のマシン環境だけに限定したいですね。

おまけ

調べればすぐにわかりますが、Low fragmentation heapを有効にするコードを下記に記しておきます。
プログラム中で使用しているヒープ全てにおいてLFHのフラグをセットしてまわります。