<<前の5件次の5件>>

2014-6-20[金] 古PC に 軽いlinux を入れる

P3-800 世代に kona linux

あいかわらずタマに軽いOS(ディストリ)をインストールしたりして遊んでいる。
といっても たいていは virtualbox で動かすだけで、気になったのがあったときだけ P3-800MHz(i810)マシン(NetVista)でお試し。

最近のお気に入りは konalinux (v2.3 2014-06-03|12付近)。
OS側使用メモリ量が少なく抑えられて (black版で60MB前後, light版80MB前後)、 このクラスの古PCなのに まともな体感で操作できる。もちろんスペック相応の非力さを感じる面はあるけれど、最新のfirefox 入れて動くし使っていられるくらいにはいい感じ。 (軽いと言われるディストリでも、このスペックだと結構つらいモノが多いのよ)

軽さというならば TinyCore Linux(TinyCorePlus) のほうが頭一つ抜けてる感じだけど、 live-cd ベース オンメモリ運用前提で用意された範囲外のことをしようとすると手間が大きく(てか やれてない)、 その点 konalinux はHDDインスールのdebian環境で普通に apt-get 等できるので普段の延長で弄れて遊び甲斐あり。(いや、すぐ放置になるのだけど)

選ぶ kona のエディションは、メモリが384MB以上あれば full(-i386)版、256MB以上あれば light(lite)版、それ以下(でも192MBほしい) なら black版、 といったところだろうか。もう数世代後のスペックのマシンなら リッチなWMのエディション選ぶのも。

firefox を常用してるので、最終的には firefox (や Libre Office) が最初から入ってる full版を選択した。
iceweasel(というか古いリビジョンのfirefox) では使いたいアドオンがバージョン不一致で使えないことがあり(己の場合 All-in-One Sidebar)、black版 や light版 にfirefoxを野良インストールするのも面倒になったので結局(メニュー登録する方法調べるの億劫になり)。

※手持ちの NetVista は CD-drive かつ USB ブートのできない機種だったので、full版を入れるため一時的に 3口のIDEケーブルさしてDVD接続でしのいだが(電源はIDE->USB変換機器のものを流用)、CD|FDD で boot してから USB 起動するツールもあるようなので、なんとでもなりそう。

※ konalinux の配布物はバージョン名が同じ(2.3)まま ちょくちょく差し替わっているので、ダウンロード時期によって微妙に状況変わってることあり。

P2-400 世代

で、最近、親戚のとこの古いデスクトップPCが2台ほど巡り巡ってウチにやってきた。
電源いれてみれば 2台とも P2-400MHz(当然 slot) メモリ512MB前後 ... 15年前後前のスペックか?
そして、かなり、うるさい。

デスクトップでも静音電源が当たり前になって久しかったので... 昔は こんなうるさかったんだよなあ。 P3-800のNetVistaも音してるけど、一応静音タイプの代物で、十数年前のPCの常識で思えば静かな部類だったのだと再確認。

とりあえず HDD 換装して kona linux いれてみることにするが、80GB とか 120GB のHDDが認識されない... どうやら 32GB が最大の頃の代物らしい。10GBや30GBのHDDを繋ぐと認識(80,120GBでもジャンパで32GBに設定すれば使えたはず)。
ついでに騒音半減した感じ。
10,30GB-HDD は 静音が当たり前になりだした80,120GBの世代より音はしてるのだけど、6.4,8GBに比べれば結構静かになっていた模様。 すっかり忘れてる。

さて、肝心の kona linux だけど... もっさり。
win98 や win2k だとストレスのなくまともな体感で動くのだが... winアクセラレータが効くかどうかが大きいとは思うけれど、 さすがにこのスペックだと今どきのosやアプリはつらいわな。

と、 TinyCore Linux を動かすと win98やwin2k に匹敵する体感。さっすが。
ウィンドウ描画等UIレスポンスがよいのだけど、特にドックが滑らかに動くのが好印象の鍵なんだろうな。
(そうはいっても firefox を立ち上げるともっさりだったけど... それは win2k でも同様だろうで)

この世代については、下手なことせず win98/win2k 動かしてるほうが幸せ、でも GUI有 linux 動かしたいなら TinyCore Linux (TinyCorePlus) あたり...というのが己の結論。(自分でチューンできる技量のないものとしては)
win2k については こちらでおもしろそうな改造されてるので、気力あれば結構楽しめそうな状況あり(気力なし)。

てな具合に弄ってみたはいいけれど、スペック低いし騒音がつらいので、箱だけ残して中身(電源やM/B)は手持ちの余りパーツで置き換えよう ... と思ったのだが、 そこはメーカー製パソコン、一見汎用パーツのようで、そのままじゃあ換装できない要素が細々あり、結局、粗大ゴミになりそうな結末。
(収穫は 256MB DIMM を NetVistaに流用できたことか)




2013-9-22[日] PCKeyboardHack, KeyRemap4MacBook でのダイヤモンドカーソル(^QF 有)設定

バッテリー妊娠で放置してた macbook を復活中(バッテリー新調)。実質win7機としてしか使ってなかったのだけど今度こそmac(osx)をそれなりにさわろうかと(未だにmacよくわからん)。macbookは昔買ったlate 2008 な奴なので今更すぎますが新しいの買うまでには至らず。メモリ8G,ssd250G にしたのでまだなんとかなるかな、と。osx10.8 や win8 (win7入れ直してwin8upgrade) にしたはいいけど、まず、何より辛いのはキーボード。普段PCのテンキーレスキーボード(フルキーボードからテンキーだけ無くしたタイプ)常用、それがないならダイヤモンドカーソル(VZ系)配置必需、という自分でも少し困った生態ですが抜けられず、で、windows環境については自前ソフトで対処だけど mac 側はさて...

といっても mac 側の選択はやっぱり PCKeyboardHack, KeyRemap4MacBook のインストールがベストの模様。以前だって入れてましたが、その能力を発揮できていなかったようで(ソフトが発達した面もありそうだけど)、今回本気で設定してみたら、ダイヤモンドカーソルで^QFとかの 2 ストロークキーも使えて、かなり幸せでした。

ということで、以下、PCKeyboardHack, KeyRemap4MacBook の設定メモ.

※[追記] PCKeyboardHack は OS X 10.8 用以降は"Seil"に、KeyRemap4MacBook は OS X 10.9用以降は "Karabiner" に変名された模様.

※[追記] ( こっち ) で 窓使いの憂鬱 を使ってlinuxのダイヤモンドカーソル対応してみた

日本語キーボードを接続する場合

PCKeyboardHack で、For Japanege の 3つをチェックする(Enable NFER Key on PC keyboard. Enable XFER Key on PC keyboard, Enable KAATAKANA Key on PC keyboard).
これで、日本語キーボード(JP106系) をつなげた時に、スペースの並びの、無変換キー、変換キー、右COMMANDキーとして使える.

※ 無変換キー=IME off 変換キー=IME on なので 全角/半角キーは使うこと無く. 無理に全角/半角キーを使うことは考えず、むしろ、このほうが楽なので、windows 環境も 無変換を IME off にすることにした.

ダイヤモンドカーソル関係

実は KeyRemap4MacBook の Change Key の項目に Diamond Cursor 等各種変更があるので、好みのがあればそれを使うのが吉... だけど好みにあうのがなかったので自分で private.xml を書くことに.

やりたいことは、他の修飾キーによる動作を壊さずに、別途CapsLockキー同時押しでダイヤモンドカーソル移動等VZ系の基本操作すること(簡易に実現できる範囲のみ用意)

まず CapsLockキーを別のキーにするには PCKeyboardHack で、
CapsLock→Change Caps Lock にチェックをし、keycode を 右CTRLキー(62) にする.
(macbookでは 右CTRLキー がついてないので右CTRLを拡張キー扱いにしても影響少ないだろうと想定)

CapsLock については、これだけでなく、macos本来のキー設定でCapsLockを無効にする必要があるらしいのでそれも行う.
システム環境設定
→キーボード(アイコン)
→キーボード(タブ)
→修飾キー...
→キーボードを選択(変更したいキーボードを選ぶ)
→CapsLock キーを アクションなしに変更.
キーボードごとに設定できるので、必要なだけ設定する.
(※と書いたけど、新規追加したキーボードのCapsLock無効化忘れてても右CTRL化してるような…)

次に private.xml の作成.
作ってみた private.xml は これ.

設定方法は KeyRemap4MacBook の Misc & Uninstall(タブ) の Open private.xml を開けて、作ったものを上書き. Change Key(タブ) で ReloadXML して項目が現れたら必要な物をチェック.

作ってみた設定項目は、(以下ここでの ^ は右Ctrlの意)

Control_R Diamond Cursor ^E^X^S^D(上下左右) ^A^F(単語移動) ^R^C(頁移動) ^H(BS) ^G(DEL)
Control_R-Q ^QF(検索) ^QA(置換) ^QS(行頭) ^QD(行末) ^QR ^QC(ファイル先頭/末移動)
Control_R-T/V ^T(HOME) ^V(END) ※vzと違うけど楽にHOME/ENDしたく
Control_R-Z/W ^Z(undo) ^W(redo) ※ お試し. (vzだと1行ロールup/downだけど)
PC Application to FN Key WinキーボードのAppsキーをmacのFNキー扱いにする

生成するキーは標準のテキストエディタ準拠。
それなりにはなったのだけど、macでの(追記:編集キーを使うと) PageUp/PageDown Home/End 等のデフォルト動作が windows とは違う習慣になっていてちくちくとつらい(移動じゃなくてスクロールだけって何それ ... 行頭/行末/頁移動/ファイル先頭末移動、がことごとくwinと違ってた)
(追記:mac側は 頁移動=単語移動(OPTION+←→), OPTION+PageUp/PageDown, 行頭移動=COMMAND+←, 行末移動=COMMAND+→, ファイル先頭移動=COMMAND+HOME,ファイル末移動=COMMAND+END, 検索=COMMAND+F, 置換(アプリで違うけど標準のエディタでは)=OPTION+COMMAND+F)

作成にあたってはググっていろいろ参照…ちゃんと控えてなかった。まあ 2 ストロークキー以外は難しいことはなかったです。
2 ストロークキー関係はあまり情報なさそうで、一番役立ったのは こちら。(あと、VZ化されてるこちとか)
見よう見まね、やった結果は先の private.xml にありますが、ほんとうにこれでよいのかは自信なし。少なくともうちでは動いてるということで。

(追記: 2ストロークキーの設定では参考元にあるように config_only を使用。使わずオーソドックス?な方法だとたしかに "キーリピートが止まらない" 症状でした。ただ VK_CONFIG_SYNC_KEYDOWNUP_???? の使い方がよくわからずウマく設定できず、他の方の2ストロークキーの設定で使われてる VK_CONFIG_FORCE_ON/OFF を真似ねてみたところ希望の動作になりました。
あと、private.xmlの定義順で2ストローク用キー(Q)より先に1ストロークのキー(SDEXAFRC)が定義されていると2ストローク目のキー(SDEXAFRC)が1ストロークのキーとして処理をされてしまうようで、Qの定義を先に行なっています)

 AppsキーをFN にするのは一見 PCKeyboardHack で出来そうに思えたけど変更元となるAppsキーが一覧にないので、KeyRemap4MacBook で試してみたら意図通り動いてくれた、といった代物. (実際使うことがあるかというと ... 音量操作は便利かも、と使うようになった)(追記: Apps キーを使うには PCKeyboardHack でチェックマーク付けて有効にしておく必要あり) [追記] 使ってなかったら...いつの間にか機能しなくなっていた模様(OSバージョンアップ付近?)

※他の方の設定みてるとアプリケーション別とかの対応をされてたりして、結構高度なカスタマイズできるようですが、そこまでの気合はなく.

※ 編集キーの役割が違うので配置的にPCキーボードに拘る必要ないけれど、キータッチ感のために変える値打ちはある……が、テンキーレスキーボード、リアフォ 91U を繋ぐと右側の日本語キーボード配置な記号群が英語キーボード準拠に化ける。数字キー部分の記号は日本語準拠なので解せない。FILCOの茶軸やFujitsuの8769 を繋ぐと問題なく入力できたのでそちらを使えばいいのだけど、ちと敗北感あり。

※追記:そもそも己がダイヤモンドカーソル使うようになったキッカケが、むかーし FM-11(OS-9)とPC98(DOS)を使ってたからで、違う文化圏のマシンを触る限り二十ウン年前と問題はかわらんし解決方法もまた……なんですが、どうせ覚えるなら emacs やら vi(m) のほうが幸せだったかもな、です(今更その気はないけれど)。unix系osは生き続けemacs,vimユーザーも新規ユーザーがいるわけですが、 DOS(CP/M) 系の操作は Windows に殺されたので、未だにダイヤモンドカーソルに拘ってる人はおそらく40代付近以上……滅んだ操作体系で 小指痛くなることもあるけれど 左手のみですむ移動操作は(特に左利きには) それなりに幸せかもとは、言っておこう。

テキストエディタ物色中

さて、最低限キーボードを触る気になれるようになったけれど、問題は常用できそうなテキストエディタがあるか……まだ物色中。

決定打は今のところなし。Windowsではなんだかんだで秀丸(VisualStudio風キーカスタマイズ)に慣れすぎて……全角空白可視化したいしvz由来のスタック型カット&ペースト必需だし tsv,csv モードもなるべくほしくetc…(後半わがままなのは自覚. 正直エディタを使いこなせてるかというと?な奴だし)

NxWineで秀丸 は 思いの外動いてくれて良さげだったけれど、細かい不具合はあるにはあるし、キー操作でタブ切り替えると窓のフォーカス離れるのでいちいちマウス操作することになり今は諦め。(他の商用winエミュソフト使えばマシなんだろうか?)

性能的には sublime text 2/3 がよさそうだけどシュアウェア購入に見合うかは微妙. この金額払うのなら秀丸で使ってる機能がほぼほしいと思ってしまい…(スタック型カット&ペーストはありそ?なくてもスクリプトでなんとかなりそうな気配だけど tsv,csvモードは無さそ?。アウトライン表示とかはどうだろ). win,mac,linux 用があるのは魅力だけど(ああwin版はime入力窓が追従せず離れて表示されるのは嫌状態).

フリーのだと mi, TextMate2, komodo edit あたりか.

mi は日本人作者だしシンプルでとりあえず使う分にはよさげ……キーカスタマイズが部分的なのでもう少し設定できればと思う(理解が足りてないだけ?)

komodo edit はIDE的要素つよくてテキストエディタとしてはちょっと重め、だけどこれもオープンソースだし win/mac/linuxあるのは魅力か.

TextMate2 は元々商用でそこそこ評判がよかったものがオープンソース化したものらしく高機能、だけどごちゃごちゃしてる感じ、でも日本語の解説頁はままありそう……あ今ググってこれみたらデフォルトでスタック型カット&ペーストできた。これは俄然興味わいてきた

……もうしばらく右往左往してます。




2013-6-16[日]

前回の影響もあって、windowsで動くCコンパイラの機能を比較した頁、

  C言語機能の比較

を書いてみた。ざっくり kr,c90,c99,c11 およびvc・gcc拡張の機能を試してる。
C++目的で初めてC部分だけで挫折したちょっと情けないものだけれど、一応 c/c++互換機能と非互換機能をわけてみたりしてるので C++ 的にも意味はあると思う。




2013-5-26[日] c++03コンパイラの機能実装の比較

昔 ow や dmc のc++の(文法)実装状態をチェックしてる表をみたことあったなあ、と探してみれば、すぐみつかる.

http://cmeerw.org/prog/freecpp/

最終更新が2006で、それ以前のコンパイラの比較だけれど、チェックプログラムのソースが公開されていたので、ow 含むそれらよりも新しい(ヴァージョンの)コンパイラで試してみた。

もとより網羅されてるわけでないし今時のc++11世代のコンパイラの比較としては不十分だけど(SFINAEのチェックもなさげ)、owやdmcが以前よりよくなっているかを見る分には、と。

