March 04, 2009自作行列ライブラリのGSL化
[Computer]
僕は車輪の再発明は大の得意(笑)で、『自作行列ライブラリ』などというものをこさえて使ってきました。しかしこの度、計算が怪しい(固有値分解で、対象が対角行列に近いと収束しないケースがある)や、計算速度をあげたい、という欲求に駆られましたので、表面では自作のライブラリを生かしつつ、裏側でごにょごにょして問題解決する、という方策をとってみることにしました。というと格好良く聞こえるかもしれませんが、実のところインターフェイスを変えてしまうと、今まで作成したプログラムのコードを全て変更しなければならず面倒くさいというのが本音です。 実はこの手の問題には今までチャレンジしたことがあります。というのもこの自作行列ライブラリをDSPに移植する際、高速化のために用意されたアセンブラルーチンに内部的に差し替えるということをしたことがあり、その際はC++言語の機能であるテンプレートの特殊化を使ってコードを差し替えました。 今回も同じ手法をとることにしますが、差し替え先のライブラリとしてGNU Scientific Library(GSL)を利用することにしました。行列演算のみならず、FFTや数値積分といった様々な算術アルゴリズムが用意されていること、OSを問わず使えること(Visual Studioでもコンパイル可能、Brian Gladmanさんが公開しているプロジェクトファイルを利用して構築可能)、Rubyへのポーティングがされていること(Ruby/GSL)、などが決め手になりました。行列についてはBlasのC版(CBlas)を基本にしているようですが、これを用途によって差し替えることによってさらにチューニングが可能であることも魅力です。 結果、できあがったのは元のmatrix.hに対するmatrix_gsl.h、complex.hに対するcomplex_gsl.h(チューニング途中であるため、今後も随時更新予定)です。テンプレートの特殊化によって、中身のアルゴリズムを入れ替えています。また、少しいいことがあってGSL自体はCのライブラリであるため、それ自体を扱おうとするとmalloc/freeをしっかりやる必要があるのですが、自作行列ライブラリについては参照カウンタを利用したフライウェイト・パターンになっているので、今回作成したライブラリを利用する限りはあまりメモリ管理を気にすることなく使えています。 アルゴリズムを実装することは理解も進んで僕にとっては楽しいのですが、一回つまり出すとなかなか前に進めないのが問題です。というわけで世の中の既存のツールをうまく活用できるようにもなりたいものです。 ※2009/3/31追加、メモリが一部あふれていたので修正版に差し替えました。 March 09, 2009C++でリフレクションもどき
[Computer]
物理法則に関係するプログラミングをしていると、変数に人間にわかる名前をつけておかないと大変な事態になります。特にその変数が配列であるときは悲劇で、インデックスが直打ちされている残念なコードを時たま見かけます。このようなコードはインデックスが少し違っただけで計算結果が発散してしまいデバックできなくなることは必至です。 前置きが長くなりましたが、今回はリフレクションの機能を持たないC++言語で、実行時にも名前からインデックスを引けるような簡単な記述方法を模索してみることにしました。解はいくつかあると思いますが、結果は以下のようになりました。 とりあえず使う分には49行目までを別のヘッダにでも定義しておき、本体には51行目~55行目の4行を書くだけで、1) コードに書いた名前で配列にアクセス、 2) 実行時に外部から取り込んだ名前から配列のインデックスを求め配列にアクセス の両方が実現されています。1) の機能はMAKE_ALIASマクロ内で展開される関数定義によっています。2) の方は少々複雑で、テンプレートの特殊化によって対応しています。内部的にリンクリストを作成することで表引きを可能にしました。 注目なのは、リンクリストを実現するためのテンプレートの特殊化方法です。テンプレートの特殊化を行うのは、通常グローバルスコープ(簡易的に言えばmain()関数と同じレベル)なので、あるクラスの中でテンプレートの特殊化をすることはあまり機会がないと思います。しかしながらそのような方針をとると、MAKE_ALIASマクロを2つのマクロ、すなわち、1)の機能を実現する関数(クラス内にある必要がある)を定義するマクロと 2)の機能を実現するためのテンプレート特殊化マクロ(方針に従うのならクラスの外)に分けなければならなくなります。重要なことなので同じ名前に関して2回定義してもいいのですが(笑)、重複は悪なので1つのマクロにまとめたいという結果が今回のコードです。こうしておくとさらにいいことがあって、クラスの中でこのMAKE_TABLEやMAKE_ALIASマクロを使っても変数定義が同じようにできます。 テクニックとしては、クラスの中でテンプレート特殊化を行うためダミー型(コードではTで表記)を利用した部分特殊化を使っています。実は部分特殊化を使わず、完全特殊化であってもM$系のコンパイラなら通ってしまうのですが、それは独自拡張だそうなので仕様に準拠して部分特殊化としました。『c++スレより「クラスの内側で定義したクラステンプレートを特殊化する」』がとても参考になりました。 なお今回コードを紹介するにあたって利用したCodepadはweb上でコードが実行できる優れものです。とても有用なwebサービスだと思います。 March 19, 2009RFPDFの高速化、StringIOを使う
[Computer]
RubyでPDFを生成したいと思い、RubyのPDFライブラリを物色していました。結果、プロジェクト管理ツールRedmineのプラグインとして開発されているRFPDFが、使いやすそう、かつ、日本語もある程度扱えるようだったので、使ってみることにしました。しかしながら速度が十分でなかったので、改造を施しパッチを作りました、というのが今回の話です。 生成しようとしていたPDFは上のようなものです。今度の5月に開催されるMake: Tokyo Meeting 03に何かだせたらいいなぁ、ということでネタ出しをしている段階なのですが、それの検証用としして作成していたものです。ビットマップを読み込んで、モザイク画像を生成するスクリプト bmp_tiler.rb (後半に無理やり高速化をかけている痕跡がありますが、笑)で生成しました。円を沢山描きまくるスクリプトです。 このPDFを一枚完成させるのに、当初、およそ2分くらいかかっていました。どう考えても時間が掛かり過ぎておかしいと思ったので、チューニングをしてみることにしました。まずはどこがボトルネックとなっているのか、プロファイルを取ってみました。 ruby -rprofile bmp_tiler.rb
このようにすると、何の関数が何回呼び出されて、どれだけ時間がかかっているか一覧で表示されます。実行してみた結果、String#+(文字列の連結)が最も時間がかかっており、10万回以上の呼び出しで120秒以上消費していることがわかりました。かなり以前ですが、Rubyをはじめた頃に、K上さんという方からRubyのString#+は特に遅いので、StringIO#writeを代替に使うといいよ、ということを教えてもらったので、それを実践することにします。 結果、RFPDFでStringIOを使用するようにしたパッチrfpdf_stringio.patchを公開します。これを使うことで、同じ条件下で実行時間を10秒程度にまで短縮することががきました。如何にString#+が遅いかが実感できています。 簡単にString#+とStringIO#writeの違いを体感したければ、以下のスクリプトを実行してみるといいと思います。ノートPC(Core Duo L2400 @ 1.66GHz)で実験したみたところ、100000回呼び出しでString#+が14.39秒、StringIO#writeが1.24秒でした。 ruby -rprofile -e "a = String::new; 100000.times{|i| a += 'hoge'}"
ruby -rprofile -e "require 'stringio'; a = StringIO::new; 100000.times{|i| a.write('hoge')}; a.string"
このような話はRubyに限らず広くある話で、文字列の連結なら、JavaだとStringの代わりにStringBufferを使いましょう(もしかしたら今は最適化のお陰で効果はないかも?、Javaは久しく触っていません)とか、C++だとstringの代わりにstrstreamを使いましょう、といったことが知られていると思います。RubyのString#+が遅いのは、推測なのですが、GCが絡んでいる?とか、中でハッシュ値を計算しなおしている?(同一内容のStringはインスタンスが一つでシングルトンになっているんじゃなかったっけ?)あたりではないかと思います。もし正確なことをご存知の方がいましたら、つっこみお待ちしています(ソース読め、という話ですが、笑)。 March 24, 2009Eclipseでgitプラグインの使い方
[Computer]
統合開発環境Eclipseを使って、gitで運用しているプロジェクトを扱っているのですが、gitプラグインの使い方がよくわからなかったので、一連の動作について試行錯誤した結果をメモとして残しておこうと思います。なおgitプラグインのインストールは、普段どおりUpdateサイトを利用して簡単に行うことができました。 ちょっと長くなりそうなので、続きをどうぞ。既存リモートリポジトリからクローンの作成、リモートリポジトリから更新があったかの確認、更新のローカルコミットとそれのリモートリポジトリへの反映についてまとめてあります。 続きを読む "Eclipseでgitプラグインの使い方" |
かれんだ~
最近のTrackback ダイナミックDNS 3domain.hk… @ 3年落ちのPCでまだまだがんばる日記 9X到着〜インプレ@ 艦船プラモとRCマイクロヘリが好き! USL-5P@ 谷岡のページ (PukiWiki/TrackBack 0.3) [mbed][猫カメラ]猫カメラつづき@ Embedded 脇見運転 [mbed][猫カメラ]mbed + 猫…@ Embedded 脇見運転 MT4 @ ダイナミックで動く画像リサイ…@ wed@ 私がAudionoではなくBlackfi…@ Blackfin空挺団::Blog 【Web】はぐれメタルできたよー@ I'm St'a'dying English ちっとも、作っていない@ 三D坊主 猫カメラ@ 脇見運転 To 『猫カメラ』 試作中 最近のこめんと いきなりのコメント申し訳ありません。
… by まろまろ先輩 @ GPD Pocket 内蔵USBハブ基板 音楽を読み取りする 説明して欲しいですby 榎本待子 @ iPodからPCに曲を転送 Arduino嫌いだわ。
あんなもの見…by Alice @ 僕がArduinoを使わないわけ やや遅い書き込みで失礼します。
別の機…by LOSスマホ @ Xiaomi Mi Max (Hydrogen) の MIUI8 FM Radio (stock) 日本バンド対応 >Bさま
確か当時、そこまで高くなかっ…by fenrir @ MKS Promenade-Ezy ケージ交換 お値段はおいくらでしたか?
私も曲げて…by Bさま @ MKS Promenade-Ezy ケージ交換 >forester3さん
お返事遅くな…by fenrir @ EZUSB Keilからsdccへ、EZUSB.lib等の移植 お世話になります。3年ほど前sdccの…by forester3 @ EZUSB Keilからsdccへ、EZUSB.lib等の移植 以下のものはどうですかねby て @ VBAで泣かないために >tomi9さん
コメント気づくのが遅…by fenrir @ TCM8240MD breakout (i2cで画像取得モジュール) 動作確認完了 りんく集 かてごり~一覧 Aero & Astro (100) Computer (189) Embedded System (308) Info (14) Mountain (43) Movable Type (28) Movie & Animation (20) Music (9) Photo (47) Site Management (46) Timely (135) Tips (68) あ~かいぶ 検索君
スポンサード リンク
最近の記事 HDL-AAX2 シャットダウンスクリプ…
曜日を求める(8bit範囲で) Assisted GPS (A-GPS)… HDL-AAX2の修理 ExcelでMarkdownの表を編集 Rubyで確率分布の性質を求めるgem Windowsのcygwin/MSYS2… RubyでGPS姿勢推定 RubyでGPS受信機 boost::math::distrib… E-MailRelay本体更新(ver … RinRuby (Ruby gem fo… RSpecでのexample間共用のイン… 夏休みの工作: ソースコード公開 夏休みの工作: タッチセンサ GPD Pocketに増設したストレージ… GPD Pocketにストレージ増設 GPD Pocket 内蔵USBハブ基板… GPD Pocket 内蔵USBハブ基板 久しぶりの基板作成 自転車用六角穴付き特注ナット Xiaomi Mi Max (Hydro… Xiaomi Redmi Note 3 … Super Sylphide 進捗状況(… Super Sylphide 進捗状況(… |