大雪だった。 まあそんなにつもらんだろうと思ったら、朝方見たら既に道路が白くなっており、寒いので二度寝して起きたらもう一面真っ白だった。 しかも夜まで一日中降ってたし。日曜にはやたらとあったかくなって融けてきてたけど、しばらくは残りそうだ。
土日だったから良かったものの平日だったら大変なことになってたね。平日だったら意気揚々と休んで阿鼻叫喚な状況を見てニヤニヤできてただろうに残念だ。
PC組み換えてWindows8.1にしてから、そういやタブレット(って紛らわしいな。ペンタブレットのことだ)のドライバ入れてないと気付いたので落としにいったら。
Intuos3のドライバを落とそうとするとOS選択画面が出るがWindows8が選択肢に出てこない。……いや、WacomがWindows8対応してないとかありえないだろ。と、Windows8対応状況を見に行くとIntuos3はWindows7までの対応だと。あわわ。
ペンタブなんて世代毎でそんなに通信仕様が変わってるわけでもないだろうし、Windows7から8なんてそんなに変わらんし(と思ったがペンやタッチ周りは結構変わったりしてるのだろうか?)、いつまでも動くもんだと思ってたがダメなのか! まあいいつまでもサポートできませんよとか、そろそろ新しいの買ってもらえないと困りますよとかそんな話なのかもしれないが、HW的にはまだまだ普通に動くのにもったいないなぁ……。 そんなにしょちゅうは使ってないからなおさらだ。
ワイヤレスのやつとかタッチもできるやつがちょっと欲しいかもと思ってたから買い時なのかもしれないが、調べてみるとそれなりの出費になるなぁ。 ペンタブ無いと困るかというとすぐ困るわけではないので、値段調べたりしてしばらく考えるか。
その後ちょっと気になってIntuos3のWindows7用のドライバが使えないか試そうとしたら、Windows Vista/7用ドライバのリリースノートにWindows 8.1対応しましたという謎の文言が入っていて、インスコしたら普通に使えた。Windows 8.1対応したという新機能が入るWindows Vista/7用のドライバとはいったい。
IronRubyでゲーム書いるんですけど(全然進んでない)、どうもやたらと遅いんですよね……。
どこが重いのか計ってみようとしたら、そもそも時間計測が遅い。なんでだよ!
時間計測はこんなコードでタイムスタンプを取ってそれの差分を計算して行ってるわけですが……
@@freq = 1000000.0/System::Diagnostics::Stopwatch.frequency
def timestamp
System::Diagnostics::Stopwatch.get_timestamp*@@freq
end
こいつが既に遅い。System::Dignostics::Stopwatch
は.NETのクラスね。普通にTime.now使わないのは少なくともWindowsだとよくても1ms、普通は10ms単位くらいの精度しか出ないためです。
ぱっと見はおかしいところないのでしばらく悩んでいたんだが、System::Dignostics::Stopwatch
が遅いことに気付いた。System
やSystem::Diagnostics
はRubyのモジュールではなく.NETの名前空間だ。IronRubyはそれをあたかもRubyのモジュールのように見せかけてはいるがあくまでも別物で、System::Dignostics::Stopwatch
と書くと毎度延々と名前空間やらクラスやらを探しにいっていたようだ。そりゃおせぇ。まあ実装までは見てないから毎度じゃないかもしれないが、キャッシュされてたとしてもあんまり効いてもなかったようだ。
じゃあということで
Stopwatch = System::Diagnostics::Stopwatch
@@freq = 1000000.0/Stopwatch.frequency
def timestamp
Stopwatch.get_timestamp*@@freq
end
としたらだいぶ速くなった。よかったよかった。
しかしまだちょっと時間食ってる気がして謎だなぁ。なんとなく気になるところはクラス変数だろうか。 クラス変数が実は遅いんじゃないかという気もしたので、変数のアクセス(読み出し)速度を調べてみた。するとなんと驚きの結果が!
IronRubyでの変数読み出し速度比較。速い順
ローカル変数>Structメンバ>>インスタンス変数≒Hashエントリ>>クラス変数
こんな結果でした(IronRuby 1.1.3)。計測したスクリプトが諸事情により無くなってしまったので数字はないです。 ローカル変数が速いのはわかるけどStructメンバの異常な速さは何これ。ていうかインスタンス変数遅すぎじゃない?
JRuby 1.7.4くらいでも計ってみました。ちょっと古い
JRubyでの変数読み出し速度比較。速い順
ローカル変数>インスタンス変数>>Hashエントリ>>Structメンバ>>クラス変数
具体的な数字が書けてないけど、IronRubyはなんだったんかという程インスタンス変数めちゃくちゃ速い。 一方Structメンバがなんでこんなにっていう程遅くなってる。どこに遅くなる要素があるんだ?
IronRubyのインスタンス変数の遅さとStructメンバの異常な速度をソースを見て調べてみると、まずインスタンス変数は順当にDictionary<string,object>
で実装されてた。順当だけどもうちょっと最適化の余地はありそうですね。キーがstringって……。
ついでにHashも調べてみるとこいつはもうまんまDictionary<object,object>
だった。順当ですな。
インスタンス変数とHashの速度がだいたい同じなのはこういうことか。Dictionaryは思ったより遅いんだなぁ。
Structの実装を調べてみると、こいつは中身がobjectの配列だった。アクセス用のメソッドもクラス作ったときに式木で定義されるのでアクセスも速そう。 作った時点でメンバが確定するからこういう最適化が出来るんだね。
クラス変数が遅い理由は調べるの大変そうだったのでやってないんだけど、まあそんなに使う物じゃないのでループ内で使わないよう気をつければよかろう。
CRubyでも計りたかったんだけど、Time.now
では精度が出ないのでWindowsのパフォーマンスカウンタ相当の物を取るのに簡単な方法が思い付かなかったので保留した。ちなみにJRubyではjava.lang.System.nano_time
を使いました。
以上の結果から、タイムスタンプの取得は
def initialize
@stopwatch = System::Diagnostics::Stopwatch.new
@stopwatch.start
end
def timestamp
@stopwatch.elapsed.ticks / 10
end
にしました。
これでやっとどこが重いのか調べられる……って思ったが、文字描画が重いんじゃー! 画面にパフォーマンスカウンタを表示させようにも表示が重いんだよ。
文字描画が重いのはまあ分かってたんだけど、ちゃんと調べてみると実際描画する前のフォーマット時点で既に重い。 テキストを描画しようとすると、一文字毎に分解して文字情報取ってきてレイアウトするって作業をするわけだ。 レイアウトした情報はその場で描画しないで保持しておく。これだけの作業なのに300文字で9msもかかってることが発覚した。 文字毎に処理するって量多いけどこれ以上削減できないし、300文字ってそこまで多くもないだろ。 9msって短くも見えるけど、60fpsのゲームだったら1フレームは16msしかないわけで、文字のレイアウトだけで半分以上持ってかれたらゲームどころではない。
見てたら文字毎のループ内でインスタンス変数が結構使われてますな。 これをStructにまとめたら速くなるのかなーとやってみたら速くなった。3msくらい。 実行時間66%削減!速い!って300文字のレイアウトに3msかー。
よく考えたらStructにする必要なくてループの外でインスタンス変数をローカル変数におとせばいいだけじゃん。 それをやって他にループ内でのメソッド呼び出しなんかもできるだけローカル変数にキャッシュしてループ外に出したら1ms弱くらいまで削減できた。 やったー。
300文字のレイアウトだけに1msってふざけてんのかと言う程長いけど、たぶん許容範囲なので今のところは気にしないことにしよう。
次は描画側をなんとかしないとなぁ。たぶんこっちもインスタンス変数減らしたりすればちょっと速くはなるけど、そもそも一文字毎にDrawCall発行しちゃってるあたりがやばいからなぁ。
全部入り(?)バージョン管理ソフトであるfossilの1.28がちょっと前に出てたのに気付いたのでまた変更点を訳しておきます。
http://www.fossil-scm.org/download.html
2014-01-27 17:33:44 バージョン1.28です。このリリースでの主な変更点は以下の通り:
/reports
でイベント種別による絞り込みができるよう強化しました。
リポジトリをクローンした時に、URLで指定したユーザ名(があれば)をローカルな管理者ユーザ名のデフォルト値として使うようにしました。--dirsonly
, --emptydirs
, --allckouts
の各オプションを追加しました。-W|--width
オプションと--offset
オプションを追加しました。-n|--limit
オプションが他のコマンドと同様にエントリの数を指定するよう変更されました。タイムライン関係の機能は上限に達すると出力の末尾に”— ?? limit (??) reached —“を出力するようになりました。上限を無しにしたい場合は”-n 0”を指定してください。fossil clone
コマンドに--once
オプションを追加しました。クローン時に指定したURLやパスワードを保存しないようにします。fossil ui
が開いているリポジトリの”default user”を見るように変更しました。/ci_edit
ページでチェックイン毎に”hidden”タグを追加できるようにしました。--sha1sum
オプションと--integrate
オプションを追加しました。--whatif
オプションを追加しました。これは”–dry-run”と同じ動作をしますが、”fossil all”の--dry-run
と名前が衝突しないために追加されました。ファイル一覧はツリー表示がデフォルトになったというので喜んでみたんですけどなってるようには見えませんね……。 訳し間違えたかと思ったけどそうでもなさそうなんだが?
タイムラインの上限表示あたりが細々と変更入ってるのはうれしい。上限に達したのでやめましたという表示がないとわからんのよね。まあ普段Web UI使ってるんで関係ないですけども。