dmc 8.56ow 1.94.7.1 tdmclang3.1 (+mingw462)vc8vc9vc11bcc 5.5.1
1digraphpassfail[c]passpassfail[c]fail[c]fail[c]fail[c]
2alternative tokenspasspasspasspassfail[c]fail[c]fail[c]fail[c]
3new style castspasspasspassfail[c] / 実質passpasspasspasspass
4boolpasspasspasspasspasspasspasspass
5bool conditionpasspasspasspasspasspasspasspass
6mutablepasspasspasspasspasspasspasspass
7explicitpasspasspasspasspasspasspasspass
8typenamepasspasspasspasspasspasspasspass
9covariant returnpasspasspasspasspasspasspasspass
10arrow operator returnpasspasspasspasspasspasspassfail[c]
11overload enumpasspasspasspassfail[c]fail[c]fail[c]pass
12nested class fwd declpasspasspasspasspasspasspasspass
13friend namespace classpasspasspasspasspasspasspasspass
14class name injectionpasspasspasspasspasspasspassfail[c]
15friend name injectionfail[e]passpasspasspasspasspassfail[e]
16static const intpasspasspasspasspasspasspasspass
17delete constpasspasspasspasspasspasspasspass
18return voidpasspasspasspasspasspasspasspass
19new scopingpasspasspasspasspasspasspasspass
20if stmt condpasspasspasspasspasspasspasspass
21switch stmt condpasspasspasspasspasspasspasspass
22while stmt condpasspasspasspasspasspasspassfail[c]
23for stmt condpasspasspasspassfail[c]fail[c]fail[c]fail[c]
24defarg scopefail[c]fail[c]passpasspasspasspassfail[c]
25namespace enumpasspasspasspasspasspasspasspass
26namespace templatepasspasspasspasspasspasspasspass
27namespace template funcpasspasspasspasspasspasspasspass
28using namespace templatepasspasspasspasspasspasspasspass
29template non typepasspasspasspasspasspasspasspass
30explicit template instantiationpasspasspasspasspasspasspasspass
31template default allpasspasspasspasspasspasspasspass
32template default dependent argpasspasspasspasspasspasspasspass
33template template argpassfail[c]passpasspasspasspasspass
34template function explicitpasspasspasspasspasspasspasspass
35new template specializationpasspasspasspasspasspasspasspass
36partial template specializationpasspasspasspasspasspasspasspass
37partial ordering class templatespasspasspasspasspasspasspasspass
38member template classpassfail[c]passpasspasspasspasspass
39member template functionpassfail[c]passpasspasspasspasspass
40bad allocfail[e]passpasspasspasspasspasspass
41bad typeidfail[e]passpasspasspasspasspasspass
42throwing destructorpasspasspasspass (c++11fail[e])passpasspasspass
43koenig lookuppassfail[c]passpasspasspasspasspass
44two phase lookuppasspasspasspassfail[e]fail[e]fail[e]fail[e]
45empty base optpasspasspasspasspasspasspassfail[e]
46return value optpasspasspasspasspasspasspassfail[e]
47static assertionspassfail[c]passpassfail[c]fail[c]passfail[c]
48right angle bracketsfail[e]passpasspasspasspasspassfail[e]
49func predefinedpasspasspasspassfail[c]fail[c]fail[c]fail[c]
50hex float literalpassfail[c]passpassfail[c]fail[c]fail[c]fail[c]
51long longpasspasspasspasspasspasspassfail[c]
52restrictfail[c]fail[c]fail[c]fail[c]fail[c]fail[c]fail[c]fail[c]
53variable arraypassfail[c]passpassfail[c]fail[c]fail[c]fail[c]
54dynamic sizeofpassfail[c]passpassfail[c]fail[c]fail[c]fail[c]
55empty macro argumentpasspasspasspasspasspasspasspass
56enum trailing commapasspasspasspasspasspasspasspass
57flexible array memberpasspasspasspasspasspasspasspass
58compound literalfail[c]fail[c]passpassfail[c]fail[c]fail[c]fail[c]


補足

  • いずれもwin用32bit版コンパイラ. win8でコンパイル&実行.
  • fallにつけてる[c]はコンパイル出来なかった場合、[e]は実行結果で0以外を返した場合、を表してる.
  • 4.7.1tdm は mingw 4.7.1 tdm版.
  • clang v3.1 はllvm公式のmingw用バイナリを、本家 mingw g++4.6.2 の環境に上書きしたもの。
  • 元表にあるow1.6やdmc8.4.5は試していない(インストールしてない)ので元表をみてください.
  • vc8は元表にもあるけれど return void の結果が違ってる.
  • 47,48のみ必要ならば c++11 をコンパイルするオプションをつけている.(他はつけていない. 実はclangの不具合回避)


結果に fail があるチェックについて

  • 1 digraph: 交代記号( '{' が'<:'等) が使えるか.
  • 2 alternative tokens: and や and_eq のような記号の交代予約語が使えるか. ※ iso646.h(ciso646) で同様のものが#define定義されてる
  • 3 new style casts: const_cast<T>(t)のようなc++からのキャストが使えるか。clang が fail になっているのは本題とは別の virtual void A::f(); の実体が定義されていないことによるものでソースを実体定義に修正すれば問題なくパス。(このエラーは clangの挙動でも問題無いと思うけど、他のコンパイラがコンパイルできていることが興味深いかも)
  • 10 arrow operator return: メンバーのoperator->()の返型がT*,T,T&でない場合にコンパイルできるか.
  • 11 overload enum: enum型を基本整数型とは別型として関数オーバーロードできるか?
  • 14 class name injection: クラス名インジェクションが機能してるか ※このソースだと B() : ns::A() {} でなく B::B() : A() {} になっているところ.
  • 15 friend name injection: friend名インジェクションが機能してるか ※class内friend 定義したものはクラス外(非friend)で定義されたものよりも名前検索の順位が低く、またそのことは引数のマッチよりも優先される...ってことかな。
  • 22 while stmt cond: while の条件式でローカル変数を定義できるか
  • 23 for stmt cond: for の条件式(2文目)でローカル変数を定義できるか
  • 24 defarg scope: デフォルト引数スコープの扱いに関するテスト. ow はメンバー関数のデフォルト引数は関数宣言側ならOKだが定義側だとNGのようで、また、関数内での外部関数宣言ではデフォルト引数が使えない模様。bcc5.5.1 はデフォルト引数の問題でなく static const 変数の扱いが定数でないためのfailで、static const int c=3;の代わりに struct B に先立ち enum {c=3}; を定義すれば ok.
  • 34 template template arg: template<template<class T> class T1> のような template template 引数を使えるか
  • 38 member template class: クラス・メンバーとしてclass テンプレートが使えるか. ※ow1.9 はクラス定義内では使えるが、クラス定義外でtemplateを2回使う記述はNG.
  • 39 member template function: クラス・メンバーとして関数 テンプレートが使えるか. ※ow1.9 はクラス定義内では使えるが、クラス定義外でtemplateを2回使う記述はNG.
  • 40 bad alloc: new が メモリー不足の時に bad alloc を投げるか. ※ dm 標準では行えてないが stlport のようにライブラリ実装で対処可能.
  • 41 bad typeid: Typeidの引数が不正だった場合 bad_typeid を投げるか.
  • 42 throwing destructor: デストラクタ中に例外を投げることができるか. ※ clang++ 3.1 では通常は問題ないが -std=c++11 をつけでコンパイルすると実行時にハングした.
  • 43 koenig lookup: koenig lookup(ADL) が機能してるか. (関数呼出で、その引数の型が定義されている namespace から関数名をみつけられるか)
  • 44 two phase lookup:スコープ違いで同名のある関数の呼出が正しく行われるか
  • 45 empty base opt: 継承元class(struct)にメンバー変数が無い時0バイトにオプティマイズするか
  • 46 return value opt: クラス変数を返す時、コピーを発生させないようオプティマイズするか (VCはオプティマイズ指定しないとコピーになる)
  • 47 static assertions:[c++11]: static_assert があるか
  • 48 right angle brackets:[c++11]: templateで閉じカッコ2つを 空白を入れずくっつけて >> と記述して大丈夫か
  • 49 func predefined:[c99, c++11]: 関数名文字列 __func__ が使えるか
  • 50 hex float literal:[c99, c++11]: 16進数浮動小数点表記が使えるか
  • 51 long long:[c99, c++11]: long long を使えるか ※ bcc5.5.1は __int64 ならある
  • 52 restrict:[c99]: restrict 指定が使えるか. ※ c++11には入らなかった機能.
  • 53 variable array:[c99]: 動的ローカル配列が使えるか. ※ c++14に入るかもらしい(?)
  • 54 dynamic sizeof:[c99]: 動的ローカル配列に対するsizeofが機能するか ※ c++14には入らない.(c++のsizeofはあくまでコンパイル時に決定できるモノのみ)
  • 55 empty macro argument:[c99]: 空のマクロ引数を許容するか ※ bcc はこのソースでは大丈夫だが、引数が1つの場合 NG
  • 58 compound literal:[c99, c++11]: (struct A){1, 2} のような構造体リテラル表記できるか.

bcc 5.5.1 を表に加えるんじゃなかった...面倒増えてしまった(いや本当はpassしてるのもひと通りみたほうがよいくらいだけど)
vc が overload enum、two phase lookup あたりを修正しないのは、互換性がらみなんでせうかね? (既存の巨大ソースだと意図せず依存してそうな場合もありえそうだし).




2013-5-21[火] open watcom v2

年始くらいに某2chスレで 年末に2.0でるかも(ソースはニューズグループ)、とか書かれていて、けれど、watcom のサイトのデイリービルドみてもちっとも進んでなさそうで、ほんとかしら、と首をかしげてたのですが、今日、検索しててみかけました。

https://github.com/open-watcom

どうやら open watcom v2 を非公式にフォークしてたらしい。 リポジトリ覗くと、24時間以内の更新とかあって、そこそこ活動してそうな雰囲気。 といってもスタッフ的にお二人の名が書かれていたのでこじんまりとしたものなんだろうけど。

v2 ってことは Version 2 todo list の内容を目指しているのでしょうかね。どうなんだろ。watcom c++ の実装自体は c で書かれていて結構大変そうにも思いますが... まあちょっと楽しみです。




2013-5-20[月] stlport 5.2.1 for dmc,Open Watcom

今更ながら(現実逃避がてら) stlport 5.2.1 を Open Watcom 1.9 や dmc 8.56 に対応してみてた。ow のほうはそれなりになった気もするが dm のほうはリンカのこともあっていまいちかも。(何か根本的に見逃しているような気もする)

前回 stlport いじってたのが3年前……時間立つのは速いなあ。5.2.1がrelease最新版のままで開発自体は進んでなくもないけれど、vcでさえ面倒臭そうだったのと、watcom への対応を思うと古いコンパイラへの対応が残っているほうが無難そうに思えて結局5.2.1。(追記: 最近の開発版のほうはどうもunix系でc++11対応のg++のみなのかも. vcはおろかmingwもだめそう)

面倒くさいといえば付属のbuild環境も面倒で無視した。手抜きでバッチでコンパイル。ow,dmc以外にコンパイル試したのは vc(7.1,9,11), mingw g++4.7.1tdm版(32bit/64bit), bcc5.5.1。(ああ mingw 64bit対応が一番マトモな作業かもしれない……動作確認不十分だけど)

作業の参考にと pointer_specialization.txt「コンフィグレーション マニュアル」 をいつものごとく翻訳サイトの訳を手直ししたりしてみたが……コンフィグは内容古くて実際には結構廃止されてたり追加されてたりするようで少し徒労感有り。

と、ま、モノは stlport521dmow2.zip(txt)
(追記5/31: clang3.1(+ming4.6.2) の設定を追加)




2013-5-19[日] optlink のコンパイル

仕事が一段落したので放置していた諸々に手をつけねば、だけど、忙しい最中の現実逃避の残滓を先に…とグダグダ。現実逃避で dmc や ow で遊んでたのですが、dmc ってc++としてはowよりよさげだけどリンク時にハングしたり-gでデバッグ付でまともに動かせなかったりと optlink がかなりネック。交代のリンカ探すもデバッグ機能対応してるやつなんてそうそうなく…で灯台下暗し。optlink 自体がオープンソース化されてたようで dm856c よりも新しいソースがコミットされてた。コンパイルして使うとハングとか -g の具合が改善されてる模様。(といっても -g付きでちょっと大きいリンクすると Error 168: >64K Global Types の刑なのは変わりませんが)

とりあえず、コンパイルメモ
  https://github.com/DigitalMars/optlink
より ソースを入手 (己はzipをダウンロード). また
  http://www.robpol86.com/index.php/ImageCFG
より imagecfg.exe というツールをダウンロード。

 コンパイルには dmc と vc(9) が必要。(express版 でいけるかは未確認)。 vc の nmake と ml(マクロアセンブラ) あたりを使っているよう。
 dmc は必ず ドライブのルートに
    \dm
としてインストールされていること.( \dm にインストールしていない場合は、 別途インストールするか、win7以降ならば mklink /d \dm \hoge\hage\dm 等でリンクするなりして)

dmcとvcのパスを通し(vcvars32.bat 実行後 set path=x:\dm\bin;%path% をするなり)、 imagecfg.exe をパスの通ったところに置いておく.(不精して dm\bin に掘り込んだ)

ダウンロードしたzip を \dm があるドライブの適当なフォルダに解凍。 (gitで取得のほうが普通か?). 一応 開発者と同じ状態にするならば
   \cbx
というフォルダを用意してそこに展開.

その中の
   build_optlink.bat
を実行(他のバッチは気にしない)、コンパイルに成功していれば
   optlinkc\os2link\objnt\link.exe

ができているので、dm\bin に上書きコピー。


追記 dmd 2.063 (及びそれに対応するdmc.zip)付属のlink.exeは2013/04 の修正が反映されたバージョンになったようで、わざわざコンパイルしなくてもよくなった。




2012-12-14[金] boost::container で俺俺アロケータ

これは C++ Advent Calender 2012 14日目 の記事です。

C++11やboostをまだロクに使っていない人間なので、雰囲気を掴むために boost1.52 の boost/container フォルダを一寸覗いてみました。 new,delete等メモリーアロケート のコストを無視できないターゲットを扱うことも多いので、俺俺アロケータを渡してみたいってのもあり。 C++11仕様でアロケータが今までより楽にかけるようだし、scoped_allocator_adaptor も何か使えそうですし.

※いまだvc9をおもに使ってるので(vc12も使いますが)、C++11の記述はさけてます.

boost::container

boost::container ですが、C++11で仕様拡張された vector,list,map,set,deque 等のコンテナの機能を C++03コンパイラでもなるべく使えるようにした互換コンテナ群+α です。 C++11 で増えたコンテナ(array, unorderd_map 等)については すでにboostに実装があるためか(?) boost::container には含まれていません。詳しいことは こちら とか他のサイトにあたってください。

将来的にどんどん変わっていく部分も多々あるでしょうが、とりあえず boost_1_52_0/boost/container/ フォルダで wc してみると、41ファイル 27613 行(detailフォルダ含)。 実際には container 外のboostヘッダをいろいろinclude しているので実質はもっと大きいです(map,set(tree)等は boost::intrusive のものを使っているようです)。 (ちなみに boost_1_52_0/boost/ では 8779ファイル 約172万行、やっぱりデカいです)

boost/container/ 直下にあるファイルは

allocator_traits.hpp std::allocator_traits 互換
string.hppstd::string 互換
vector.hppstd::vector 互換
deque.hppstd::deque 互換
list.hppstd::list 互換
map.hppstd::map・std::multimap 互換
set.hppstd::set・std::multiset 互換
scoped_allocator.hppstd::scoped_allocator 互換
scoped_allocator_fwd.hpp(scoped_allocator の最小宣言)
slist.hpp古のslist の拡張版
stable_vector.hpp vector<T*>で要素を別途アロケートのvector
flat_map.hppvector< pair<KEY,VALUE> > 風実装で mapインターフェースを持つコンテナ
flat_set.hpp(上記の std::set 風実装)
container_fwd.hppboost::container
detail/ 詳細実装のファイル群

(ptr_container のような)既存のstdコンテナを継承して拡張(メンバー関数追加)とかではないです。 (といっても boost::intrusive 等 boost内の他のライブラリはよく使われています)

次に、いくつかコンテナについて。

vector

ざっくりメンバー変数の部分だけ抜き出してみて、

template <class Allocator>
class vector_alloc_holder {
    struct members_holder : public Allocator {
        pointer     m_start;
        size_type   m_size;
        size_type   m_capacity;
    }
}
template <class T, class Allocator>
class vector : vector_alloc_holder<Allocator>;

(SGI版派生等)他の実装だと全てポインタで管理していることが多いですが、この実装はsize,capacityを個数で持っています(個人的にはデバッグ時にメンバー変数で見れるので好み)。

Allocatorは、(非static)メンバー変数がない場合に実質 0バイトになるよう struct の継承元になっています。
stlの実装では 多少の差違はあれ Allocator は (非static)メンバー変数になっていることが多いですが、 C++03 の場合 static メンバー変数で持つのも有りだったようで、実際そうなっていたコンパイラもありました。
C++11 では scoped_allocator_adaptor のこともあるし Allocator は (非static)メンバー変数必須のようです。

ということで C++11なら

// 1回 N個 アロケートするだけの Allocator
template<typename T, unsigned N>
class SampleAllocator1 {
public:
   typedef T value_type;
   SampleAllocator1() { }
   T* allocate(unsigned n) { assert(n == N); return reinterpret_cast<T*>(buf_); }
   void  deallocate(T*, unsigned) { }
   bool operator == (SampleAllocator1 const & ) const { return false; }
   bool operator != (SampleAllocator1 const & ) const { return true; }
private:
   typedef double buf_t;
   buf_t   buf_[(N*sizeof(T)+sizeof(buf_t)-1) / sizeof(buf_t)];
};
//typedef std::vector<int, SampleAllocator1<int,1024> >  Int1024Vector;
typedef boost::container::vector<int, SampleAllocator1<int,1024> >  Int1024Vector;
Int1024Vector  g_intVec;

みたいな真似をしても大丈夫のはず...と書いたけど上記はたぶん boost::container に依存しています.
(ターゲット環境で mallocの準備前に(固定サイズの)コンテナを使いたい...こともあった)

list

実装は boost::intrusive の定義も多く面倒なので、かなり端折って (boost::container としてでなく) ありそうな list 実装のメンバーの雰囲気として以下 (すみません、後付で boost::container からめたはいいけど対処しきれず...)

class Node_Base {
    Node_Base* next_;
    Node_Base* prev_;
};
template<typename T>
class Node : Node_Base {
    T     value_;
};
template<typename T, class A >
class List : A {
    ListNode_Base root_;
    size_t        size_;
};

かなりいい加減ですが、メモリーの雰囲気がわかれば...

map,multimap, set, multiset

map,set は たいてい赤黒木 実装のようで、boost::container では boost::intrusive を使ってるようです。
で、これも メモリーの雰囲気だけ...

class Node_Base {
    Node_Base* left_;
    Node_Base* right_;
    Node_Base* parent_;
    bool       balance_;
};
template<typename T>
class Node : Node_Base {
    T     value_;
};
template<typename T >
class Tree : A {
    Node_Base root_;
    size_t    size_;
};


List や Map は 渡された アロケータをそのまま使うのではなくて、allocator のメンバーの

template <class U> struct rebind { typedef allocator<U> other; };

を用いて、 T でなく Node<T> の allocator を使っています。 また、allocator への要求は通常 1個単位になると思います。

ということで、list や map の俺俺アロケータとしては、ノードサイズ固定のメモリーをプールしておく、というのが考えられます。

template<unsigned B, unsigned N>
class SampleAlloc2 {
public:
    SampleAlloc2() {
        for (unsigned i = 0; i < N-1; ++i)
            buf_[i].link = &buf_[i+1];
        buf_[N-1].link = NULL;
        root_ = &buf_[0];
    }
    void* allocate(unsigned n) {
        assert(n == 1 && root_);
        Link*   p = root_;
        root_ = p->link;
        return p;
    }
    void  deallocate(void* t, unsigned n) {
        if (t) {
            assert(n == 1);
            Link*   p = reinterpret_cast<Link*>(t);
            p->link   = root_;
            root_     = p;
        }
    }
private:
    union Link {
        Link*   link;
        char    b[B];
    };
private:
    Link*       root_;
    Link        buf_[N];
};
enum { ELM_SIZE = 32 }; // コンテナのノードを含んだ要素のバイト数.
enum { MAX_SIZE = 16 };
template<typename T>
class SampleAllocator2 : public SampleAlloc2<ELM_SIZE,MAX_SIZE> {
    typedef SampleAlloc2<ELM_SIZE,MAX_SIZE> base_type;
public:
    typedef T value_type;
    SampleAllocator2() {BOOST_STATIC_ASSERT(sizeof(T) <= ELM_SIZE);}
    T* allocate(unsigned n) { return reinterpret_cast<T*>(base_type::allocate(n)); }
    void  deallocate(T* t, unsigned n) { base_type::deallocate(t, n); }
    bool operator == (SampleAllocator2 const & ) const { return false; }
    bool operator != (SampleAllocator2 const & ) const { return true; }
};
// list
typedef SampleAllocator2<int>  IntAllocator;
typedef boost::container::list<int, IntAllocator > IntList;
// map
struct cstr_less {
    bool operator()(const char* l, const char* r) const { return strcmp(l,r) < 0; }
};
typedef std::pair<char const* const,int> smpPair_t;
typedef SampleAllocator2<smpPair_t> SmpPairAllocator;
typedef boost::container::map<const char*, int, cstr_less, SmpPairAllocator >	StrIntMap;

※ 要素(ノード)サイズ(ELM_SIZE)が直うちでみっともないですが、とりあえずは。

deque

(実装面倒なのと、ターゲットであまり使わないし... いえ、時間切れ. 後日に何か)

string

std::stringは(C++03では)ライブラリごとに結構実装がばらけています(EffectiveSTL に載ってるのとか)。 c++11 で縛りがきつくなったので多少にかよってくるかもですが、それでもいろいろできそうです。

最小限としては vector と同様の内容になりそうですが... boost::container::string から端折って抜き出してみると

 struct long_t {
    size_type      is_short  : 1;
    size_type      length    : (sizeof(size_type)*CHAR_BIT - 1);
    size_type      storage;
    pointer        start;
 };
 struct short_header {
    unsigned char  is_short  : 1;
    unsigned char  length    : (CHAR_BIT - 1);
 };
 struct short_t {
    short_header   h;
    value_type     data[UnalignedFinalInternalBufferChars]; 
                   // UnalignedFinalInternalBufferChars ≒ (sizeof(long_t)-sizeof(short_header))/sizeof(value_type)
 };
 union repr_t {
    long_raw_t  r;
    short_t     s;
 };

long_t は長い文字列でアロケータを用いる場合で、sizeof(long_t)-α 以内におさまる短い場合は short_t のようにして領域をバッファとして使い動的確保せずにすませる、という工夫がされています。 64bit CPUだと、vector互換でもsizeof(ポインタ)*3=24bytesになりますし、結構ありがたい実装です。 (最近作ってた 俺俺string がまさにこのタイプだった... もうboostのでよく)

※ メモ: ビットフィールドは エンディアン問わず、先に書かれたものが低アドレスに配置される.

stable_vector, flat_map, flat_set

stl コンテナの代用品でなく、vector 実装をベースにした特化版。
stable_vector は、vector<T*> と要素を別途アロケートしたもの。(boost::ptr_vectorの類似品?)
flat_map,flat_set は、vector<T> (mapはT=pair<KEY,VALUE>) にソート状態で登録して、インターフェースがmapやsetになったもの。
各自で俺俺コンテナを作ってそうな類なので(ええ作ってました)、boost にあると楽になりそうです。 (できれば stable_vector を flat_map 化したものもあればうれしいところ)

詳しいことは他のサイトにあたってください。

scoped_allocator_adaptor

C++11 で増えた アロケータです。

scoped_allocator_adaptor を用いれば、例えば map<string,int> のようなコンテナで、ローカルなアロケータをstringとmapで共通で使えるようにできます。
※ 内側のコンテナ(この場合 string)のコンストラクタとして、デフォルトコンストラクタでなくアロケータを引数にとるコンストラクタが使われるようになります。

アロケータをコンテナのメンバーにするので、当然メモリー使用量も増えます(とくに内側のコンテナは数が多くなりやすく)。 ので、コンテナのメンバーにするアロケータはポインタだけにし、実装はさらにその先に用意、といった感じにすることになると思います。

詳しいことは こちら のサイトとかみてもらったほうがいいです。

正直なところ一見ではよくわからず、試してみてなんとなく納得の状態です。

以下、試してみたソース.

#include <stdio.h>
#include <boost/container/map.hpp>
#include <boost/container/string.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/foreach.hpp>

// mapで解放しないこと前提に、スタックで解放無視の簡易アロケータ.
template<unsigned N>
class SampleAlloc3 {
public:
    SampleAlloc3() : size_(0) { }
    void* allocate(unsigned n) {
        assert(size_+n <= N);
        void* p = ptr(size_);
        size_ += n;
        return p;
    }
    void  deallocate(void*, unsigned) { /*dummy*/ }
private:
    typedef double buf_t;
    void*       ptr(unsigned n=0) { return (char*)buf_ + ((n + sizeof(buf_t)-1) & ~(sizeof(buf_t)-1)); }
private:
    unsigned    size_;
    buf_t       buf_[N / sizeof(buf_t)];
};

// map<string,int> のメモリー
template<unsigned SAMPLE_ALLOC3_SIZE>
class Hoge {
public:
    Hoge() : strIntMap_(std::less<String>(), MapAllocator(StrIntPairAlloc(&smpAlc3_))) {}
    void insert(const char* name, int val) {
        //strIntMap_[String(name, &smpAlc3_)] = val;
        strIntMap_.emplace( name, val );
    }
    void printAll() {
        BOOST_FOREACH(StrIntPair p , strIntMap_)
            printf("%s = %d\n", p.first.c_str(), p.second);
    }
private:
    typedef SampleAlloc3<SAMPLE_ALLOC3_SIZE> Alloc;
    template<typename T>
    class SampleAllocator3 {
    public:
        typedef T value_type;
        // SampleAllocator3() : alc_(0) {}  // デフォルトコンストラクタは用意しないほうが安全.
        SampleAllocator3(Alloc* alc) : alc_(alc) { }
        template<typename U> SampleAllocator3(SampleAllocator3<U> const& r) : alc_(r.detail_get_ptr()) { }
        T* allocate(unsigned n) { return reinterpret_cast<T*>(alc_->allocate(n*sizeof(T))); }
        void  deallocate(T* p, unsigned n) { alc_->deallocate(p,n*sizeof(T)); }
        bool operator == (SampleAllocator3 const & ) const { return false; }
        bool operator != (SampleAllocator3 const & ) const { return true; }
        Alloc* detail_get_ptr() const { return alc_; }
    private:
        Alloc*      alc_;
    };
    typedef boost::container::basic_string<char, std::char_traits<char>, SampleAllocator3<char> >   String;
    typedef std::pair<const String, int>    StrIntPair;
    typedef SampleAllocator3<StrIntPair>    StrIntPairAlloc;
    typedef boost::container::scoped_allocator_adaptor< StrIntPairAlloc >           MapAllocator;
    typedef boost::container::map<String, int, std::less<String>, MapAllocator >    StrIntMap;
private:
    SampleAlloc3<SAMPLE_ALLOC3_SIZE>    smpAlc3_;
    StrIntMap                           strIntMap_;
};

void sample3()
{
    Hoge<1024>  hoge;
    hoge.insert("xyz", 1);
    hoge.insert("abcdefghijklmnopqrstuvwxyz", 2);
    hoge.insert("1234567890", 3);
    hoge.printAll();
}

emplace, emplace_back、単に(コピー)コンストラクタの頻度さげるだけじゃなくて、今回のような場合まさに必須の類でした。
共通で使うアロケータ(SampleAllocator3)には デフォルトコンストラクタをつけちゃダメ、というのを実感。
( デフォルトコンストラクタつけてると insertや push_back 使ってもコンパイル通るため... ハマりました)

おわりに

遅刻したうえに、 グダグダな内容ですみません。
(当初の目論見からずれまくり...そもそも deque 調べるため boost::container 見始めたはずが)

例に挙げたソースのとおり allocator の記述に関してはすごく楽でした。 が、boost::contaneier を std:: にかえて vc12 でコンパイルすると全く×だったので boost::contaneier に結構依存していると思います。

時間の余裕なくなってるので、たぶん後日 補足修正書くことになりそうですが...

おつきあいいただきありがとうございました。


15日目は、@yohhoy さんです。


追記: コンパイル試したときのソース



2012-12-12[水] サイト分割

このサイトのプログラミング以外のページをこっちに移した。いろいろ思惑あれど遅々として進まず、けれど年越す前には何かしとこうと... というか、c++ advent calendar に参戦申込(12/14) しちまってたのでその前に多少なりとも、で。(肝心のネタをどうしよう... )




2012-10-27[土] Win8pro インストール

Win8の1200円のアップグレード版をダウンロードした勢いで(サブ機だし)Win7引き継ぎでインストールしたはいいけれど不安定になって結局更地で再インストール中。(OSのインストールは楽ちんになっても各アプリ側が面倒この上なく)

引き継ぎインストール、最初はそこそこいい感じに移行できたように思ったけれど、使いだすと引き継げてるもの・引き継げてないものがあってチグハグだった。

特にWindowsエクスペリエンス計測の このコンピューターの評価 がエラーで動かなかったときは唖然...
原因は、ユーザー環境変数 tmp, temp 。これらの内容は win7 での値が引き継がれていたが 指していたパス(=Ramdisk)は win8には引き継がれないため パス不正のため不具合に化けた模様。

[追記] Win8 設定完了前に メインでつかってる Win7機がお亡くなりになったため win8に強制移住。HDDが生きてたので被害は少ないけれど、元環境のアプリを起動できないのはやっぱり面倒。

[追記2] iPad mini を購入したら一気に win8 熱が冷めてしまった。片手で持ててそこそこ広いってのは思いのほか重要だった模様。寝ころんでpdf読んで寝落ちするのはある種幸せです。




2012-6-3[日] LaVieLight に Win8rp をインストール

久しぶりにサブノートPCを持ち歩こうと思いたち、Win8cp を試しに入れて放置しっぱなしだった LaVie Light BL350/D を復活中。 丁度 Win8 Release Preview が公開したてだったので更地にしてインストールすることにした。

マシンのほうは Atom な netbook の範疇だけど、1366x768 ドットある奴なんで一応 Metoro も大丈夫(なので Cp 版インストールできてた。非力な Atom だけど 1.5GHz 2コア(HT x4) だし、メモリは2GBにHDDはSSD120GBに換装済みなので、それなりに使える感じ)

インストール前に、まず、Microsoft アカウント(Live ID)の氏名欄を 英数のみに変更。

Win8 はPCのユーザー設定で MSなクラウドサービスと連動前提の設定と、そうでない(従来タイプの)設定を選べるが、CP 版時に いろいろ試したく 連動のほうを選んだら、Microsoftアカウント情報に登録してある氏名の“名”の文字列でユーザーが作られてしまったのだった。本名を漢字で設定したままだったから c:/users/本名 な漢字フォルダが作られしまい、古いツールを使う機会もあるプログラマとしては腹立たしい状態だったので、今回はアカウント情報のほうを変えておくことで対処。(CP版のときはこの段階でかなり萎えて余り使わず放置)

更地からなので ISOイメージをDVDに焼いて USB-DVD でインストールした。 途中でプロダクトID を聞かれたので、Webインストール版を実行して手順に従って操作している途中で表示されたプロダクトID を用いた。(この方法でよかったのか不明だがとりあえず動いてる)。

当然インストール開始時には以前インストールしたwindowsの情報は引き継がないほうを選んだのだけど、インストール後デスクトップを選んでみれば壁紙無し単色でタスクバーが縦置き状態……これWin8のデフォじゃないよね? CP版で設定していた己の設定ぽいので、アカウントに紐付された情報が一部あるのかも。

とまOS自体は結構すんなりインストールできたと思うけど、メール設定でミスってしまったようで(ExChangeどうこう持ってないのに選択してしまってエラーは出たと思う)、スタート画面でMailを選ぶとタイトルのみ項目のないアプリが立ち上がるだけ…Metroなアプリってどこで諸設定できるのか……よくわからず放置中。
(間抜けてた。メール画面で右サイドメニュー(右下か右上あたりにマウスカーソル持って行ったら出る奴)の"設定" を選べばメールの設定できた。右サイドメニューの5項目の名前かわらないから、てっきり全体で共通のものかと思ってたらメトロアプリごとに内容は変わってて、デスクトップアプリのメニューバーみたいなものだったのね)

その他アプリのインストールについては、CP版より更にスタートボタン破棄の方向が強められてる感じ。 CP版のときは、タスクバーに新規ツールバーとして

C:\users\(ユーザー名)\AppData\Roming\Microsoft\Windows\Start Menu\Programs

を登録すれば簡易なプログラムメニューとして使うことができたけれど、RPではアプリをインストールしても そもそも このフォルダにアプリのショートカット等は作られず、Metoroなスタート画面にドバっとアイコンが現れる状態。元の(start-プログラムメニューでの)フォルダ構成無視なんで一気にスタート画面がゴミ溜めと化す。全くスタート画面を使わなくてすむならそれでもいいけれど、立ち上げ時に必ず来るしね……しかたないので、右クリックで不要なものをマークして一気にピン止めを外した(ちょっと面倒)。

※ 全部が全部じゃなくて一部(susie)は従来のメニューに現れるものもあった(たぶん START-プログラム・メニューへの登録が今のwinの作法に則っていないのかも)

 

インストールしたプログラムでまともに動かなかったのは TortoiseSVN(1.7.7)。 チェックアウトしたりTortoiseSVNのメニューが閉じられるときにクラッシュする。 それだけでなく Exproler(タスクバー) が不安定になって ゴミ箱を空にしようとしたり タスクバーを自動に隠す設定をやめようとしたらハング(即再起動するが)。
Tortoise??? の仕組みからいって、新規OSでいきなり動かなくてもしかたないとは思うが、使えないのはちょっとつらい。

とりあえず TortoiseSVNをアンイストールして再起動で元に戻ったけれど、最初 アンイストール後シャットダウンで終了して電源ボタンで起動しなおしたら OS不安定のままだったので結構あせった。2,3回やっても変わらずで。再起動を選んだところ"更新します"みたいなメッセージでて再起動後ゴミ箱空にしてもハングしなかったので一安心だけど。Win8からの高速なブートや終了のための仕組みの影響なんでしょうかね。

追記: またゴミ箱空にしたらハングするようになった。FireFox(12)も終了するたびにクラッシュレポータが表示される。 どうやら今度は Google日本語入力が原因だった模様。設定をMS IMEに切り替えたらゴミ箱空にできたしFireFoxも正常終了、googleIMEに切替るとまたハング...うーシステム拡張的なものは結構引っかかる感じなのかな。




2012-2-29[水] pyukiwiki 0.2.0

月末に作業締め日がある場合、さて閏年でよかったと思うべきか... はどうでもよく。

このサイトに使っている pyukiwiki 共同開発版は一時開発が止まってたけどまた再開していたようで v0.2.0p1 が出てたので更新してみた。

wikiプログラムの更新だけでサイト自体のリニューアルというわけではないけれど。でも微妙な修正をちょこちょこ、どうせspamしか書き込まないのだからcommentは無しにしたり(少し寂)、無理にblog風にすることもないなで昔のtop頁に戻したり。 (もう少しいじってからとか思うもその状態で2週間放置だったり。)

pyukikwikiの更新のほうは、久しぶりすぎて、いろいろ細かいこと忘れていてすごく手間取った。自分の改造やプラグインの事情が記憶の彼方なのは当然として、使用した環境じゃ CRLF だとcgi(perl)が動いてくれないことに中々気づかなかったり(本来なら年始に移行するつもりが)

0.1.9あたりから utf-8 専用板が用意されてるようなので、utf-8 版にしようと思ったのも一手間。頁等のutf8へのコンバータプラグインが用意されているけれど、さすがに 0.1.7では駄目のようで一旦 euc(従来)版 の0.2.0環境に移行する必要があり... コンバートだけだからと compact 版を使ったところ動かなかったり(full版は動いてくれた)

改造|自前のpluginの辻褄合わせは微妙に面倒だけどしかたなし。editは改造しなくてもよくなってたけど、calender2とか改造に依存したサイトになってるので... 入れ替える時面倒なので結局 改造プラグインは名前を変えて対処したり。

スキンは 0.1.7で使ってたのがほぼ無変更で使えたのでそのまま. うち向きの仕様も増えてるっぽいので ほんとは 0.2.0 のをベースに作りなおしたほうがいいのだろうけど。

と、pyukiwiki共同開発サイト 見に行ったら 0.2.0p2 のアナウンスが出てた模様。 compact版はやっぱり配布内容がおかしかった模様. (p2にしようかと思うもダウンロードは3/1予定... とりあえずp1のままで)




2011-11-11[金] C++11 を忘れたい、3年くらい

ポッキーの日、と言われてすぐになんのことか思え出せなかった虚け者です...いや、覚えていなくてもいいと思うけれど おすそ分けのポッキー食べたんだからちょっとくらいは覚えておこう>己。で連鎖的に C++11 を思い出す、けど、まともな処理系がでてくる2,3年後までは知らずにすませていたかったというか忘れたい。今 C++ 03 で(ライブラリを)作るものにとっては非常に目の毒です。(と、ま、ただの生存証明)




2011-1-6[木] stlport.org

ひさしぶりに www.stlport.org を見に行ったら消失していて焦ってしまう。 といっても sorceforge にも頁があるので…

というより http://stlport.sourceforge.net/Home.shtml が公式ということか? 左サイドのメニューをちゃんと認識していなかった。 いまさらながらhistoryFAQを見てなんとなく納得。 (放置してた旧サイトのドメインが消失したってだけのことでいいのかな)

あとFAQみて4.6系はいまいちな状態でv4の最後の綺麗な版が4.5.3だったことを知る。dmc用公式 stlport が4.5.3どまりなのはそのへんもあるのかと連想。

現在の最終の公式リリースは 5.2.1(2008) のままだけど、開発版のソースをみると、メジャーバージョン(#define)は 6 になっていた(6に向けての開発中)

C++0xを考慮してるし、あまりに古い仕様のコンパイラは対象外にしていってるよう。 さすがに、メンバー関数テンプレートのサポートは必須扱い、stdint.hも利用してるしで、互換のためにごちゃごちゃしていた記述が省かれたり単純になったりですっきりしてきている。(v4→v5 時ほどではないのだろうけれど)


それと 以前 気になっていた type_traits の ライセンスの "Academic Free License ("AFL") v. 3.0" はやめたようで、(STLport共通の)緩いライセンスに変わった模様。type_traitsだけでなく他のファイルでも "AFL v.3.0" のものは無くなっていた。(以前 そのライセンスの.makファイルのあった buildフォルダごと無くなっている:)

ライセンスについては LICENSE ファイルが同梱されているので、それを確認、と。

[1/8追記] どうも http://stlport.com/ がある模様。消失じゃなくて移転ということなのか?
[5/22追記] 単に一時的に失効してただけみたいでstlport.orgも復活している模様




2011-1-1[土]

あけましておめでとうございます。今年もよろしく。

去年は人生の節目のようなことがあった反面、 総じてグダグダな一年だったので来年はもっと頑張る予定。 いや今年はも少し頑張るです(数え年は気になる)


といったところであいかわらずgdgdだけど、年末に自宅PCを win7(64)に移行した。 vista64 のwindows updateでエラー80070024が出て更新できなくなり、 ググって見つかる試せる解法はすべてダメであとはMSにメールするしかないパターンのようなので…いっそ更地インストール。 動作環境を残しての移行なので、PC崩壊からの移行にくらべれば楽ではあるけれど、時間は掛かるし動作環境復元できないものもやっぱりあるので、毎度のことながら消耗はげしい。

また、そこそこ環境整い、さて年賀状印刷しようとしたら、今度はプリンタ(Canon MP640)がエラー6C10 で動作できず。検索でみつかるモノを見ると、基本、メーカー修理するしかなさそうだ。年末年始修理受け付けてないようなので後日。しかしまだ半年経ってなくてあまり使ってないのに…いやプリンタは使用頻度が低すぎるのがまずいのだろうけど。ああ6C10で引っかかる頁はMP640以外もあるのでCanonの機種はエラーコードを継続しているのだなあ、と当たり前といえばそうだけれど妙に感心してしまった。




2010-3-21[日] LLVM lli での実行

そういや LLVM の VM(lli) ってどれくらいなんだろうか、とちょっと気になったので 3/12のを lli で実行してみた。

llvm-gccでコンパイルして、 llc で生成したネイティブアセンブラソースからexeを作ったもの、と、 lli で実行したもの。 llcからのexe結果は不精して、前回のからコピペ。 今回試した lli はそのときより数日新しいllvmになっていたり 多少測定環境がぶれていたりするけれど、おおざっぱな雰囲気をみる分には...で。 (ソース&exe)

コンパイラBilinear 拡大(ミリ秒)安易 インタプリタ(秒)quick sort(μ秒)QSORT(μ秒)Dhrystone/secWhetstone (MWIPS)
llcでasm→exe105.827.61987135860(25056376)1525.463
lliで実行 103.626.01749939343(26184864)1530.688

大筋 lliの実行結果は llc でネイティブアセンブラ生成した場合と同様の結果のよう…

仕組みからすれば、lliのほうは測定範囲外の部分で余分に時間かかってる (実行時コンパイルしてる)だろうが、 .bcサイズに対する今時の実行環境のパワーを思えば たいしてペナルティがあるわけでなく、ってとこ、か? ( ロード時に一括コンパイルしているのかな?)

ネイティブ実行以外興味なくて、最初にちょろっと試しただけで、以外に速いかも なんて思ってたのだけど、以外に、どころじゃ、なかった。

LLVM関係の記事(appleのopenglな件とか)に書かれていることを思い返せば、 こういうことなんだろうけど、実感してなかった、というか、わかってなかったことを実感です。




2010-3-20[土] LLVMで Cに変換してみる

LLVM (llc) には Cソースコードを生成する機能があり、 C++ソースをCソースにすることができる模様。

ただし C++ から C への直接変換するのではなく、 一旦.ll/.bc(llvm用アセンブラソース,ビットコード)にしたものを、 llc.exe で(ターゲットCPU用アセンブラソースのかわりに) Cソースへ変換するというもの。

普通のアセンブラソースをCに変換した場合 オーバーヘッドは当然あり、 全体として問題になることはそうないかもだが (昔アセンブラソースからCに変換しての移植作業を何本かやったときの印象)、 何割(何倍)か遅くなっていてもおかしくない。

が llvmの .ll/.bc は、 普通のアセンブラソース/オブジェファイルでなく、 それより情報の多い中間コードなわけだし、 llvm-gcc & llc でオプティマイズしているため、 Cソースになっても元よりも速くなる可能性もありそう。

ということで、ちょっと、試してみた。 3/12にしたテストの1つ目。 C++でなく Cソースだけど。 (32bit色640x480→1920x1080拡大の50回生成の平均時間を求める奴. 実行環境は前回同様)

llvm-gcc で

llvm-gcc -S -o tmp.ll -emit-llvm -O2 -DNDEBUG test.c
llvm-as  -f -o tmp.bc tmp.ll
llc -march=c -f -o test_dst.c tmp.bc

として test_dst.c を生成。
なのだが、このまま別の(複数の)コンパイラでコンパイルしてみると __imp__iobやQueryPerformanceCounter等が未定義参照だと リンカに怒られる。 __imp__iob は stderr の本体(を収めた配列名)、 QueryPerfomance…は時間取得につかってるWin-APIのもの。

ヘッダ込みでコンパイルされた結果を C化してるのだから、 
llvm-gcc でコンパイルする場合のヘッダ/ライブラリと、
ターゲット・コンパイラでのヘッダ/ライブラリが同じ(矛盾しない)
でないと当然マズいのだった。

とりあえずstderrやwin-apiを使わないようにして(外部はC標準関数だけにして)回避。
ソースは、 これこれ
それを llc で変換した後のソースは、 これ

ついでに 一旦 ldでまとめたものを.llに戻してから llc したものも試す。

llvm-gcc -S -o tmp.ll -emit-llvm -O2 -DNDEBUG test.c
llvm-as  -f -o tmp.ll.bc  tmp.ll
llvm-ld     -o tmp.ll.exe tmp.ll.bc
llvm-dis -f -o tmp.2.ll   tmp.ll.exe.bc
llvm-as  -f -o tmp.2.bc   tmp.2.ll
llc -march=c -f -o test_dst.c tmp.2.bc

変換後のソースは、 これ

前者の変換後ソースには元の関数を維持しているが、 後者の変換後ソースでは関数はmain()だけになっている。


2つの変換後のソースは、だいたい他のコンパイラでもコンパイル可能。
(ダミーの alloca.h の読み込みを用意したり、 dmc では bool のtypedefが衝突するのでダミー alloca.h 内で誤魔化したり する必要はあった) (このとき使ったllvmは rev.98686 )

が失敗したモノもあり、
vc64に関しては、ハング(作られたソースが32ビットcpu専用のソースかも?)。
bcc 5.5.1 は宣言に型が多すぎる、と怒ってくれてコンパイルできず (bcc 5.8.2は可)。
clang は型チェック関係でひっかかるので挫折。
mingw440 は、前者の変換ソースのものを実行するとハング。
pcc では、後者の変換ソースでは、DEP チェックにひっかかりハング。

実行できたものについての結果は以下 (単位:ミリ秒)

コンパイラ 元の結果前者の変換での結果後者の変換での結果
vc9sp1 197153162
cygwin gcc344 256238237
mingw gcc345 255239237
mingw gcc440 269---255
LLVM-gcc42(SSE?使用) 103109104
open watcom(1.9rc1) 397327317
dmc(8.51) 352301317
pcc 323308---
coins 493334317
PellesC 408353350
TinyCC 449397396

測定したタイミングによっては10,20ぐらいの差がでたりするかもで、 ざっくりとした感じに受け止めてもらうとして。

LLVMのツールであるllvm-gccではあまり差はないようだが、 他のコンパイラでの結果は、多少なりとも llc で変換したソースのほうが速くなってる雰囲気。

ただ前者と後者の変換については、モノによって多少違うも、 測定誤差でありえる範囲の差で、あまり違いはなさそうに思う (関数の分割具合の違いによるオプティマイズの トレードオフはあるだろうで、それが微妙に出てる可能性もあるけれど)

他のソースも試すべきたんだろうが、面倒で挫折... 他の例でも速くなるのか遅くなるのかどうかは結局ソースしだいと思うが、 それでも元のソースよりも速くなる例ができたわけだから (元ソースがヘボいのだろう、というのは置いといて)、 他の例でもそう酷く遅くなるようなことはないんじゃないかと期待.

※'元の結果'は3/12の結果と比べて少しずれてる。やってることはほぼ同じだけれどソース的には多少(時間取得関数だけでなくclang測定対策等)違うせいか、測定誤差といいきれない差のものがある. 前回のexeを実行すればやはり前回と同様の値なので、ソース変更の影響のよう。今回は今回、ということで。

zip


C++ → C

で、 肝心の c++ → c .
C++標準ライブラリの使用については、 実体がすべてヘッダでの定義ですんでいるようなモノ(std::sortとか)を使う分には、 (実体がライブラリ(アーカイブ .libや.a)化されているものを使わない範囲では)、 変換ソースを他のCコンパイラでもコンパイル&実行できる(た)。

が、g++(clang)側のライブラリ(.a)に実体がある関数や機能を使った場合は、 コンパイルできても当然リンクが行えない状態。 bad_alloc みたいなライブラリものもそうだけれど、 virtual使ったり 例外を使った場合もそう。その他諸々。 C++らしい組み方をしてるとまずその手のものは使われてるだろうで...

足りてないリンク物の代用品をターゲット環境用にも用意できれば なんとかなるかもだが、大仕事だろう。(あるいはターゲット対応をllcに施すとか... どちらにしろ個人がチョロですむ作業ではなく)

I/Oを含まずtemplateを使ったような処理をベターCの範囲で書いてCに持ってくる、くらいなら...と思うも、やっぱ面倒だなあ.


あと、llc は c だけじゃなく c++ ソースも生成できる。
計測に使ったソースを後者の変換をしてみたものが これ

なんかすごい、というか、目が点になる、というか。
効率どうこう以前に趣旨が違うもののような気もする。
(パッと見でincludeフォルダ設定を追加してコンパイルを 試しみたけど、どれも上手くいかず。あまり追及する気にもなれず)


※と、まあ、発展途上のllvmを使っての感想なんで今後どうなっていくか、わからないけれど

他のC++ → C トランスレータ

ついでのメモ。

元祖のC++実装の cfront は、Cソースへのトランスレータとして実装されている。 例外が実装されずに開発は終わっているが、 こちら でR3.0.3等いくつかのバージョンのソースが公開されている模様。 (使えるかどうかはしらない)

現行のC++をサポートしているだろうトランスレータとしては Comeau C/C++。 有料だけど低価格($50)。 面倒がって未購入だけど。 他環境向けのCソース生成ならこちらのほうがよい?(夢見てるかも)... といっても、ターゲット環境ごとの個別対応は必要だろうで、 Comeauのサイトで対応と書かれているのは比較的メジャーな環境のみのよう。




2010-3-15[月] watcom,dmcのテンプレート不具合

open watcom 1.9rc1 が出ている模様. が c++ 関係はあまり進展していないのか、 1.8よりちょっとは増えたようだけれどまだ未実装のSTL関係は多そうで (stable_sortなかったり)、 クラステンプレートのメンバー関数テンプレートをクラス外に書くのも まだ未サポートのよう.

template<typename T>
class Bar {
public:
    template<typename U> void test(T* t, U bgn, U end);
};

template<typename T>
template<typename U>    // この行.
void Bar<T>::test(T* dst, U start, U last) {
    while (start != last) *dst++ = *start++;
}

のBar<T>::testの2つ目のtemplateでシンタックスエラー.

template<typename T >
class Foo {
public:
    template<typename U> void test(T* t, U bgn, U end) {
        while (bgn != end) *t++ = *bgn++;
    }
};

のようにクラス内に書くのはok.

ついでに、上記は dmd(8.51) でもコンパイルエラー(startが未定義)になる。 こっちは、 テンプレートな引数の名前が Bar::test()宣言と定義で違うのが気に入らないらしい。 定義側の引数 start, last を bgn, end に修正すれば ok。 (テンプレートでない引数は名前が宣言と定義で違っても無問題)

別のコンパイラ(bcc 5.? だったか)でも、

template<typename CharT, class Traits>
class Foo {

のようにクラス定義してメンバー関数を外に

template<typename C, class T>
void Foo<C,T>::hoge(…) {

みたいにテンプレート引数名を変えていたら 某かの不具合がでた覚えがあり(名前を統一したらok)

汎用性を思うならば(古いコンパイラ気にするなら)、 クラステンプレートのメンバー(関数)は、 下手にクラス定義から分離せずに、内部に書いてしまうほうが 余計なバグに出会わずに済むのかも。 (分離する場合は名前を揃える... てか、ひょっとして普通揃えないとダメなのかな?)

(ごちゃごちゃする定義はクラス外部に追い出して、 クラス宣言は身軽にしておこう、 なんて考えてたらドツボにハマることもあった、と)





2010-3-14[日] winの LLVM-Clang でコンパイル.

Clangで、なんとか、コンパイルできた。 (前日冒頭のつづき)
単純なhello.cで#include <stdio.h>だけなら、実はそのまま出来てた。 ただ、3/12のテストルーチンをコンパイルするとヘッダ関係でいろいろ不具合出た。

コンパイル出来た llvm,Clang のソースは llvm rev.98447、clang rev.98448のもの(結構頻繁に更新されてるよう)で、vs2008sp1 にて release の ALL_BUILD して生成.

まず、_WIN32等が設定されてたのは まさに Clangのソース内で設定されていた。 win環境なら _WIN32 定義してて、また、VC環境だと VCのinclude等のパス設定するような処理があった. (VCでコンパイルしたから呼ばれるのかVCがinstall済みだからよばれるのかは よくわかってないけど). でもってmingw関係も定義されてる雰囲気だった(mingwやgccを詐称してるよう).

VC関係は邪魔なので -nostdinc 指定してデフォルトのincludeパスを見に行かないようにし、 引数で llvm-gcc-4.2 の環境を流用して設定するようにした。 (別に llvmのでなく普通の(最近のバージョンの)mingwの環境でも大丈夫そう)
だいたい

clang.exe -nostdinc -Dwint_t=wchar_t -D__declspec=__declspec -Ix:/llvm/bin/lib/clang/1.1/include -Ix:/llvm-gcc-4.2/include -Ix:/llvm-gcc-4.2/lib/gcc/i386-mingw32/4.2.1/include -O2 -o test.exe test.c

といった感じにコンパイル. +こまごま修正.

  • windows.h を受け付けてくれるが wint_t が未設定だったみたいで -Dwint_t=wchar_t で誤魔化した.
  • time.hをincludeしたときは、__MINGW_IMPORTが未定義扱いだったので -D__declspec=__declspec を定義して誤魔化した.
  • inline関数だった箇所がリンク時に未定義だって怒られたので、static inline に修正した(C++じゃなくてCなんだから static inline じゃないとマズイのだろうな).
  • ctype.h をincludeしたら_imp____mb_cur_max_dll等で怒られ、とりえあず ctype.h を使わないようにして逃げた.

ヘマして何か設定が足りてないだけかもしれないが、まだ、ちょっと面倒な状況かも、で。

テストの実行結果は以下の通り。 (最適化オプションは-O2にしたけど妥当かどうかは未考慮)

コンパイラBilinear 拡大(ミリ秒)安易 インタプリタ(秒)quick sort(μ秒)QSORT(μ秒)Dhrystone/secWhetstone (MWIPS)
LLVM-clang 199.927.91522567820128419161478.956

他の結果はこっちみて...
結構いい感じ。 このテストだと、VCの次くらい …gccよりよかったり悪かったりがあるので、類似物じゃないよな。 (安易インタプリタはctype.h関係を手書きマクロに置き換えたので若干条件違うことになるが→結局、他も計測しなおした)

LLVM-gcc は、dmc に対する gdc のようなものに思ってたのだけれど、どうも、測定結果を思い直すと(llvm用コードでなく)ネイティブコード生成時はただのgcc(4.2)なのかも。

追記: やっぱりマ抜けていた。--emit-llvm を指定しないとただのgccかも. --emit-llvm でllvmなコードを一旦はいてからx86向けを作る、みたい. (コンパイル手順はこっちに, 結果はこっちに追記)

で、clang も -emit-llvm 付で生成すれば同様にさらにオプティマイズできるよう。
ただ、手もとの環境で作ると、生成した.exeはハングするので、ちと残念な状態。 (ハングする前に計測結果のでたモノをみるかぎり llvm-gccと同様に早くなってた)
4/23追記: 最近のclang(1.5 trunk 102038)で試したら修正されてるようで動作。(試したのはbilinearのだけだが、さらに速く(97)なっている感じ)




2010-3-13[土] win標準と衝突するunix系コマンド.

こちらでclangのvcでのコンパイルを紹介されてたので、やってみた。出来たコンパイラを使うとincludeでvc側の ヘッダ読み込まれてエラー。 _WIN32が定義されてるし、何か、しなきゃいけない (環境)設定が抜けてるんだろうなあ。 (includeしてないソースのコンパイルでexeやasmはつくれてた)

で、そのとき、こちらの GnuWin32 をインストール.

cygwinやmsys同様 unix系フォルダ構成を持つ状態のコマンドラインツール群で、 dllや言語ファイルがあるので単体コマンドを流用したい身には一長一短だけど、 コンパイラやスクリプト言語等は含まれていないので、ある意味、身軽で、 通常(常用)の環境変数PATHの最後にGnuWin32/binを追加して使うのでも よいように思えてきた。

unix系ツールと win(dos)標準コマンド名でいくつか衝突するけど、Windows/System32/*.exeとgnuwin32/bin/*.exeを比べると

calc.exe 電卓だが、gnuのはコンソール、WinのはGUIアプリ.
expand.exe 圧縮データの解凍、だが、対象とするデータ形式は(たぶん)違ったはずだし、 引数オプションも違う.
find.exe gnuのは ファイル検索、Winのは テキスト中の文字列検索.
sort.exe ともにテキストのソートだが、オプション引数は違う.
whoami.exe ともにユーザー名表示だが、表示形式が若干違い、gnuのは ユーザー名だけだが、winのは コンピュータ名\ユーザー名 となっている. オプションも違う.

ぐらいか。
まあ、これらが関係ない状況で使う分には大丈夫かな、と。

当然他のパスも通るので衝突がありえるけど. (コンパイラ関係だと link.exe とか)
cmd.exeの内蔵のecho,mkdirも衝突するが内蔵コマンドゆえwin側としては問題なし. unix系ベースで考えるときは問題あるだろうけど、そういうときは cygwin,msysあたりをつかっているだろう、で.


※と書いたが、別に GnuWin32 でなくmsys でもほぼ同様かもだけど... (cygwinはともかく msys+mingw環境も特殊性があるのかどうか)




2010-3-12[金] ちょっと速度比較

前回触った LLVM-gccやpcc,coins (で作ったプログラム)の速度が気になったので、 手持ちのCコンパイラ(vc意外はフリーのもの)で適当に実行速度を計ってみた。

(3/14修正: cygwinの計測が間違って別のmingwでの結果になってました).
(3/15修正: llvm-gccは生成方法を間違えていたためやり直しました. また他と比較しずらいので clangの結果も含めました)

試したコンパイラは全てwin環境用で

コンパイラ 生成にかかわるオプション補足
vc9sp1 64bit -GR- -Ox -DNDEBUG -MT
vc9sp1 32bit -GR- -Ox -DNDEBUG -MT
cygwin gcc 3.4.4 -O2 -DNDEBUG bashでなくcmd.exe上で実行.
mingw32 gcc 3.4.5-O2 -DNDEBUG
mingw32 gcc 4.4.0-O2 -DNDEBUG
LLVM-gcc 2.6 -O2 -DNDEBUG -emit-llvm 実際には一度に作れず複数工程になる
clang -O2 -DNDEBUG -emit-llvmせずで、おそらくclang単体での生成
Open Watcom 1.8 -Ot -O3 -DNDEBUG -finline-functions
-frerun-optimizer -floop-optimize
-funroll-loops -finline-math
dmc 8.51 -o -DNDEBUG
pcc-20090818-win32-O3 -DNDEBUG
COINS 1.4.4.3-en -O2 -DNDEBUG bashでなくcmd.exe上で実行
BorlandC 5.5.1 -O2 -Ox -RT- -d -dc -DNDEBUG
PellesC 6.00.6 /Zx /Ze /Ox -DNDEBUG
TinyCC 0.9.25 -DNDEBUG オプティマイズは無い

正直、オプションが、どの適度適切かは不明。 Watcomはつけすぎてるけど、基本はデフォルトに近い状態。
浮動小数点関係は、設定しだいで結構違うだろうけど不精してせず(watcom以外)。

試したテストプログラム

バイリニアによる画像拡大 乱数で生成したピクセルで埋め尽くされた640x480の32ビット色(ARGB)画像を1920x1080へ拡大する処理。10回の平均値。
安易インタプリタでのスクリプト実行 400行ほどのおもちゃのインタプリタ言語で、 5000*5000ループの適当なサンプル実行. (仕組みが手抜すぎて実際的な比較向けではなかったかも)
クィックソート 以前試したCでかかれたQUICKソートと、Cライブラリのqsort互換のクィックソートルーチン のテスト.
とりあえず、この頁の結果には int 1000000個をソートしたときの時間を記入.
Dhrystone 2.1 整数演算用ベンチマーク. Wikipedia等みて. モノは、こちらの記事から リンクされているモノを使用. ソースは2.1のモノだけ使用(コンパイル楽なため). けど、Old-Cスタイルでエラーだすコンパイラ対策でANSI-Cスタイルに修正したり ヘッダ依存関係調整したり. 使用時はループ回数を100000000回にして実行.
Whetstone 浮動少数点演算用ベンチマーク. wikipedia等みて. こちらのサイトの BenchNT.zip に入っていたソースを利用. こちらもコンパイラごとの調整のための修正あり.

download:上記のソースのzip

たくさんやるのも面倒なので、これだけ(これだけでも結構しんどく)。 自分が大雑把に雰囲気をつかむため、なので、あまり適切でないサンプルかも。 1core 1threadな簡易な処理だけだし。 Dhrystone,Whetstoneは一応してみたけど、あまりピンときていない (処理内容わかってないからだろうけど).


実行環境は vista64(PhenomIIx4 3G)、通常のデスクトップでDOS窓とエディタ程度だが、サービスや常駐モノはある程度残った状態で実行.(テスト中の 1core がフル稼働で、あとの処理は他のcoreが大筋まかなってるだろうと期待. 以前別の計測にてsafemodeで起動して計測したほうが安定していた感じはあったけれど、酷すぎるほどの差もなかったので楽してる)

実行結果 は (3/14 一部計測し直し. cygwin計測ミス、安易インタプリタのclang対処反映)

コンパイラBilinear 拡大(ミリ秒)安易 インタプリタ(秒)quick sort(μ秒)QSORT(μ秒)Dhrystone/secWhetstone (MWIPS)
vc9sp1 64 87.525.21443939856142146413465.753
vc9sp1 32 189.224.71445269039115300362284.091
cygwin 344262.020.22030060900102082482108.046
mingw 345 245.025.4191666155698931541456.068
mingw 440 265.025.31911885483102732691554.432
LLVM-gcc(sse2)105.827.61987135860(25056376)1525.463
clang 199.927.91522567820128419161478.956
watcom 387.326.42822242918111869342199.402
dmc 371.925.1212246058090407741560.336
pcc 289.932.3194367962780334191176.030
COINS 384.128.0187006550059908941335.854
Bcc 5.5 582.239.41909259047101112231692.216
PellesC 429.330.4146966679473179651241.080
TinyCC 511.449.96621310585857544021063.352
(補足) ↓good↓good↓good↓good↑good↑good


たったこれだけだし、 測定(実行)環境はザルで実行毎の誤差からすれば 細かい数値みちゃうとまずいだろう。 特に浮動少数演算関係のオプション設定が適切でないだろうで 設定かえたら(Whetstoneとか)結果変わってきそうな気もする. (c標準ライブラリも計測範囲で使われてるので それの影響もどう据えるかにもよるし)。 が、おおざっぱに、vcが1番よさそうで次gcc系、 後は混戦で、ケツがTinyCCって感じか。
今回以外の例を思えば vcが抜きでてるとはいいきれないけれど. (Intel C/C++気になるけど懐的に手が出せないのでVCで満足しとく)

vc9sp1 64 の結果は CPUが64bit CPUなので、コンパイラの比較ってよりCPUの比較になるけど、 64ビットOS用にコンパイルするだけで、 結構違いがでる処理もある、という例になってるかも、で(代わり映えしない処理もあるけど)。

バイリニア拡大の結果は、 64ビット整数の利用頻度が少なかろうと 汎用レジスタが増えたことによるメリットが効いている例だろう (あとSSE2も関係あるか? 追記:というか、汎用レジスタどうこうでなく、 まさにSSE2になったことが効いているよう。 clangの結果がいいのも、SSE?なコードが生成されているためのよう (clangのほうはsseしてない) )。 32bitでもVCが結構速くなる例で、結構かたよった代物だろうけど... (この手の画像処理なんかは普通からすれば特殊な扱いになるのかも. 速度/ハードを気にしだすと生のCだけで済まさないだろうし)

感想としては llvm(-gcc)は(いろいろミスして勘違いしまくりだったけれど)ものによっては非常に速くなったりでびっくりで早く使い易くなってほしく、 Clangはllvmをしなくても(?)これだけの性能あっていろいろ期待、 PCC は速度は思ってたよりはいいかも、だけど(Win版は)思ったより安定してなさそう、 PellesC はそんなもんだろう、 TinyCC は実行時速度じゃなくてコンパイル速度優先で(-benchなんてオプションがあるくらいだし)スクリプト言語的にCソースを扱うような方向があるようなので 実行時速度はこの程度の差ならokなんだろう、 COINSは悪くないのだけど期待しすぎてたため (ひょっとするとあまりx86系向きじゃないのかもだけど) ちょっと哀しい気分、てとこか。

※追記:cygwin-gcc、測定ミスでやりなおしたけど、gcc3.4の範囲なのでたいして値はかわってない(でもWhetstoneは結構ちがうか。浮動小数点はオプション設定しだいだろうでデフォルトがいい状態だったのかも)。 もともとcygwin使ったCOINSの結果と比較するのにmingwのでいいか微妙な気もして追加したものなので(ただの計算だけだとそう違わないだろうけど). あと最初の4つのテストで cygwin-gccとCOINSは win-apiでなくtime.hを用いて計測しているため若干条件が違う、とも.

※追記:安易インタプリタの結果は、clang対策での修正前にくらべ、どれも4,5秒短くなっている. isalphaやtoupperを手抜きなマクロに置き換えただけだが、結構ライブラリのオーバーヘッドがあったということか. テーブル参照より単純比較のほうが速いのかスレッド関係やロケール対策がらみなのかはしらないけれど。

※追記: llvm-gcc のやり直しにおいて、Bilinear拡大は最適化されすぎて計算がなくなってしまったため、そうならないよう、若干ソースを修正(計測時間外での対処)した.
また、Dhrystone2.1の結果も最適化されるぎている可能性があるかも(大丈夫?).
(dhry_1.c dhry_2.c を1つのソースにした場合のvc64も結構はやかったので 全体最適化としてはありなのかも?)

※追記:llvm-gcc 同様に clangも -emit-llvm で生成すると速くなる模様 (例えばbilinear拡大のは 100.9 に). が、どうも何かミスっていて正常終了できないハングするexeが作られるためちゃんと試せていない.(追記:スタックフレームポインタを保持してるはずの ebp を退避せずに汎用レジスタ的に破壊して使うコードができてる模様) (4/23追記: 試したのはbilinearのだけだが、最近のclang(1.5 trunk 102038)で試したら修正されてるようで動作)


コンパイル不具合のメモ

  • pcc は #include で、#より前に空白が置かれていると、エラーになる場合があった.
  • 行頭に#を置けばok. #の後ろに空白が入るのはok.
  • pcc で、初期化していないグローバル or static 変数でハングする場合あり(必ずではなく).
  • char buf[10] ={0}; な感じに初期値を入れてしまうことで回避できた.
  • COINSでdhrystoneコンパイル時、 gccのヘッダを流用しているため?か、
  • stdio.hヘッダにあるstatic inlineになっていないinline関数(fget?の内部関数)が 複数のobjでincludeされてると、リンクで名前の衝突が発生. (実際に必要としたソースは1つだったので、includeを調整して回避).
  • COINS, 正常なtolower(c)で')'がらみでエラー. (interpreter_smp:マクロでtoupperを乗っ取って回避).

(とかいたけど、coinsはちゃんと環境できていない可能性もあり)





2010-3-9[火] マイナーなCコンパイラをちょっと触る

フリーでwin環境用exeが作れる、ちょっとマイナーな Cコンパイラをちょろっと触ってみた、というかインストールしてみた時のメモ.

試したのは LLVM-gcc, PCC, LCC, TinyCC, COINS。

(マイナーというと語弊のあるモノもあるけど win環境用のcコンパイラとしては、で)

LLVM-gcc

(※追記:LLVM-gccでllvmを使う場合-emit-llvmオプションとつけないとダメだったよう)

(wikipedia)

LLVM&clang は、 そのvmな仕組みとか、 オプティマイズ等の実力とか、 使用用途(appleの動向)とか、 GPL(v3)より緩いライセンスがらみとか、 いろいろ話題で今後の発展に期待大なコンパイラ(vm)、 だけど、 win環境で試すには、 mingw-msys 環境に追加する方法になっていて、 ちょっとまだ敷居が高い感じ。

また、残念ながら win 環境向けにはまだ clang バイナリは無いようなので、試せるのは gccフロントエンドのモノのみ。 (追記:clangのほうは自分でコンパイルすれば使える..ということでさらに敷居が高い)

ただ llvm-gcc側にコンパイル環境として(mingw-gccをベースにした)必要なものは一通り入っているので、mingwコンパイラをインストールしておく必要はない(あってもかまわないけど)。

設定としては、まず msys 環境が必要。 mingw本家TDM等から適当なのをインストール。
うちは 猫研pack のtdm-gcc環境を使ってるのでそこに寄生。
ここでは c:\msys にmsysがあるとする。

LLVMのダウンロード頁から以下の2つを取得

    • LLVM Binaries for Mingw32/x86 (試した時は、v2.6)
    • LLVM-GCC 4.? Front End Binaries for Mingw32/x86 (試した時は gcc-4.2)

ダウンロードしたファイルを適当な場所、たとえば
  x:\llvm-2.6 x:\llvm-gcc-4.2
に解凍したとする。(来月には2.7が出るみたいだけど、今はまだ)

msys込みで、パスを設定。

set "path=x:\llvm-2.6;x:\llvm-gcc-4.2\bin;c:\msys\bin;%path%;"

あとは、llvmc 、または、llvm-gcc, llvm-g++ を用いて、 適当なソースをコンパイル、といった感じだろう。 (※簡単にヤッたら間違ってた。追記参照)

mingw 環境のコンパイラだけ置き換えた状態のようなんで、 使い方は mingw(gcc)。 win-apiアプリの コンパイルもできるよう。 (簡単な窓を出すだけのhelloプログラムは動いた)。

速度等はろくに調べていないけれど、xorshiftのときのサンプルをコンパイルしてみたところ、inline展開が働いた時のスコアは結構よいほうだった。 ただ、inline 展開をあきらめるのがvcやg++4.4より早いようで、xorshift128あたり から関数呼出になってスコア落ちた。gcc3.4.5同様素直な感じなのかな、と。

追記: llvmとしてコンパイルするにはオプションが必要のよう. でもってコンパイラ環境がうまく設定されていないのか、一度にコンパイルできず.こちら等を参考にして

llvm-gcc -O2 -DNDEBUG --emit-llvm -S test.c
llvm-as test.s
llc test.s.bc
llvm-gcc -o test.exe test.s.s

llvm-gcc -DNDEBUG -O2 --emit-llvm -S test.c
llvm-as -o tmp.bc test.s
llvm-ld -o tmp.2.exe tmp.bc
llc tmp.2.exe.bc
llvm-gcc -o test.exe tmp.2.exe.s

て感じにしてみる(後者のほうが全体に対するオプティマイズが効くかも)

※ llc で -march=x86 を付けるとwin用でなくなるみたいでマズイのだった.

※追記 こっちでLLVM-Clangを使ってみた。


PCC(Portable C Compiler)

(wikipedia)

かって(ANSI-C以前)の Cの標準だったろう Cコンパイラで、 最近はこちらでC99化していってるらしい。 (こちらもGPLv3の影響で脚光を浴びてるかんじ?)

もともと移植性のいいモノなためか、ちゃんとwin32版も用意されている。
コンパイラ以外はgnuツールなりmingwツール/ライブラリが採用されているようだ。

こちら から、 pcc-20090818-win32.exe をダウンロード。実行してインストール。

とりあえず通常のプログラムフォルダ c:\Program Files (win64なら c:\Program Files (x86)) にインストールしたとする.
※ひょっとすると、win64でも(x86)ついてなかったかもしれないので注意.

コマンドプロンプト窓でコンパイラを使う場合は、

set "path=%ProgramFiles%\pcc\bin;%path%"

を先に実行。この状態で pcc を用いてコンパイル。

pcc --help でヘルプ表示すると ld の分しか表示されず涙目だけど、 元はunix系のccそのものだろうから、そのあたりを見ればいいのか。 (基本部分はgccが同じにしてるはずだろうからgccのを試せばよいのかも)

mingwベースなんで、winプログラムも同様。とりあえず窓helloは、

pcc w_p_smp1.c -l gdi32

でいけた。

なお、出来たexeは mingw 同様 msvcrt.dll に依存している。


PCC コンパイラのコンパイル

当初 win32バイナリの配布に気づかず、ソースにwin32用バッチがあったので コンパイルしてみてた。 ので、そのメモも。
ソース修正は1行挿入のみだけど環境設定がちょっと面倒だった。

ソースについては、こちらから pcc-cvs-100306.tgz、こちら から pcc-libs-cvs-100306.tgz をダウンロード。 展開してできたフォルダを x:\pcc, x:\pcc-libs とする。
(どうも毎日バックアップされてるもののようで日による差分は不明、最新版とればいいんじゃね、で)

ソース修正は pcc/os/win32/config.h の31行目付近の

#if !defined(vsnprintf)
#include <stdio.h>     //この一行を追加.
#define vsnprintf _vsnprintf
#endif

をコメントのように#include <stdio.h> を追加するだけ。 (あとからstdio.hがincludeされるとvsnprintf置換でバグになるため)

面倒なのは bison や flex を使うのでそれらを用意する必要があること。 幸い猫研パックのmsys に入ってるので、msys環境を用いれば済みそう。

と実際にためすと、flex がハング。msys-regex-1.dll が無いと怒られる。mingwのダウンロード頁 から regex の dll 版をダウンロードして解凍(lzmaというあまり普及していない形式なので解凍ソフト(7z)も入れたり). とりだせた msys-regex-1.dll を msys\bin にコピーしたらok。(ああ、うちのmsysはちょっと古くパックの_a004のモノなので最新で直ってる可能性あり)

vc2008 でコンパイルする場合は

call "%VS90COMNTOOLS%vsvars32.bat"

をしておき(2005なら%VS80…,2003なら%VS71…だろう)

x:/pcc/os/win32 へカレントディレクトリを移動し、

build /cl /pccsrcdir x:\pcc /pcclibssrcdir x:\pcc-libs

を実行。うまくいけば pcc.exe (とmkext.exe) が出来ているハズ。

※bison等のツールの具合によっては、build /cl のみでコンパイルできるかもだが、己の使ったバージョンの場合、bisonに(相対パスの)ファイルが見つからないと怒られた。で、絶対パス指定してみたら回避できた、という状態。

できたexeを試す場合は、配布バイナリをインストールした環境のpcc.exeと置き換えてみれば、で。


また pcc 自身でもコンパイルできる。この場合は、インストールしたpcc環境のbinへパスを通した状態で

build /pcc /pccsrcdir x:\pcc /pcclibssrcdir x:\pcc-libs

を実行.

もし pccのインストールディレクトリを c:\program files\pcc 以外にしていた場合は、build オプションとして /pccdir c:\hoge\pcc のようにインストールしたpccフォルダを追加する必要がある。win64の場合 (x86)付なので指定が必要だろう(/pccdir "%ProgramFiles%" かな)。

LCC

LCC は、こちら が大本。 コンパイラ作成の教材のような感じで、 配布されているものは、ソースのみでバイナリなし。

ただ、これをベースに使える環境にしたパッケージがいくつかあるようで

といったものがある。


こちら にlcc対応のデバッガが公開されてる。

LCC-WIN32

LCC-WIN32 は結構昔からあって、 昔試した時点で、IDE環境完備でデバッガ等の出来もよく、 言語仕様拡張や生成改善等もされていて で独自発展していたのだけれど、 今、サイトをみると頁はあるけれどコンパイラ等へのリンク等がことごとく切れてる。 一応、去年の秋はまだダウンロードできてたのだけど。 開発会社のトップページを みると権利関係が別の会社に移譲されたようなことが書いてあるようで... 現状フリー配布はなくなったってことなのかな(LCC-WIN32系のサイトをあたれば、FTPからのダウンロードがまだできるかもだけど、リンクしないでおく)。


Pelles C

PellesC もLCC-WIN32同様に IDE完備の開発環境になっている。 IDE上でSJIS入力できたり、char文字列中に表やソで\含文字を使っても 実行で文字化けせず表示されてちょっと感動。 デバッガもそこそこいい感じ。ただwatchポイントは貼れず(LCC-WIN32は出来てた)。 プロジェクト設定は DEBUG/RELEASE切り替え等はできないようで、 プロジェクトのオプション設定でコンパイラ頁とリンカ頁のデバッグ設定をそのつど 切り替えないと駄目なよう(たぶん。でも、その程度)。

当然Winアプリ作れる。(ウィザードもあり)
(あとWinCE用の開発環境にもなっている)

コマンドプロンプトで使用するときは、まず、

set "PATH=%ProgramFiles%\PellesC\bin;%PATH%"

を実行。cc を用いて

cc hello.c

といった感じ。win窓helloなら

cc /Ze w_p_smp1.c user32.lib gdi32.lib

で、とりあえず。


LCC コンパイラのコンパイル

大本のLCCはソースしかないけれど、win32様のコンパイルバッチが入ってたので 試してみた... が、少々修正する必要があった。 のでそのメモ。

試したのは v4.2 のもの。tar.gz, tar.Z, zip の3つの圧縮ファイルがあるけれど、 基本同じものだけど、ソースの改行コードが違うかも。 winなら zip のモノを選ぶのが吉。

※実は tar.gz のを使った。lburg/lburg.c ファイルのみ改行コードが lf(\0a) でなくcr(\0d) だったためコンパイラに怒られた。lfに置換して済ましたけれど、zipのを展開したらcrlfでそもそも出会わないはずの不具合だったorz

win向けにコンパイルするのには、makefile.nt を使う。 使用するコンパイラは vc. ただちょっと古いバージョン(vc6ぽい) 向けみたいでvc2008にはすでにないオプションが使われていたり。

makefile.nt の9行目付近からの

CFLAGS=-DWIN32 -Zi -MLd -Fd$(BUILDDIR)^\
LD=cl -nologo
LDFLAGS=-Zi -MLd -Fd$(BUILDDIR)^\

の部分を

BUILDDIR=.
CFLAGS=-Doutp=outP -DWIN32 -Zi -MT -Fd$(BUILDDIR)^\
LD=cl -nologo
LDFLAGS=-Zi -MT -Fd$(BUILDDIR)^\

のように修正.
-Doutp=outP として、マクロ置換しているのは、関数宣言された名前を変数名としてつかったといって怒られたため、その回避。 (outpはx86系のout命令をc用にした名前として昔からある...のでビルトイン関数かなにかの影響だろうか... とりあえずのお試しで回避できたため原因追求せず)
(-MTにしてるから-Ziいらないけど、面倒なので残したまま。逆に-MTdにするでもいいが後述の修正箇所の.lib名もそれにあわせる必要あり)

あと、etc/win32.c の

  • 8行目付近

    #define LCCDIR "\\progra~1\\lcc\\4.1\\bin\\"

    の内容を、実際にlcc.exeをインストールするフォルダに変更.
    とりあえず、お試しなので "x:\lcc42" で作業しているとして、そこを設定。


  • 20行目付近の "libc.lib""libcmt.lib" に修正する。

win32.c を見ての通り、結構、環境をハードコーディングしているので、 本格的に使うならば、いろいろ修正したほうがよさげな雰囲気。
また、この内容から、コンパイラ以外のリンカやライブラリ等は VCに寄生するスタイルのよう。

とりあえず、staticリンクライブラリが使えるエディションならコンパイル可能になったはず。

dllランタイム版でコンパイルする場合は、上記までの修正に対してさらに、

  • makefile.nt の CFLAGS,LDFLAGS の -MT-MD に変更
  • cpp/unix.c の memmove関数の定義を #ifndef _MSC_VER で挟む.
  • etc/lcc.c の extern int getpid(void);宣言を #ifndef _MSC_VER で挟む.
  • etc/win32.c の "libcmt.lib"(元"libc.lib") を "msvcrt.lib" に変更.

を施す。

で、vc2008を使ってコマンドプロンプトでコンパイル

call "%VS90COMNTOOLS%vsvars32.bat"

を実行(2005なら%VS80…,2010なら%VS100…って感じか)

作業場所が x:\lcc42 フォルダだとして、そこに移動して

nmake -f makefile.nt clean
nmake -f makefile.nt all

を実行. 上手くいけばlcc.exe,cpp.exe等が作られてる(ハズ)。

お試しは

extern int printf(const char* fmt, ...);
int main(int argc, char* argv[]) {
    printf("hello world\n");
    return 0;
}

を hello.c としてセーブ.

lcc hello.c

でコンパイル。 うまくいけば a.exe ができるので、a.exeを実行してhello worldが表示できたらokと。
※ リンカー等はvcのモノを使うので、vcコンソール環境が使える状態で使うこと.

なお、#include をせずに直接 extern でprintfを宣言してるのは、#include <stdio.h> をすると cpp.exe 実行中に帰ってこなくなったため... 追求するのは面倒なので、お試しとしては、これで終わりにしておく。


TinyCC

TinyCC は小さいCコンパイラ。 (コンパイラ本体のc,hソース行数は3万行弱)。

けど、文法は、ほぼフルスペックのC89+α(C99の一部)。 (浮動小数点数も構造体もビットフィールドもあるし long long もある, らしい)

とりあえず、サイトからwin用のバイナリを取得して、適当な フォルダに展開。とりあえず、c:\tcc にいれたとする。

set "PATH=c:\tcc;%path%"

でパスを通して、あとは tcc hello.c のようにしてコンパイルするだけ。 winアプリも出来るよう(examples/hello_win.c )
※ランタイムとしてmsvcrtを使用の様.

すごく、あっさり使えてしまう代物のよう。


※実は試すまで、この作者のotcc の延長のモノかと思ってた。 舐めてました。すみません。 otccのほうはwin用でなくlinux用の 1000行に満たない小さいソースのKR-C系ミニ言語. 実行ファイル生成. (IOCCC 2002優勝らしく. 配布ではちゃんと可読なバージョンもあるのでそれをみるのも吉. それどもトリッキーですが)

TinyCC コンパイラのコンパイル

mingw-gcc を用いる。
mingw-gcc を使える状態にしておいて、 サイトから取ってきたソースのzipを x:\tcc-0.9.?? にでも展開する。

x:\tcc-0.9.??\win32 フォルダに移動して、 build-tcc.bat を実行する。exeができたら吉。


COINS

COINS についてはリンク先の概要をみるなりして。 コンパイラ研究のインフラとしてのCコンパイラが配布されてるよう。 ライセンスはApache Licene Version 2.0

モノは java で作られていて、また win環境では cygwin を使う ので、予め、それらがインストールされている必要がある。

javaに関しては、コンパイラをコンパイルするのでなければ jdk は必要でなく jre がインストールされていればよさそう。何かの折にjre6がインストール済みなのでそれを利用。
c:\Program Files (x86)\java\jre6 にインストールされているとする。

cygwin は gcc等の基本的な開発ツールがインストールされていればよく。 かなり昔にインストール済みなので、新規インストールについては他のサイトを適当にみてもらって。 と自分の環境はしばらく更新してなかったのでsetupで更新... したら、どうも最新のcygwin環境だとCOINSはちょっと不具合がでるようで対処が必要になる.後述)
cygwin は c:\cygwin にインストールされているとする。

COINSコンパイラのインストールや使い方については、こちらこちら やその他諸々を参考に...

ダウンロードはCOINSのダウンロード頁 から、 こちらのサイトの助言にしたがい 国際(en)版をダウンロード。 (jp版は euc が使われているためツールによっちゃwin環境では不味い場合があるらしい... なおjp版だけならSourceForgeの頁 からもダウンロードできる)。
己が入手したのは coins-1.4.4.3-en.jar

ダウンロードしたファイルを(jarだけど)zipファイルとして適当なフォルダに解凍。
とりあえず、 x:\coins\ に解凍したとして、
  x:\coins\coins-1.4.4.3-en
ができているとする。

※この中には classes\ フォルダがあり中身が生成済みだったので、今回はそれをそのまま使うことにした。ソースのみ配布のバージョンなら当然再コンパイルが必要。


最新のcygwin での不具合回避のため、c:\cygwin\bin 中から gcc-3.exe cpp-3.exe
gcc.exe cpp.exe に変名して x:\coins\bin\ フォルダ作ってコピー.

こちらで紹介されてる不具合回避方法だとCOINS以外で不味い場合もあるかも(?)なので、また、今回はhello world のみの簡易なお試しなので暫定的な回避にした。


コンパイルでのコマンドプロンプトでの記述が長くなるので、次の一行をバッチにしておく。

java -class x:/coins/coins-1.4.4.3-en/classes coins.driver.Driver -coins:target=x86-cygwin,assembler=as %1 %2 %3 %4 %5 %6 %7 %8 %9

名前は coins_tc.bat として x:\coins\bin\ にセーブ。


コマンドプロンプト窓(dos窓)をあけ、pathを設定する。

set "PATH=x:\coins\bin;c:\cygwin\bin;%ProgramFiles%\java\jre6\bin;%PATH%"

※不具合回避で置換すべきexeのあるフォルダがpath検索で先に見つかるように設定。

hello.cとして以下を適当なフォルダに作成しておく.

#include <stdio.h>
int main() {
    printf("Hello World!\n");
    return 0;
}

先のバッチを使い

coins_tc.bat -o hello.exe hello.c

のようにコンパイル。出来た hello.exe を実行して、hello world が出力されたらok.

cygwin ツールを cygwin 環境以外で使うため、パス関係の警告がいろいろ出るけど無視。

もし cygwin 環境で実行したいならば、この(上記path設定の)状態で

bash --login -i

を実行。カレントがhomeに移動してるので、お試しフォルダへ再度移動。
そこで coins_tc.bat -o hello.exe hello.c を実行すれば、パス名警告は減る(無くなる)かも。


コンパイルして出来上がったexeは、cygwinのgccのライブラリをリンクしているだろうで、当然、その制限をうける。


(※だめもとでmingw環境でコンパイルしたらやっぱり駄目だった。リンク関係でいろいろ無いと怒られる。けど、そのへんの問題だけなのかも?)


その他

  • hello world頁をどうこうしようと思ってやり始めたが面倒になってあきらめ... が、折角試した分くらいは、で書いたのがこの頁。
  • vc,bcc,dmc,watcom はとりあえず、いろんなサイトあるし。
  • Fail-Safe Cというモノもある模様。win用はなさそう?で、cygwinで試しみるも失敗。(どちらかというとocaml関係に振り回される時間のほうが多くorz)
  • COINSしたくてcygwinも使ったが、cygwinだとunix系のモノが試せてしまい、前行のようにダークサイドへ突入...で疲れたので止め。ポート済み以外はみないですまさないと... TenDRAはないのかな。
  • 試して無いけどwinで動くcインタプリタとして Ch とか CINTとか
  • Under C++ とか、 その他諸々以外とある模様。





2010-2-13[土] unittestの作成メモ

D言語の unittest に触発されて、 C++用に真似たものを作ってみたことがある.

使い方はこんな感じ

// テスト例
#include "unittest.h"

class Foo { 略 };

UNITTEST(Foo_Test) {
    Foo foo;
    assert(foo.hoge() == 1);
    略
}

// 起動ルーチン
#include "unittest.h"

int main() {
    UNITTEST_RUN_ALL();
    略
}

  • unittest.hをincludeして
  • UNITTEST()でテストを書き
  • main()の初っ端で UNITTEST_RUN_ALL() を呼び出す.
  • テスト実行の有無は、コンパイラオプションでのUSE_UNITTESTマクロの定義の有無

といった感じでヘッダファイル一つですむ. そのヘッダの中身は

#ifndef UNITTEST_H
#define UNITTEST_H
#include <cassert>

#ifndef UNITTEST_MAX
 #define UNITTEST_MAX   256     ///< 登録できるテストの数
#endif

#ifndef USE_UNITTEST            // テストしないとき.

#define UNITTEST_RUN_ALL()
#define UNITTEST(T)     template<typename D> void uniTTesT_dmy##T()

#else   // テストするとき.

#define UNITTEST_RUN_ALL()  uNITtEST_Mgr<>::runAll()
#define UNITTEST(T)                             \
    class T {                                   \
    public:  T() {uNITtEST_Mgr<>::add(&test);}  \
    private: static void test();                \
    };                                          \
    static T uNITtEST_vAr_##T;                  \
    void T::test()

template<int N=UNITTEST_MAX>
class uNITtEST_Mgr {
    static unsigned tblNum_;
    static void*    tbl_[N]; //関数ポインタの配列だとvcが落ちたorz.
public:
    static void add(void (*fnc)()) {
        if (tblNum_ < N)
            tbl_[tblNum_++] = (void*)fnc;
        else
            assert(0 && "too many UNITTEST.");
    }

    static void runAll() {
        for (unsigned i = 0; i < tblNum_; i++)
            ((void (*)())tbl_[i])();
    }
};
template<int N> unsigned uNITtEST_Mgr<N>::tblNum_=0;
template<int N> void*    uNITtEST_Mgr<N>::tbl_[N];

#endif  // USE_UNITTEST
#endif  // UNITTEST_H

テストしないときは、
UNITST_RUN_ALL()マクロは 空なので main()で何も実行されず、
UNITST_TEST(T) マクロは 関数テンプレートを定義するが 使われず実体化しないので、コードは生成されない。

テストをするときは、
uNITtEST_Mgrクラスが定義されてる。
こいつはstaticメンバーだけで構成していて、 テスト関数へのポインタの配列とその数、 テスト関数をポインタ配列に登録するadd()関数、 登録された関数をすべて実行するrunAll()関数、 がある.

UNITST_TEST()マクロは、ファイルstaticのclass変数を定義にすることで main()実行前にコンストラクタが実行され、 そのコンストラクタ内でテスト関数へのポインタを UnitstMgr::add()で登録している.

グローバル変数のコンストラクタの実行順番は不定なので、Mgrの管理する変数はそれらよりも先に初期化されている必要がありstatic変数にしている(ので登録可能なテスト数/配列サイズも固定)

そして main()関数の開始時点で、uNITtEST_Mgrにテストがすべて 登録済みなので、UNITST_RUN_ALL ( UnitstMgr::runAll ) を実行すれば、テストが全て実行される.

わりと単純にすむ、というか、すませてる.
main()で1文とはいえテスト用に呼出す必要あるし、 テストの最大数を決め打ちする必要があるのは無粋だけど.


まあ、実際に使おうとすると、assertだけでなく、各種チェック用のマクロがそこそこほしくなるし、多少なりとはいえ、経過メッセージをだしたりエラー数カウントしたりしだすと、すぐ1桁以上大きくなってしまったけれど.

[これ]


こんな "オレ仕様" でなく CppUnit なり Google の gtest なり boost のモノなりを 使い慣れたほうが生産的だろうけれど、 慣れる以前に面倒そうで手が出せず、 こんなものを作ってしまった、と (ターゲット環境で使えるものがほしかったてのもあり)

ただ色々付け加えた後に、ひさしぶりに元の(上記の)ソースみると、 蛇足だったかなあ、という気にもなる.

※そういや、グローバルのコンストラクタって処理順保証なしだから マルチスレッドでばらばらに実行される可能性ってあるのかな? (当然そうだと今のままでは破綻)




2010-2-5[金] Win環境でのSTLport 5.2.1のインストールのメモ.

前回の試しで、STLportの結果がよさげだったので VC以外のコンパイラでも試してみたくなり、とりあえず dmc 用を インストールしてみようとしたのだけどハマった。

VC用はググればインストール例あるし configure.bat --help やって、指示通りにすればできるようで一番お手軽だった模様.

まあ付属ドキュメント読まずに適当にやるでは不味かった. 読めば書いてた. でも英語なんで翻訳ソフトでちまちま... 悔しいので適当に気になるところだけ訳ぽくしてみた (わからないところを雰囲気で適当にしてたりするので、ちゃんと元のを参照のこと)
README.windows, README.msvc, README.mingw, README.dmc, build_system.txt,
(最近の修正が反映されてない文章もままあるので注意)

ようは、mingw,dmc,bcc 用を作る場合は、Msys 環境が必要. またmsys版でなくMingw32版のgnu make が必要そう. →dmc,bccが目的でもmingw入れちまうが吉かも.

  • コマンドライン版コンパイラが使えるコンソール窓を用意.
  • msys環境(sh)環境へ遷移(msysフォルダ下のmsys.bat実行)
  • STLport-5.2.1を展開したフォルダ直下の configue 実行
  • build/lib フォルダ下で ming32-make 実行. (できたライブラリを STLport-5.2.1/libへコピー)
  • build/test/unit フォルダ下でming32-make実行.
  • build/bin のテストexeを実行.
  • stlportを使うコンパイラ環境の設定.

て感じか.

以下、作業メモ. ただし、あまりうまくいってません。


※watcom c++ 用の build 環境は用意されていない模様.
(古い記述からするとターゲット名vc6で出来そうに思えたけど結局駄目だった)
※追記: openwatcom の wiki で stlport 5.1.5 のコンパイル済みのモノが実験物として置かれている模様. (ただ dll版のみの様)

http://www.openwatcom.com/index.php/User:Cmeerw


※2013-05追記: やり残し感を成仏させるため今更ながら コッチ で watcom , dmc 向けの修正をしてみました。

mingw,dmc,bcc共通

といいつつ基本 dmc しか作業できてないので...

configue実行だけど、MSys環境で

configure --use-compiler-family=???

な感じで ??? に gcc, dmc, bcc を設定.('='も忘れずに、と). 必要に応じてその他オプションも併記して.

configureやったあとに build/lib/ で

mingw32-make -f ???.mak clean
mingw32-make -f ???.mak depend
mingw32-make -f ???.mak ターゲット名

のような感じでメイク.
(bccの場合はmakeのほうがよい? 少なくともcleanは mingw32-make でエラーでて make を使えばokだた)

ターゲット名で install を指定すればallコンパイル&libへのコピーだが、dmcではエラー. また、all は dll(shared)版しかコンパイルしないようなので、結局自分の必要なものを 指定するのが無難そう. (このへんコンパイラごとに事情が違う)

mingw32-make -f ???.mak release-static dbg-static stldbl-static

な感じに、必要なものを列挙してメイク(指定できるものはコンパイラごとに事情が違う).
できた obj/???/*.lib を STLport-5.2.1/lib/ とかにコピー.


あと、テストのコンパイルだけど、日本語環境だとソース中のフランス語文字が壊れたSJIS扱いで怒られるかもで、

ctype_facets_test.cpp 430 付近の'で囲まれた文字を'\xE7'に書き換え

ておく(怒られたのは vc だっけ)

build/test/unit/ に移って

mingw32-make -f ???.mak

で、STLport-5.2.1/bin/にテストプログラム生成、 できた exeを全て実行、出力でエラーがなければok ...なんだが、 エラーでてるかも. ロケール関係ぽいので、とりあえず、あきらめ.


stlportのヘッダや出来たlibを利用するる場合は、 各IDEやコンパイラごとの環境設定するなり、 makefileやプロジェクトファイルごとに設定するなり.


適当に端折ってるので、不味かったらいろいろ試す、で.
ちゃんと使う場合は、configure時のオプションや、 ソースのconfigヘッダ等で、いくつか環境にあわせた設定をしたほうがそさそうです.
(テスト試すところまでで、力尽きた)

dmc

dmcは、ビルドする前に、 dm/bin/ にある link.exe, lib.exe をコピーして
dm_link.exe, dm_lib.exe
を作り、pathの通ったところにおいておく必要がある.

また、makefile の修正が若干必要かもで、
build/makefile/gmake/dmc.mak 111行付近の -p128 を書き換えて

release-static : AR += -p256

のようにする. (256は適当にえらんだ. これでもおこられるならさらに大きくか)

リンク時に文字化けした警告がでてるのが気になるが、libできてるようなんで 気にしないでおく.

ただコンパイル途中で

nbytes=65664, ph_maxsize = 65520
Internal error: ph 1854

なんてエラーがでるかもだが... 出たらあきらめ orz
(-HPでおおきな値設定しても駄目だった)
test/unit でのメイクの hashテストか何かで発生した.
ので、test/unit未確認.

stldbg-shared のコンパイルでも出るかもだが、 dll版は興味ないので放置した (先に static 版のコンパイルをしてあると コンパイル通ったかもだが、それでいいのかで)


コンパイル環境の設定については、dm/bin/sc.ini の INCLUDE,LIBの先頭に

INCLUDE=c:\STLport-5.2.1\stlport;…元の文字列…
LIB=c:\STLport-5.2.1\lib;…元の文字列…

みたいな感じに追記するのも手.
(CD版の dmc の場合、DMが配布している4.5.? の stlport が入っているかもだが、 バージョン違ってファイル名等微妙に違うので、下手に上書き等はしないのが無難)

あるいは、己は、元のと新規とを使いわけたいので 元のsc.iniでは行末に置かれていた %INCLUDE%と%LIB%を先頭にもってきて

INCLUDE=%INCLUDE%;…その他の元の文字列…
LIB=%LIB%;…その他の元の文字列…

のようにして、コンパイラ環境設定のバッチで INCLUDE,LIBの設定を切り替えるようにしてみた.


で、とりあえずいけるはずなんだが... 試しにコンパイルしてみたら .lib が見つからないと怒られた. リンク時の引数で stlport_static.lib とかを指定したらとりあえずリンクできたが、 自動リンクされなかった. ヘッダみるかぎり.libは自動リンクされるはずなんだが. なにか設定抜けてそうだが未調査.

mingw

とりあえず上記でstatic版のみ作れた. dll版は、 リンクエラーがでたので放置. (使ったmingw環境の設定等があわなかったのか?)

test/unitのはコンパイルできて実行できたと思う.

できたlibを使ってのテストは何もしていない状態.
(パスとかオプション設定とか README.mingwみてると面倒そうなんで)

bcc

bccの場合は bcc32.cfg と ilink32.cfg の -L に psdk のpath(???/lib/psdk とか)が 抜けていたらそれを追加.

とりあえずdll版は作成できるけど、tlibで怒られてしまいstatic版は作れてない(未調査) でもって bcc v5.5.1 のせいかテストでコンパイルできず.. 面倒になったので挫折. (readme.bccもちゃんとみてないので)

その他のテキスト

インストールに関係ないけど、気になった文章の適当訳も.

README.utf8, stlport_namespaces.txt,


Academic Free License ("AFL") v. 3.0 なファイル

makefile 弄ってたらふと、ファイル先頭に、ライセンスとして Academic Free License 3.0 となっていて、検索すると、stlportヘッダフォルダでも
 type_traits

ファイルが、このライセンスになっていた.

これは c++0xから増えるヘッダで、v5.2.1では、これ単体で, 他の部分では Boost 発祥の type_traits がincludeされているため、 このtype_traitsファイルさえ使わなければ、気にしなくていいのだけど...

最近の STLportの git リポジトリからとってきたものをみると、 他のソースもこの type_traits ファイルinclude するようになっていて 結構影響する状態のよう.

実質が今のライセンスと かわるのかどうか...

Wikipediav2.0の和訳をみてると、 微妙に面倒くさそうに思える...(読解力無くて読み違えてるかも...)


[2011/01/07追記] 最近の開発版のソースを覗くと、type_traits を含めAFL3.0のファイルは無くなったようで、stlportのLICENSEのみでよさそう。




2010-2-4[木] sprintf,string,stream のメモ.

去年だか一昨年ぐらいから、もうそこそこパワーあるのだから、と、 ターゲット環境でc++で string 系を使ってたのだけど、 そのとき不精して、デバッグログでも使い始めたら やたら処理落ちする箇所の原因になってしまったことがある.

ログといっても シリアル とか USB とか LAN とか経由しない、 数十KBのメモリに溜め込むだけの処理だったんで、 開発中は release コンパイルでも有効にしていて、 多少重くなるといってもI/Oからまないから大事ないと思って 見過ごしてしまっていたのだった. たしかに想定してた使用量を超えたルートができていたけれど、 それ以上に酷い重さに化けていた.

もちろんログをとってることが問題ではなくて、 string系の文字列をつかって記述で楽して

dbgmsg = strFmt("%s (%d) :",fname,line) + msg + '(' + a + ")\n";

のような感じに + 等使って、テンポラリ変数発生、メモリーアロケート発生、 が山ほど起きていたのが敗因. (↑は今適当に書いたので実際のじゃない)

文字列専用にアロケータ用意してフラグメンテーション対策はほどこして いたけど、当然速度的にはよろしいもんじゃなく. わかってみればあたり前だけど、思い込んだら、でなかなか気づけなかった.

そのときは、デバッグログからstring系一層してsprintf系で やりすごしたのだけど、 たとえば + でなく += を使えばテンポラリ無くなり アロケート頻度は落ちるし、 キャパシティをある程度コントロールしてアロケート発生させなければ、 書式なしの文字列連結ならsprintfより速くなる 可能性だってあるはず.

文字列連結を一個一個指定することになって記述が面倒だけど ... iostream系の << なんかはやってること的には += と似たようなものの はずなんだよね.

などと思うと、stream関係って、実は速度的に 悪いもんじゃないかも、って気がしてきたのだった.

て、ことで、例のごとく、ちょっと計測してみた.


test1:

    sprintf(buf, "%s(%d) : test> %s", fname, line, msg);

sprintf だとこんな感じになる処理を、ポインタ操作+mem系, str系, std::string, stringstream, strstream, カスタムstream 等で書いて計測.
表示ルーチンぽくしているが、計測では表示しないので、文字列生成が主な時間.

ソースはこれ, これ, これ

数値→文字列化を持っていない処理では、ltoaを用いて文字列化している.

CharAryStream は、固定サイズのchar配列に結果を書き込むだけにしたカスタムstreambufを使ったもの.
strstreamとほぼ同じだが、その存在を失念していた.で、気づいて計測しなおしたが、vc9付属のはバグがあるようなので、CharAryStreamも残してるしだい(endsの件もあるし).

string, stringstream, CharAryStream では、ローカル変数として関数内に持つ場合と、static変数にして、初期化を一度きりにしたものを試してる.
stringの場合はローカルでの使い方が普通だろうが、streamに関しては static かはともかく、まとまった出力をしている間は1つのインスタンスをずっと使いまわすようなコードになると思うので.

ということで、phenom2 3GHz環境で、vc9 と mingw g++4.4.0 での結果.
100000回の平均. 単位:μ秒.

  vc9[A]vc9[B]mingw[A]mingw[B]
sprintf 0.5401.1710.5071.036
ポインタ操作+memcpy+strlen 0.0580.2130.0740.221
strcpy+strcat 0.0870.3670.0830.298
std::stringで'+'使用 0.7272.0330.9641.270
std::stringで領域予約で'+=' 0.3390.4860.4100.544
std::string↑の変数をstatic化 0.2060.3470.1220.278
stringstreamローカル変数 2.2153.1002.1232.141
stringstream static変数 1.4602.2670.7740.852
strstreamローカル変数 1.8912.3611.3491.400
strstream static変数 0.530---0.3460.408
CharAryStream ローカル変数 1.8622.1990.9841.047
CharAryStream static変数 1.0111.3940.2860.342

[A][B] は、test_sprintfに与える引数の文字列長の違い. 文字列長が違うと、差のありようもかわるので. (一例の結果だけみて、何倍の差があるとか早とちりしないように:)

やっぱり、ポインタ活用や、strcatを用いたものはそこそこ早く. アロケートの(ほぼ?)発生しない stringの '+=' やstream系の<<も まあ早く.
(てか g++ の strstream や CharAryStream の速度ならば、 もう Cできりきりに書かなくていいやん、と)

stringstream も、多少気になるかもだが(毎度ローカル変数生成のような)下手な 書き方さえしなければ、悪い速度じゃなさそう. (VCの stream 実装がいまいちぽいが)

というか、そもそも printf 系の処理はそんな速いものでもなく...


あと、vcでの strstream は [B]の段階で[A]の文字列のままだった. seekp(0,ios::beg)が効いていない模様. 仕様把握してないので言い切れるか微妙かもだが、バグだろう. 速度的には、自前のCharAryStream と大差ないし、 strstreamを追求したいわけじゃないので放置.


test2 : 浮動小数点数を使ってみる

sprintf(buf, "%s(%d) : test (%7.5f,%7.5f)%c %s"
           , fname, line, d1, d1, ch1, msg);

s_stringstream << fname << '(' << line << ") : test (" 
               << d1 << ',' << d1 << ')' << ch1 << ' ' << msg;

double を使ってみた例. ↑で%7.5fにしてるのはstreamでのデフォルトに合わせるため.
面倒なんで sprintf, CharAryStream, stringstreamだけ、だが、vcのstlの出来がいまいちっぽいのでSTLport(5.2.1)もためしてみた.

ソースはこれ

で結果( 100000回の平均. 単位:μ秒 )

 vc9mingwvc9+STLport
sprintf 2.5832.0622.460
CharAryStream 5.0474.1222.164
stringstream 5.8463.9952.553

vc,mingwとも stringstreamがsprintfの倍くらいにばけてる. test1の結果からすると、必要以上にオーバーヘッドがある気分.
stringstream のかわりに CharAryStream(strstream) を使うのは 若干の固定費削減って感じで劇的は無し、というとこか.

で、STLport版、sprintfと大差なく... なんか速い.
仕様のオーバーヘッドじゃなくて実装の差、てことになる、か.

細かいことはあとにして、とりあえず、次.

test3 : 幅指定等

sprintf(buf, "%-24s(%10d) : test %#016llx\n", fname, line, val);

s_stringstream << setw(24) << left << fname << right
               << '(' << setw(10) << line
               << ") : test "
               << setfill('0') << setw(16) << hex << showbase << val
               << '\n';

真打:-)
printf系で楽に書ける書式が、どうしようもなく面倒になることがstream系を使いたくない 大きな理由だけれど、まあ stream への愚痴は後回しで、

ソースはこれ

で結果(100000回の平均. 単位:μ秒).

  vc9mingwvc9+STLport
sprintf 1.2351.1991.183
CharAryStream 2.1580.5290.647
stringstream 2.9391.4741.105

stream、記述のゴツさに、つい比例してしまいそうな印象をもってしまうが、 書式解析がコンパイル時の型チェックでまかなわれているため、 sprintfより速くなる、可能性がある ... vc標準は無視、したいなぁ:)

stringstreamは STLport が がんばっている、って、ことだろうけど.
(string側の出来もいいってことかな?)


test1改 : アロケート頻度.

test1 において、お手軽な範囲で、無理やり、include関係での malloc や new を乗っ取って、使用数を計測してみた. (ソースこれ追加)

ライブラリ.lib 部分になっているのは手がだせてないので、不正確すぎて、判断するには危険だが、大雑把な目安にはなるかも、で.

といっても、ヘッダのみなんで、vcは値でたけど、mingwはひっかからず.

以下vcでの1回表示のときの、表示部分でのmalloc:freeの呼び出し数.

  [A]malloc:free[B]malloc:free
std::stringで'+'使用 2:211:11
std::stringで領域予約で'+=' 1:11:1
std::string↑の変数をstatic化 0:00:0
stringstreamローカル変数 14:68:8
stringstream static変数 3:25:5
CharAryStream ローカル変数 3:33:3
CharAryStream static変数 0:00:0

vc の string 処理は 16バイトまでならstring内にバッファがあるため、 文字列長でアロケート回数が変わる.

stringstream の[A](初回)の値が多かったりfree数が合わないのは、 ライブラリ側の処理とか、あと、バッファ以外にも、 stream処理のサブクラス等の初回生成が含まれているためだろうか.

処理順の都合、stringstreamでアロケートされているけど、 CharAryStream, stringstreamの順に計測すると、CharAryStream側の 回数増えたりするので、可能なものは共通化されてるよう.

で、stringと CharAryStream のstatic変数版が 0回になっているので アロケートを極力回避しようと思えばできる、って感じ.
(面倒なんで表にしてないけれど、double使った test2 でも 0回)

stringstream は、static版でも アロケートが発生しているので、 vc版の測定結果が遅い原因だろう.

逆にいえば、g++や STLportのものは、メモリーアロケート発生させてない、 ということでよいか.


test1 追加 : WTL::CString, STLportのstd::string, の追試

やっぱり STLportのstd::stringが気になったので、test1の追試. ついでに WTL::CString の結果も. (test1書き直し面倒なんで... vc9,mingwの測定値が若干違うのも面倒で)

STLportは v5.2.1 (staticリンク), WTLは8.1のもの.

  vc9[A]vc9[B]mingw[A]mingw[B]vc+stlp[A]vc+stlp[B]
std::stringで'+'使用 1.1761.9930.9651.1970.3260.907
std::stringで領域予約で'+=' 0.4940.4400.4120.5480.2810.480
std::string↑の変数をstatic化 0.1710.3310.1260.2900.1270.355
WTL::CStringで+使用 0.8080.946----
WTL::CStringで+=使用 0.3240.463----
WTL::CString Format使用 0.8751.314----

STLport std::string の '+' での結果がこれって、何だ? って感じだ.

STLportはメモリー確保関係工夫してるようなことどっかに書いてあったと思うけど、 いいなあ.


WTL::CString は ある意味順当かな. std::string のシガラミないし設計の方向性が違い (1core環境じゃ)軽めの処理だろうで. (参照カウンタのわりと素直?な実装だし)

static 変数版を試してないのは実装的にメリットないからだけど、 かわりに Format メンバーを使ったものを併記.
Format()の実装はソースみると自前でprintf系実装しているのではなく、 ラッパー. メモリー確保のために、そこそこformat解析してサイズを求めているので、 速度的には確実に sprintf より遅くなるのだけど.(使い勝手のものだから).


結、というか、雑感

たったこれだけのお試しで結論するのも不味いという気もなくはないし、 使い慣れてない iostream系は何かぽかってないか不安もあるけど、 とりあえず.

iostream系は、それだけなら速度パフォーマンスのそう悪い仕組みでない、といったところか.
併用される他の要因で結果的に遅くなりやすいかも、だけど.

でも、実装は工夫が必要なんだろう. vcやg++のものが工夫が足りてない、というより、 STLport ががんばっているんだろうし.

stream よりも string のほうが速度ペナルティが多くなりそうだ. += じゃなくて + で楽したいんだし.

少なくとも string 使ってる奴が速度パフォーマンスを理由に stream系にケチをつけちゃいけないだろう(自戒:)

ただ stringstream は 無様に思えてきた.

strstream は完全に捨て去る必要ないよなあ、で.
strstream は ends の手間が嫌らしいだけで、 str()時、あるいはc_str()なりを新設して、取り出し時に '\0'を付加する モードさえあれば、かなり状況改善されてたんじゃなかろうか. 原理主義的な人たちは滅ぼしたい代物だろうけど、 C文字列を無視できない人間に stream 系売り込むにはベターな存在だったのかも.

vc標準の奴の性能があれなんで躊躇しちゃうけど、 速度を気にするならstrstream(かその代用品)使うのも手かも、と.
※test2,test3はコンストラクタを追い出した状態の結果なので、 コンストラクタの頻度があがるとtest1でのローカル変数版の結果に近づく わけだから気をつける必要はある.


printf系は速くないってのを再認識かな.
書式解析やargvな処理を思うと原理的に... 実装の差もあるだろうけど (大昔のbc遅い実装だった覚えが). 今回は vc, mingw ともprintf系は MS の実装が使われてるはずなので 違うsprintfだとまた違う印象になった可能性もあるだろう.

まあ速くないといっても、この程度の差で困ることは今時まず無いので 気にしないか. (printf系の使用を避けて速度アップを実感できたのは8bit,16bit機時代くらいか).

今回の結果はまさに50歩100歩といったところだし.
ただ、メモリーアロケートの発生をさけた結果なので、 それが頻発する状態はやっぱり気にしたほうがいいとは思う.

デバッグ処理で極力メモリーアロケートなんて起きて欲しくないわけだし.

もちろん、printf系だって全くメモリーアロケートしないかというと 実装しだいだし書式によってはありえるのだけれど. ただ通常極力しないように作られてるし、 デバッグで通常出す程度ならまず起きないし、で.


あと今回は文字列処理をメインにしてたから、ためせてないけれど、 コンソール出力等でiostream系が遅くなる(かもしれない)要因の一つは endl 時にバッファフラッシュの動作が含まれていることだと思う. これも今時のPCでは気にするほどのこともないだろうけど. でも、'\n'と endl を意図的に使い分ける意味もある、ってのは 忘れずに、と.



今回のソース関係のzip : [download]





<<前の5件次の5件>>