<<20082010>>

2009-11-2[月]

実は仕事辞めました。 正確には今月末なんですが。 で今日は送別会してもらいました。 今までありがとうございました>職場。 プレゼントのPSPGOはわりと(ry。




2009-11-20[金] go言語

話題のgoogleのgo言語、おもしろそうですね。
ネイティブコード吐し、 ケン・トンプソンとかロブ・パイクとかの名前で釣られます。
結構、わくわくです。始めてD言語を知ったときと同様に。
でもって、いろいろな失望もD言語と同様:)
まあこれから変わっていくんだろうけど.

とりあえず、確かにC言語系だけれど、perl以上に似ていない。
java,C#等のC系しか使ったことない人だと詐欺に思うかも。

でも、javaやC#が、C/C++ユーザーの習慣に妥協した、 型宣言やビット演算子の順位等の'不味い仕様'の部分にも手をつけていて、 基本的な部分での記述量を減らす工夫が多々あり、

  • 名前 型 順の宣言になってるとか、
  • 型も*intのようにCと逆(英語の語順?)だったりとか、
  • 変数宣言が初期値からの型推論されるのは当然としてさらに :=で簡略表記できるとか、
  • 関数が複数の値を簡単に返せるとか、
  • ビットクリア演算子&^が追加されたりとか、
  • ビット演算子の順位が&,&^,<<,>>が*,/,%と同位、|,^が+,-に同位になってたりとか(<<8+bが合法)、
  • 制御文if 条件式 {文} で{}必須で条件に()不要だとか、
  • while,do while 無しで高機能な for を用意したりとか、
  • packageのアクセス制御指定を名前の先頭が大文字(公開)か小文字(非公開)で設定できたりとか、
  • スレッドを簡単に生成できたりとか

C風というには、あまりに思い切りがいいです。結構好みです.

ビットクリア演算子は、ビット演算が敬遠されるご時勢にいれてくるのは、 執念か何かでしょうかね. 関数の他値返しも今風だけれどタプルなんてクッションも無く... アセンブラからCに移った人のボヤキがよみがえってきたり.


プログラムの分割については、 公開/非公開の制御を classベースでなく package ベースのみ、ってのもばっさり感があり.

指定方法が、名前の先頭文字が、 大文字なら外部(public)公開、小文字なら内部(private)、 というネーミングルール強制というのもそうだし.

構造体メンバー変数についても、構造体固有のアクセス制御ができないだけで、 メンバー変数名の名前の大小文字で、packageレベルでは行われる。 もちろん同一パッケージ内の他の関数からも丸見えですが、 このへんはD言語での同一ファイル内の非メンバー関数をfriend扱いするのと同じ考え方でしょうね.

パッケージの規模を大きくしすぎず設計しろよ、ってことで.


クラス関係は C++やjava等のclassがもつ(継承とかの)強力さをあえて抑えることで、 必要以上に強力な機能を濫用して発生してた複雑さを軽減しようって感じでしょうか.

継承はないけど struct のメンバー関数は、struct宣言と同一package内なら 別ファイルでも宣言できるので、既存のパッケージのstructの拡張がわりと容易のよう.

... と、まあ、見てるとわくわくするのですが、

  • GC必須とか、生ポインタ演算無しとか、
  • ロウレベル・プログラミングを捨ててかかっている. (もちろんそれがメリットでもあるんだけれど)
  • ジェネリック(template)関係がない.
  • 内/外やポイント先に対する読書制御(const,mutable)が無い。
    D言語も最初は無しですまそうとしてたけど
  • 結局D2でconst,immutable指定するようになったし、 スレッドを思うと要求あるような. (で、個人的にはデフォconstでmutable指定のほうが)

なあたりで、様子見な感じになってしまうのでした. (例外が無いのは個人的にはok)


ちょこっと弄ってみましたが、 package のコンパイルは、 同一packageのソースはコンパイラに一度に指定する 必要があるぽい。

6g foo.go foo_sub.go

逆に違うパッケージは一緒に指定しちゃダメ.

生成されるオブジェファイルは .o 等と違い go 固有の情報を含んでるみたいで import "foo" で参照されるファイルはソースじゃなくて .6(.8) のよう.

なんで、依存関係を考慮した順番にコンパイルしないとダメかも... D言語での rebuild や bud 相当のツールがほしいところです.

GCCベースのほうはどうなのかは未見.




2009-11-23[月] ひさびさにD言語

ひさびさにD言語を触ってみました。
サイトぶらぶら見るだけならたまにしてましたが、 実際にコンパイラ更新したりIDE入れたりは数ヶ月ぶり、 サンプル数行とはいえコード弄るのは数年ぶりかも.

まあ、Goの影響です:-)
これからだろうGoに比べれば、 D2の文法やライブラリの整い具合は結構いい感じに思えてしまうのですよ。

ただ問題はデバッガ.
IDEもいいのあればそれに越したこと無いけど、 デバッガ無視で評できるものでもなく.
一応 dmd 専用の Ddbg がでてて、 大昔(5年前)にくらべりゃそこそこ改善されてる模様。
で、どの程度のものか、と.

とりあえず dmd2 2.036, dmd1 1.051 入れて、

  • Eclipce3.4+Descent
  • Code::Blocks ( nightybuild)
  • 楽したいのでやっぱりIDE入れて ちょろっと試そうとして...案の定シクハクする羽目に.

Ddbg

Ddbgは本家のダウンロードページにある v.0.11.3beta をダウンロード。
※ トップページにリンクされているv.0.11.3betaは 実はv.0.11.2betaという罠.

普段はIDEから使うだろうで、その場合は大丈夫でしょうが、 一応、dmdコンパイル・デバッグ時に pathの通ってるフォルダに インストールしておくのが無難な気はします. (というか以下、パス通した状態で設定してるので、下記ideの設定で パス抜けの可能性もなくはなく)

Eclipse+Descent

Eclipse+DescentでのD環境は、Descent本家とかこのへんとか見ながら設定.

試してみると、EclipseのC環境(cdt)とかに比べるといかにも無理やり間借してる感じで、ちょっとわかりにくいです。

IDE本来の設定項目名の場所でなく、 外部ツールとしてdmdリビルドツールを登録、という形になるので、 ソース依存関係や構成の管理はIDE側じゃなく、 登録するツール任せ。 なので、RebuildやBud等のD専用リビルドツール使うのがベターってことのよう (面倒でよければ自分でmakeなりバッチなり書くのでも).

デバッグ実行は、生成されたexeファイルの右クリックメニュー の'デバッグ'の中のAplication1とかを実行. (他のメニューのデバッグを押してはだまされたり:)

eclipse自体に慣れていないので、適切かどうかは別として なんとかデバッグ実行できるようにはなりました。

で、一応、

  • ソースレベルデバッグ(step in,out,over)
  • 変数表示、
  • コールスタック表示、
  • プログラムのブレークポイント機能

ができてそこそこな感じなんですが、 ウォッチ・ポイント(データのブレークポイント)が貼れない... Ddbgのコマンド一覧見ても(またソースでgdbのwatchコマンド探しても) 無かったので、Ddbg自体が未対応のようなんでしょうね。

他にも変数表示がおかしい場合があるとかバグもちょこちょこあるようで、 あともう少しなんとかなってほしい感じなんですが... Ddbgの開発一年以上とまってるぽいのがなんとも残念.

Code::blocks

Code::Blocksはdmd対応なんで、 最初からほとんどそろってますが、dmd実行パスとかデバッガ(ddbg)の 設定等、やり直してあげる必要が何箇所かあります。

(以下、dmd自体はデフォルトのc\dmdかc:\dmd2にインストールされているものとして)

  • setting→compiler & debugger... →select compiler
    で Digital Mars D Compiler を選び
  • Toolchain executables →program files で、
    • コンパイラのディレクトリを修正.
      dmd.exe等を含むbin\フォルダのあるフォルダなので、
      C:\dmd2\windows や C:\dmd\windows
      のようにwindows/フォルダ付に.
    • デバッガの設定を Ddbg_gdb.bat に変更する.
    • 他はたぶんそのままでok.
      (上からdmd.exe,dmd.exe,dmd.exe,lib.exe,ddbg_gdb.bat,rcc.exe,make.exe)
  • Additional Paths に、Ddbg.exe,ddbg_gdb.batのあるフォルダを追加.
    (既存のパスの通ったフォルダにいれてるなら、たぶん不要)
    • 同様に dmc環境 c:\dm\bin も追加しとく(ほうが何かとよいかも?)
  • Linker settings のライブラリディレクトリを修正.
    bin同様現状windows/が抜けているで、c:\dmd(2)\windows\lib のように.

  • また、使用したnightybuildの場合、D1,D2用2つのパス設定が かかれてましたが、 実際に登録したdmd.exeに対応する版のみにして使わないほうは削除.
  • , Search directories にあるimportディレクトリを確認修正.
    これも、nightybuildの場合、D1,D2用2つの設定が入っているかもだけど、
  • 実際に登録したdmd.exeに対応する版のみにして使わないほうは削除. (2つあると、import関係おかしくなることがあった)
  • Compiler and debugger settings をokで終了.
  • メニューのProject → Build Option → Linker settings → Other linker options
    -g を追記. これがないとDdbgでデバッグできない。
    (exeのリンクとしてdmd.exeを指定してあるが、あくまでリンカー扱いなので、
  • Compiler settings側のオプション指定は反映されない ...)

さすがに対応ソフトなので、素直に操作できます。
出来ることは、Descentと同様の一通り+α(現在行まで実行とか)て感じ。

最初、変数表示が watch(監視)ウィンドウで行えることに気づけずてっきりないのかと はやとちりしてましたが、あったので安心. (IDE ドッキングできていい感じ). (ただ watchpoint=データ・ブレークポイントは, ブレークポイント・ウィンドウで 設定できますが、Dではやっぱり機能していませんでした)

 

winでD2したかったので dmd + ddbg でしましたが、 D1でよければ gdc + gdb(gdc対応?版) という選択もあり... 面倒なんで手がまわりませんが。 ldc とか D.net とかもあって、どんな感じになってきてるのでしょうね. D.netは、以前試したときは、 D.netコンパイラ自身のコンパイルはすんなりすんだけど、 .netの事情わかってないので (単純すぐにvs環境で使えるわけじゃないようで) リッチなのかプアなのかよくわからず.




2009-11-26[木] 〔D言語〕Ddbgの再コンパイル

Ddbg(Descent,CB)を使って変数表示がおかしくなるのは、 どうも Ddbgコマンドの lsv が使われた時みたい... なので、そこそこ状況限定されるから、なんとなくバグとれそうな 気がしてしまったで、 ソースのsvnリポジトリr1094 をみると実は公開exe(v.0.11.3)よりも新しいv0.12(2008-3-26)のソースがコミットされているようなのでした。 (コミットログにはbasic hardware breakpoint support-minor changesと)

で、とりあえず Ddbg をコンパイルしてみたのですが... そこはD言語、やっぱり泥沼にはまったのでした。

Ddbg 自体はD1で作られていて、 最新のD1でコンパイルしても今まで見過ごされていたバグが 検出される程度(すぐ修正可能)だったのですが、 問題は、bud とパーサージェネレートに使われてる Apaged.

budはエラーがでるため、apagedは配布サイトにソースしかないため、 ツール自体の再コンパイルを行ったのですが、まさにドツボ。
dmdのバージョンやtangoのバージョン等罠にはまりまくりで、最終的には断念。

結局、budについては、ソース構成割り出してバッチで処理, apagedに関してはふと apaged.exe を検索したらこちらで見つかったので それを用いることでなんとか.

ただ apaged 自体の文法に変更があったり、 ジェネレートされたルーチンの関数引数が変わってるため Ddbg側もそれに合わせて必要だったり、と結構疲れました.

あと win32 bindingも、今のdmdだと依存関係でひっかかり、ちょっと嫌な修正. udis86-1.4部分もたいしたことないけど (こいつも perl でソースジェネレートとかあって、それをさけるため) makefile若干弄ったりとか.


で、肝心の Ddbg lsv のバグですが、
ddbgcli.d の evalScopeSymbols() 内

StackSymbol[] locals_args = scope_sym.symbols.stack_symbols;
auto psym = cast(ProcedureSymbol)scope_sym;
if  ( psym !is null )
    locals_args ~= psym.arguments.stack_symbols;
foreach ( sym; locals_args.sort )
{

の部分で、関数内ローカル変数一覧に関数引数変数を追加して ソートし出力してるのですが、locals_args がコピーでなく実体 を指しているため、追加&ソートにより scope_sym.symbols.stack_symbols が 破壊されてしまっていたようです.
(main(char[][] args) { int i=0; ... } て感じに引数が中のローカル変数より 若い名前だと、デバッガの変数一覧で args が複数表示され他の変数がなくなる、 という状態)

とりあえず .dup つけて

StackSymbol[] locals_args = scope_sym.symbols.stack_symbols.dup;

で直るよう.
(.dup抜けって D言語の落とし穴の代表例の一つだよなあ、って気も)

弄った Ddbg をさらしておきます.

[download]

※どうも元配布のDdbg.exeは実行ファイル圧縮されているぽくexe小さいのですが、これはそんなことしていないので、ちょっと太めです.


ついでにbudのバグもメモ.

文字列インポートとしての import("file.txt") に未対応のよう.

source.d の void doImport (in string pFileText, inout int pPos) 中の

bool	first = true;                             //@@@
while ((lSavedPos = pPos,
        lCurrentToken = GetNextToken (pFileText, pPos)) !is null
           && (lCurrentToken != ";"))
{
    if ( lCurrentToken == "(" && first) return;   //@@@
    first = false;                                //@@@
    if ( lCurrentToken == ",")

のwhile付近に //@@@ の処理を追加すればとりあえずなんとかなるぽい.
(あとbuild.d (1450) のreturnの戻り値不要)

(自分のコンパイルしたexeを使って出るエラーの原因が不明なんでexe無)


と書いててて思い出した.

dmd自体の仕様変更かバグかしらないけど、 ddbg の再コンパイルではまった件として、-Jsrc 状態で import("cli\ddbg_help.txt") が使われてもソース無いって起こられてた.
とりあえず -Jsrc\cli にして import("ddbg_help.txt") にすることで回避.




2009-12-2[水] Unicodeコンソール関係の適当メモ

unix/linux系なら、過去互換気にしなければ普通utf8環境.

winだと一応(たぶんnt系. 少なくともw2k以降の) dos窓にて

chcp 65001

とすれば、文字エンコードをutf8にした環境に (あるいは chcp 65000 とすれば utf7環境に) はなる.

ただし、文字フォントが日本語ファイル未対応なので、そのままだと文字化けする. こちらのサイト等みて レジストリ設定すれば日本語表示可能になる.
("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" に名前 "0." で文字列値"MSゴシック" (か何か日本語フォント名)を設定. cp932のままのdos窓のプロパティでMS ゴシックを選択、そのあとchcp 65001で切替. ただ何度か失敗するかも? 一度os再起動したほうが無難のよう)


で表示はなんとかなるが、問題は、日本語入力(IME)が使えない. 日本語環境とみなされていないよう. CP932でのみ判定してるのか、DOS標準コマンドのヘルプが英語になる. (当然sjis依存ツールは文字化けなんで、それに比べれば十分マシだけど).

os標準の入力(MS-IME)が出来れば、もっとutf8コンソール普及するかも? (Win7は未確認だけどたぶん)


utf8環境での、言語(国)の判定は win32apiだと

LCID GetUserDefaultLCID();

で判定可能。LCIDでの日本は1041. (他にも何か判定方法はあったような気はするけど、これが楽かも.

C標準ライブラリの場合 setlocaleはあれど getlocale なんてのはないので標準的な判定はなし. (そもそもsetlocaleの引数/戻値はosによって設定する値が違うので、移植性を考えよう無い)
追記: os環境の情報ではないけれど、setloacleの現在値については、setlocale(type,NULL)で情報取得できるので getlocale 相応があるといえばある状態.

unix系だと環境変数LANG みれば... iconv とか gettext とか用いるが普通?


オーソドックスなコンパイラなら、ソース中のマルチバイト文字(というかSJIS)対応をするオプションを立てずにutf8でソース書けばok (のはず).
がvcは不明. vc はソースの文字エンコードにかかわらず 実行バイナリに対してはcharはマルチバイト文字, wchar_tはunicode(utf16)に変換されるが、 char型の文字エンコードを切り替える方法がわからない. cl のオプションには見当たらず (プロジェクトのプロパティのは単にライブラリヘッダに対するdefine). コンソールをus(chcp 437)やutf8(chcp 65001)にした状態でclでコンパイルしてもexeはsjis.


winでsjisコンソールのままプログラム内部の処理をutf8にした場合 問題になるのは

  • コマンドライン引数
  • コンソールに対する入出力.主に標準入出力、標準エラー出力(stdin,stdout,stderr)

あたりか. もちろん通常プログラムが扱うテキストファイルはutf8でいいとして.

このためにCランタイムやライブラリを修正するとしたら、 コマンドライン引数はW系文字列で取得してutf8化すればすむだろうが、 対コンソール入出力についてはどうする?

標準入出力関係だけならば、fileno(fp) が 0,1,2 なら標準入出力エラー出力だろうで、 決めうち変換する? (freopenとかやられると不味いそう?)

win系コンパイラ(vc,mingw,dm,bcc,watcom)ならio.hにfileno(),_get_osfhandle()があるだろうで、

FILE   fp    = stdout; //fopen("hoge","rb");
int    fno   = fileno(fp);
HANDLE hFile = _get_osfhandle(fno);
DWORD  type  = GetFileType(hFile);

として type == FILE_TYPE_CHAR ならコンソールだろうとして、扱えばいいか (LPTは微妙)

コンソールのコードページ判定は

GetConsoleCP();        // コンソール入力のコードページ
GetConsoleOutputCP();  // コンソール出力のコードページ

でできそうなので、utf8(65001)以外ならその文字エンコードに変換してから出力すれば... FILE関係, io.hな_open関係 にごっそり手を入れる必要があるのでやってられないけど(可能性としては).


utf8化することでSJISに対し

  • 使える文字がSJISより増える. 多言語対応が楽.
  • \ (0x5c)問題が回避できる

が、SJIS(DBC)だと基本的に 1バイト文字は半角、2バイト文字は全角、になるので 固定フォントによるテキスト表示をバイト数で桁あわせできて楽だったのが、utf8だと、単純にできなくなる.
mbc,utf8未対応の(海外)ソフトを日本語対応するならばmbc(sjis)で行うほうが桁あわせやバッファサイズ調整の手間は少ないだろう. (変わりに\問題が... なんでeucjpのほうが)

ただ日本語フォントかつ SJIS範囲の文字のみを前提に決め内するならば,

  • 0x00~0x7f, 0xff60~0xff9f(半角カナ) を半角文字(1文字幅)
  • 以外を全角文字(2文字幅)

で扱うのでもいいかも.

欧州系の文字の場合半角扱いのフォントのほうが多いだろうけど、 JIS第一水準のギリシア・ロシア文字あたりは、日本系のフォントなら全角だったりして、その判定は 結局フォント別に判定が必要になってくるかも...なので、あくまでJIS漢字の範囲を前提にするならばこの程度でよいかも、と.


vcの場合fopen("hoge", "rb,ccs=UTF8")やopen("hoge", _O_RDONLY|_O_UTF8); のようにオープン時にutf8(同様にutf16)指定することが可能なよう.



D言語環境とか、mingwでの文字列をutf8ベースにする場合とかを考えてた. mingwの場合、msvcrt.dll系のdllを使うので、ライブラリ関数一部差替は ヘッダ弄ってimportやめてリンクする形できるだろうが... あるいは newlib 使ったバージョンとかはないのだろうか... とか何かと大事な作業に化けてしまうので、思うだけで終わってしまったのでした.




2009-12-4[金] pyukiwiki(0.1.7)のrss10プラグインがmixiで使えていなかった

mixiの日記設定でここを登録していたのだけれど、結構前からrssが反映されなくなっていた。以前は反映されてたのに.

この機会にちょろちょろ調べてみたところ、 こちら にらしい情報が... mixiのヘルプ見返したら、たしかに http://www.feedvalidator.org/ でチェックしろ、と.

で、どうやら

<dc:date>2009-12-03T00:00:00+9:00</dc:date> 

等の+9:00が+09:00でないと駄目なのか?

共同開発版 pyukiwiki 0.1.7 のrss10.pl をみると該当箇所は

my $date = $1 . "T" . $2 . sprintf("%+02d:00", $gmt);

となっていてちゃんと02dじゃ...いや +がついてるから+-のための桁も必要で "%+03d:00" にしないと駄目なんだろうな(perlはよう知らんがcではそうなので)

修正して試してみるとあたりだったよう. とりあえず、無理に日記移転とかする必要はなくなったかな.


(さすがに開発が止まってしまったpyukiwiki(共同開発版)を使い続けるのも 面倒になってきたのでpukiwikiなりsitedevなりに乗り換えようとローカルで 作業してて...面倒くさくなって挫折中. いっそ日記ははてなか何かに移ろうかとおもいつつ、やっぱり面倒に思えて)




2009-12-9[水] ググれるようになった

自分のサイト/ページがググって出てくるのってやっぱ嬉しいな.
いつのころからかこのwww.6809.net下のページが全くググれなくなっていた. 忙しさにかまけてサイト更新せず放置してたのだから埋もれるのは しょうがないと思ってたけど、まったく引っかからないのは???で、 robots指定関係を書き損じてたのかなとも思ったりしたけれど yahooとかMS Bingで検索すると以前と同様に見つかる。 なんかグーグル向けに不味い書き方になっているのか、 あるいは誰かになんかヤラレタのか? ようわからん。こちらをみてて、 とりあえず googleウェブマスターツール というものに登録. 新規登録されチェックも別段問題なさそう. (細かなリンクミスとかはみつかるけど) (ああsite:とかinfo:とか登録前に試しとけばよかった). でも2,3日ググってみてもひっかからず... だったが1週間ぶりに試したら見つかってくれた。ふぅ。




2009-12-10[木] C標準ライブラリのマルチスレッド対応のメモ

グローバル変数や関数内部のstatic変数、あるいはそれらにアクセスする関数は、 複数のスレッドから同時に読み書きが行われると破綻する(バグになる).

C標準ライブラリで(特にマルチスレッドセーフに作っていない場合)そのようなものは

  • グローバル変数(風のもの). stderr,stdin,stdout,stderr
  • rand, srand, strtok, tmpnam
  • stdin,stdoutを暗黙に使うモノ(printf,puts,putc,getc,scanf...)
  • errnoを書換えるモノ全般(ファイル関係:fopen,fgets,fputs,fread,fwrite,..等)
  • ロケール関係(setlocale, およびロケールの影響を受けるstring系関数,時間系関数等)
  • (malloc関係)

等結構ある.(malloc関係はちょっと別枠だけど)


マルチスレッド対応の方法としては、たとえば元が

static unsigned long rand_seed = 1;
int rand(void) {
    rand_seed = rand_seed * 1103515245L + 12345;
    return (rand_seed >> 16) & 0x7fff;
}

て感じだとすると, 雰囲気として

struct ThreadLocalVar {           // この構造体は適当
    long  rand_seed;              // rand,srand
    char* strtok_ptr;             // strtok
    char  tmpnam_buf[_MAX_PATH];  // tmpnam
    int   errno_wk;               // errno
       :
     (その他標準ライブラリが使う変数全部)
       :
};
ThreadLocalVar* get_threadLocalVar() {
    return 現在のスレッドのThreadLocalへのポインタを返す;
}
int rand(void) {
    ThreadLocalVar* p = get_threadLocalVar();
    p->rand_seed = p->rand_seed * 1103515245L + 12345;
    return (p->rand_seed >> 16) & 0x7fff;
}

といった感じに、ライブラリが内部で使う変数すべてを収めた構造体を用意してスレッド別にそのメモリを持つ. スレッドごとに独立して処理するため、他スレッドの影響が起きないようになる.

当然、スレッドの開始時にはこの構造体の初期化が必要になる.
vcでC標準ライブラリ使っている場合にスレッド生成するなら、
 CreateThreadEx でなく _beginthreadex
を使う必要があるのは、この手の初期化も行うため.

あと、上記では、適当にget_threadLocalVar()の名で中身はしょってるけど、 vcだと_getptd()、newlibなんかだと _REENT となっているので実際はそれらを みてみれば. (_REENTはちょっと意味違うものだから紛らわしかったかも)

ようは、スレッド別のメモリのポインタの取得は、 グローバル変数アクセスごとにmutex等で制御したりするのに比べれば まま軽いだろう(そこまで非効率な実装にはなってなかったよと).

ただ strtok のような本来十分に軽い処理からすれば (そうであることを前提に利用頻度が高い場合)、 スレッド別のメモリのポインタの取得は気になるかもで、 可能なら使わずにすます形にしていったほうがよいだろう.
(汎用性は落ちるけど、vcなら strtok_s, unix/linux系なら strtok_r, に 置き換えるのも手)


C++0xではスレッドローカル記憶域(TLS)が追加されるかもらしい.
もっともvcにしろgccにしろ他のコンパイラにしろ、結構すでに サポート済みのよう. (wikipedia)

そういやD言語ver2もサポートしてる. D2の場合は特に指定のないグローバル変数はスレッドローカルになる.




2009-12-12[土] ソートはPGの基礎知識...

昔(もう20年ほど前か)、os-9/6809を使っていたときアセンブラで dirコマンドを自作してソート機能をつけたことがある。 このとき最初 単純にかける(O(n^^2^^)系の)ソートで 実装していたのだけど、 公開してみたら、遅いからクィックソートにしてみたら、 と言われたのだった。 実際、差し替えたところ、 十数秒かかっていたのが3秒ぐらいになって、非常に驚いた覚えがある。 アセンブラでカリカリに書いてるから速いつもりだったんだよ。 でもそれ以上にアルゴリズムの性能が段違いにモノをいう、 ってのを身をもって教えられたのでした。

まあ、ものわかりの悪い奴なんで、 実際に経験しないと気づけないという... 本に速いと書かれているのみてても、その性能差を汲み取れてないのよね.

その後、情報処理専門でない理系の大学のプログラムの授業で ソートを習ったりしたので、PGならソートくらいは知ってて当然の つもりだったのだけど...

数年前、作るものの仕様に整列をする部分があって、 やたら見積もり時間がおおかったり難色しめしたりする子がいて、 聞いてみるとソートを知らないという。 ゲーム専門学校とはいえプログラマ・コースだったから てっきり知っていると思ったら習ったことない、と。 初めてコレ聞いたときはかなりがっくりきた。

その後ゲ専出の何人か聞いた範囲ではほとんどが習ってなかった。 習っていた子もいたけれど、 バブルソートを自分で書いたことがある程度で、 でもって、ちゃっかりそのルーチンを仕事の実機で書いてくれて、 非常に残念な気分を味わえたのだった。(己と同じ過ちを...)

これが酷いのか普通なのかはよくわからないけれど...

ソートに関しては、 簡単だけれど性能の出ないルーチンを下手に作らせるよりも (PGは自分が書いたルーチンを使いたがるものだから)、 アルゴリズムの違いの性能差をとっとと見せ付けておくほうが、 そして、標準ライブラリにはそれらを使ったstd::sort(なりqsortなり)が あることを知ってもらっているほうが、いいだろうと思う.


ソート時間を測定してみる.

ということで、かるくソート時間を計測してみとく.

実行環境は Athron64 X2 5600+ 8GB(Vista64) と Crusoe TM5400(600MHz) 256M(Win2k) なマシン.

テストしてみたルーチンはコレ.

元ネタはwikipediaやその他検索ひっかかった所から.(面倒なんでクィックソートとか単純なまま)

バブル,選択,挿入, コム, クィック, クィック+挿入(閾値32), std::sort, qsort の時間をチェック. (std::sortを呼ぶためC++でコンパイルしてるけれど他はCでの記述状態)

適当な個数のソートを何回か繰り返した平均を出している。

テスト環境は普段使っているPCのまま。 なるべく他のソフト立ち上げていないけれど、エディタやファイラは 多少残してたり常駐ソフトも残ってるしで、厳密さはなし。 時間計測も単純にC関数のclock()に任せてるので精度とかは微妙かもだし。 測定しなおすと、細かい数字は結構かわるし、たまに当たり所が悪いと余計に時間 食っていることもありそうだし。

それでも、大雑把な傾向は出てると思う.
(追記:コンパイルはvc2008で32bit版でコンパイル)
以下、結果.

Crusoe TM5400(600MHz) 256M(Win2k)環境でのint値のソート時間.(単位:μ秒)

      個数10個20個30個40個50個100個256個1000個10000個
バブル ソート 1.3624.8263.85324.63238.205110.0731148601283800
選択 ソート 1.0923.5647.37716.14026.64090.04706970825200
挿入 ソート 0.6911.9643.8376.2929.41540.02403064373500
コム ソート 1.2425.8505.0077.4129.46525.07176211000
クィックソート 1.4225.6485.5407.73210.26520.0703008000
クィック+挿入 0.7211.9843.8739.3727.06015.0402407000
std::sort 1.0012.8443.7039.29213.17020.5613008000
qsort 2.9357.61219.76326.68035.85070.017080221000

Athron64X2 5200+(2.6GHz) 8GB(Vista64)環境でのint値のソート時間.(単位:μ秒)

      個数10個20個30個40個50個100個256個1000個10000個
バブル ソート 0.2370.7381.5472.7924.11518.01041566152200
選択 ソート 0.2490.7441.4202.2803.33511.56282278300
挿入 ソート 0.1210.3060.5330.9321.1553.52131029100
コム ソート 0.2320.5540.9601.4121.8104.514761100
クィックソート 0.2800.7201.1901.6882.5305.01468800
クィック+挿入 0.1230.3000.5330.8241.1453.0942500
std::sort 0.1580.3400.5730.9961.3403.51156700
qsort 0.5241.2822.1533.1924.2159.0281302100

上から3つが O(n^^2^^)、次の2つがO(nlogn)。

10,20個程度だと、大差ない雰囲気があるけれど、 1000個とか10000個のソートになってくると O(n^^2^^)ものとO(nlogn)モノとで1~3桁 時間が違ってきてる。 (当然それ以上だとさらに差は拡大するわけで)

数が少ないときは比較的似通っているといっても、 挿入ソートは目だって速く、 上記結果だと、TM5400では int 50個程度までなら、Athron64X2では int 100個程度 までなら、コムソートやクィックソートより速い結果になっている. (もちろんCPU等環境の違いで個数は大きく変わる)

で、クイックソートは、一定個数以下になったら挿入ソートに切り替えることが 可能で、それによって速度を上げることができる.
それが クィック+挿入 の行の結果.

std::sort()も実はだいたい同様でクィック+挿入(少なくともvcのはだったはず.)。 若干遅い結果なのは汎用性等の書き方で多少オーバーヘッドがあるのか. この差が問題になるかどうかは、用途しだいだけど、 普段気にするようなレベルではないだろう.

※追記>std::sort()の実装は(普通?は) 再帰が深くなるとヒープソートに切替えるらしい. (イントロソートらしい?)

ただ、Cライブラリの qsortもアルゴリズム自体は同様と思われるが、 こちらはCプログラムでの汎用性のため (とくにintなんていう単純なデータのソートとしては) オーバーヘッドが大きくなってしまっている模様。

quick+挿入に対して、1桁違うことはないだろうが、 下手すると数倍の時間がかかったりして、結構大きい。

C言語の場合は、性能のためにあえてqsortを使わず、 自前で(コムやクィック)ソート・ルーチン用意するのは、 ありの選択.

(が、性能と手間を思うと、C++環境にできるなら とっととC++に移行してしまうのが吉かも)

※クィックソートから挿入ソートへの切替個数は、 コンパイラ付属のものにあわせて 32個にしている。 アルゴリズムの本(20年位前にかかれたもの)をみると、 CPU性能やコンパイラ性能等でかわってくるが だいたい 10~20 位、って値が示されているのだが、 最近のCPUの性能がいいのかより大きい値のほうが速いようだった.

ついでに他のソート時間を測定してみる.

ついでに、wikipediaのコムソートの説明にあったcomb sort 11 と、 数日前に流行?っていたやねうらお氏挿入ソートも試してみた。 (ちょっとはしょりすぎて100~1000の精度がいまいち...)

Crusoe TM5400(600MHz) 256M(Win2k)環境でのint値のソート時間.(単位:μ秒)

個数 10個20個30個40個50個100個256個1000個10000個
insert sort 0.6911.9643.8376.2929.41540.02403064373500
insert sort(yane)0.6811.9623.8406.36814.22040.02006230425700
comb sort 1.2425.8505.0077.4129.46525.07176211000
comb sort11 1.2823.0840.81310.93613.82025.08058211000
quick+insert sort0.7211.9843.8739.3727.06015.0402407000
quick+yane-insert0.7112.0023.8735.3687.11015.0502406100

Athron64X2 5200+(2.6GHz) 8GB(Vista64)環境でのint値のソート時間.(単位:μ秒)

個数 10個20個30個40個50個100個256個1000個10000個
insert sort 0.1210.3060.5330.9321.1553.52131029100
insert sort(yane)0.1180.3160.5800.9241.3454.52740438800
comb sort 0.2320.5540.9601.4121.8104.514761100
comb sort11 0.2310.5641.0271.4801.9454.514741000
quick+insert sort0.1230.3000.5330.8241.1453.0942500
quick+yane-insert0.1230.3220.5870.8641.1903.0942600

Athron64X2 5200+(2.6GHz) 8GB(Vista64)環境でのdouble値のソート時間.(単位:μ秒)

個数 10個20個30個40個50個100個256個1000個10000個
insert sort 0.1850.4780.8631.3401.9106.53548047100
insert sort(yane)0.1960.5020.9031.4001.9906.53549848600
comb sort 0.3100.8121.3972.1482.8407.0221121700
comb sort11 0.3140.8601.4532.2083.0206.5221081600
quick+insert sort0.1850.5020.8631.3761.9304.51466900
quick+yane-insert0.1940.5100.9071.4241.9205.01468900

comb sort11については、個数が多いときには効果あるようだけど、逆に個数が 少ないときは増えた if 文のペナルティが出るのか、遅くなってしまっている。 その効果もささいな感じなので、無理に使う必要はなさそう.

やねうらお氏の挿入ソートだけど、説明読んだときは効きそうに思ったのだけど、 結果は、よくなったり悪くなったり、で、ちょっと残念な結果でした。 いや、なんか、自分がポカやってる可能性は多いにあるのですが。 (TM5400の50個の列の値は、当たり所悪く他の処理時間が混ざったパターンぽく)

やなう版は、最内側のループの外側とはいえ、外のループの内側に if文が増えているので、そのへんが影響して、 コンパイラの最適化やCPUのキャッシュ具合、分岐予測 等、 何かバランス的にくづれて、メモリー代入のペナルティと同等か それ以上のペナルティになってしまっているのかな?

追記:こっちを書くまで気づいてなかったけど、 比較回数が1回増えてるので、コピーしないですました時間より 比較時間が増えるのが無視できないということかも. (元記事の前提と違う状態で使ってしまったとも)


その他

しらべていないけれど、 (己がかいた)クィック+挿入は、一見性能よさそうにみえるけど、 個数がある数(以上?)だと、急激に時間がふえてしまったりしていた. ちょっと困った.

あとソースをコンパイルしたexeや使ったバッチ等

ダウンロード




2009-12-15[火] ソートについて2

test1 補足

やねう版の結果がちょっと気になったので、手元ですぐ動くvc以外の コンパイラでも試してみた。
mingw32-gcc(3.4.5, 4.4.0TDP-1), dmc8.51(beta), open watcom 1.8, bcc5.82(フリーのTurboC++) あたり. (手元に残っていたものなので、最新版というわけでない)

プログラムのほうも時間計測の関数変えたり結果出力編集するの面倒だったので若干修正.
(ソース:sort_test1.cpp)

実行環境は athron64x2 5200+ 8GB(Vista64)環境.

実行結果は 1回目2回目

(だいたい似たようなもんだけれど、それなりに誤差があるので雰囲気見るために)
(あと表にはしてないけれどvcは2003,2010β2ともvc2008と同様の結果だった)


やねう版挿入ソートについては、mingw-gcc,bccの場合は効果があるよう. 他はどちらともいえない感じ。 このへんは、このテストの偶然の部分が多そうなので判別付かず.
どちらかというと gcc4.4.0 のinsert sortの結果が抜き出て悪い..これは コンパイラのバージョン上がれば直る?(駄目?). 3.4.5のほうは素直な結果に思える.

さらに quick sort の一部として使った場合の結果は、微妙.
傾向は現れてそうな感じもあるけどひっくり返ることあるし、そもそも測定誤差の振れ幅を思うと気にしても仕方ないレベルかもで.

でもまあ、基本どんぐりの背比べ、だけどよくなるコンパイラもある、んだから、汎用的に書く場合は やねう版 でいいかも、と。

(下手な書き方してでっかい要素をそのままソートする場合にはやねう版のほうが有利な気もするし)

※ と結論にしたけれど、後のtest2~は test1補足を試す前に調査してたのでやねう版になってません
※追記: こっちで結局結論変えてしまった.


ついでに std::sort。 gccやwatcomだと他の結果がいまいちのことがあっても 付属stlのstd::sortは速いので、 基本的には付属のを使うのが吉のよう. vcのは若干、bccのは結構、遅いけれど...

bccについては使ったのは数年前のもので最新じゃないし、 borlandのc++はその時々に付属するstl(の元)が変わったりするので… てみたらdinkumwareだった(VCと同じ元ネタ)...orz

※追記: std::sortの実装は単純なquick+挿入なだけじゃなくスタック溢れ対策?もあるよう.


前回もちょこっと書いたquick sortの10000000個時の時間が極端に悪くなっている件はvcだけでなく他のコンパイラでも同様のよう. スタック拡張とか何か極端なことが起こったのかとも思うけどわからず. このCソースバージョンの元にしたC++テンプレートバージョンでは10000000個実行しても正常な時間だったので、深入りしないで放置中.

※追記: vcのコンパイルオプションが不味く、スタック等のチェックルーチンが結構生成されていた. (関数分割や分岐が多いと不利だった模様). チェックを生成しない設定でコンパイルしたら、 結論がかわるほどの大きな違いはなかったけれど、 std::sort等ややねう版の結果も心持よくなったような気も.


test2 引数の数の違いの影響

関数呼び出しオーバーヘッドが性能に影響する、状況だろうから、 じゃあ、2引数版(<専用) と 3引数版(比較ファンクタ指定) でどれくらいの差がでるか、と思い、試した.(引数の数というより、ループの最内側で使われる引数で渡された'比較'が、ちゃんインライン展開されているや否や)

(ソース:sort_test2.cpp)

cでなくc++のテンプレートで実装. std::sortに引数をあわせている. また quick sort とかいているけど実際には挿入ソートを使ったバージョン. (以後単にquick sortと書いていても同様)

vcでの結果(単位:μ秒)

int 1万個double 1万個string 1万個int 1千万個double 1千万個
std::sort(arg2) 756114762779426941381667
std::sort(arg3) 748114762079571181408231
quick sort(arg2) 53183655237483001245526
quick sort(arg3) 56287355267642351236120
quick sort/bidi(arg2)55985664827812531220958
quick sort/bidi(arg3)53987056048077951252734

他のコンパイラもだいたい同様の傾向.

引数が2個か3個かの違いは、(ちゃんとオプティマイズされてたら)気になるような 差は見受けられず.
(オプティマイズ無しだと当然2引数のほうが速くなる)

てことで、実体つくるなら3引数版をつくってそれを呼び出す2引数版を作る、で よいのだろう.


表の下2つは、次のテストの前準備として軽く確認実行してみたもの.
bidiとなっているのは、引数として random iterator でなく bidirectional iterator を受け取れるようにしたバージョン(ようは std::list をソートできるようにしたもの).

イテレータの大小チェック代わりにカウンタを追加してるため、大きくはないけれど若干遅くなっているのは現れている模様.


test3 std::listのソート

(追記: マージソート失念して間抜けなことしてます..orz)

std::list のソートのテスト. 比較のため、

  • std::vectorをソート
  • std::listをquick_sort|bidi版でソート
  • std::list.sort()でソート
  • listの要素へのポインタのvectorをつくってそれをソート

してみた。
ソース:sort_test3.cpp)  (コンパイルはvc2008)

SmpClass版(mallocポインタやstd::vectorを持つ適当なクラス) (単位:μ秒)

個数10個20個100個1000個10000個100000個
vectorを quick sort 23.829101.530506.0156833.29993907.7451378442.931
list を quick sort 23.002101.610510.7477135.18898371.3011443433.383
std::list.sort 9.27223.95726.209289.9113688.17869306.364
list要素へのポインタのvectorをsort 2.3374.32219.277237.2093285.82355324.629

std::string版

個数10個20個100個1000個10000個100000個
vectorを quick sort 3.8069.11167.051580.9477106.49077688.365
list を quick sort 3.3708.54369.276625.4857640.35798245.657
std::list.sort 9.64912.03533.156372.9734950.97880472.099
list要素へのポインタのvectorをsort 2.5625.26628.576388.5694996.93482327.433

int版

個数10個20個100個1000個10000個100000個
vectorを quick sort 2.0983.19015.860228.3112789.60032882.182
list を quick sort 1.9763.29917.805269.6713953.64547324.450
std::list.sort 9.11911.07524.704252.2673489.20045217.828
list要素へのポインタのvectorをsort 2.3814.05717.913230.3646432.31237080.760

基本的には SmpClass版の結果が、実使用に近いものだと思う.

で、みてのとおり、std::list でソートしたくなったら、

 std::list のメンバーの sort() を使う

という当たり前の結論.

intやdoubleのような小さい要素で少量のときは逆転してるけど、 そもそも個数がn個程度と限定されているならばlistでなくvectorあたりでよく.

無理に bidirectional iterator を受け取れる quick sort 作ってまで やることじゃない、と.

あと、そのものstd::list自体のソートが必要なく、 途中の処理として整列された順番でデータ舐めたいだけならば、 4つ目のように、 要素へのポインタを集めてそれをソートして使うのが吉かも.


test4 大きめのオブジェクトのソート、スマートポインタのソート

普通は、大きめのオブジェクトの実体を直接ソートしない。しないですむように作る。
 整列状態で処理する箇所用に別途ポインタ配列を作ってそれをソート、
という感じ。


もっとも、大きめのオブジェクトはポインタなりハンドルなりで扱い そのまま管理/やりとりすることはないだろうで、 c++だとスマートポインタの類による管理も増えている.

じゃあスマートポインタのソートはどう?ってことで、試した.
ソース:sort_test4.cpp

以下 SmpClass (mallocポインタ,std::vectorメンバー有り)の結果(単位μ秒)

vc2008版(64バイト)

個数10個20個100個1000個10000個100000個
vector要素へのポインタのvectorのみをsort 2.7965.14721.990287.3693684.75661983.786
vectorを sort 30.635118.802648.0038777.072118188.9041659458.255
ポインタでソートして、その結果でvector再構築 11.17021.526119.5041107.96917498.802196852.603
shared_ptrのvectorを sort 4.27018.97097.1321006.03614163.602254964.388
intrusive_ptrのvectorを sort 2.3014.99428.664411.3515306.40194754.501
intrusive_ptrのvectorを生ポインタソートで再構築 3.4796.10025.769319.0494364.80176751.165

mingw32-gcc(4.4.0)版(56バイト)

個数10個20個100個1000個10000個100000個
vector要素へのポインタのvectorのみをsort 1.8722.2358.086126.0841692.53433156.449
vectorを sort 16.77971.353335.6374449.42761817.563961931.055
ポインタでソートして、その結果でvector再構築 6.66910.97370.962603.14211622.357138767.218
shared_ptrのvectorを sort 2.9537.17761.087636.1429128.046190523.935
intrusive_ptrのvectorを sort 2.2174.39725.608367.8895052.66798505.257
intrusive_ptrのvectorを生ポインタソートで再構築 2.2253.28711.059152.9732379.91145465.695

上から順に.

  • 本体のソートが不要であれば、やっぱりポインタの配列作ってソートしちまうのが一番安そう.
  • 実体の直接ソートは桁違いに時間を食うはめに.
  • 一旦ポインタ配列ソートしてからだと結構ましになる. でもポインタだけの管理にくらべれば桁がやっぱり大きい.
  • c++0xで入る予定のstd::shared_ptrの場合. 実体にくらべ小さいとは言え、生のポインタにくらべれば複雑なので、実装方法次第だろうけれど、この例ではちょっと気になる程度のペナルティが発生している感じ.
  • boost::intrusive_ptrを使った例. 生のポインタにくらべ時間は数割増といった感じで、思ったよりもペナルティは少ない感じ.
    10,20個程度だとポインタ配列を作るコストのほうが高くなることもあるのか、intrusive_ptr直ソートのほうが速くなることもあるよう.
  • boost::intrusive_ptrで管理しているものを、一旦生のポインタ配列を作ってソートし、その結果を元に返す例. 一定以上ソートするならば intrusive_ptr のままよりもこのほうが速い.


shared_ptrはいろいろ便利だけれど、やっぱりその分実行時コストがかかってしまう。 それが気にならない箇所ならいいけれど、 ソートのような場合は考えたほうがよさそう.

intrusive_ptrは、ポイント先になるクラス側に参照カウンタ処理が必要となり、 shared_ptrより使い勝手は落ちるけれど、 参照カウンタの処理自体は shared_ptr よりも素直な状態なので、 実行時コストは小さい.

で intrusive_ptr のほうは、ソート済の生ポインタをも一度intrusive_ptrに することができる(もちろん、このへん、操作をあやまると参照カウンタ管理を 破綻しかねないので注意深く...)が、 shared_ptrは生ポインタ化してソートした結果を元のshared_ptrに戻す方法が なさそう. (shared_ptrの指す先でなくshared_ptr自体のアドレスでソートすればだが不本意)


追記:比較条件が単純でソートキーが値一つですむようならば、 ポインタのみの配列でなくソートキーとポインタのペアの配列を ソートしたほうが速くなりやすいと思われる(test5)


ソース&実行ファイル

とりあえず、今回のソース等を固めたもの.

[download]




2009-12-17[木] CPU換装→AMDLLD64青画面

どうもPC組立やパーツ差替のたびにトラブルってるような... ソフマップの特価につられつい CPUを PhenomII945に換装したら、 vista起動ログイン直後に必ずブルースクリーンになってしまうのでした. (前回は9月頃MBのBIOS更新に失敗してMB交換. でもそもそも BIOS更新した理由はMBで不具合のでるGカードを買ったせい)

いやsafeモードだと問題なく.メモリテストも問題なく. BIOSはちょっと古かったので更新かけたけど変わりなく.

青画面のメッセージには amdlld64.sys(AMD Low Level Device Driver) の中のアドレスが表示されていて、こいつが犯人ぽい.

ググッたところ日本のサイトでは見つからなかったけれど、海外にちらほら. 初っ端に見つかる こち が正解のよう.

MBの種類は違うけれど、症状は同じ.
どうも vista64 にて、 AM2+なMBにAM2なCPUをつけてた人が、AM3なCPUに乗せ変えた時に遭遇 しているって感じか?

対処は、
 safeモードで立ち上げて \windows\system32\driver\AMD64LLD.SYS を削除
するだけ. 起動し直すと、とりあえずブルースクリーンはでなくなった.
( あとシステムのプロパティ→デバイスマネージャでAMD Low Level Device Driver(だかAMDLLD64だか近い名前のもの) に黄色マークがついていればそれも削除)

AMDLLD64.SYSがなくていいのかは わからないけれど、起動できないよりは、で (?別のドライバに置き換わってるのかも?).




2009-12-18[金] 夢にみたソフト

xp64で64ビットwinに移行して以来、自宅メインPCでは 16ビットdos用の exeが使えなくなっていて、 それもあって win7bisのxp付はちょっと魅力的だったりしたのですが. (いやイザとなればサブPCはw2kだし、virtualpcでwin9xという手もあるけれど)

最近ごそごそ別件で検索してたら

なるMSDOSコンソールなエミュレータが2つも開発されていた模様.

双方公開されて日が浅く... というかwin7(64)で16bit exe使えず 不便だからと作られたもののよう.

ハードのエミュレートじゃなく、dos(+α)部分のみで 入出力が仮想ドライブじゃなくて通常のドライブ(環境)のままで、 まさに、かって欲しかった(作れなかった)ソフトそのもの.

MSDOS Playerのほうは msdos.exe hoge.exe files のように単発実行できるもの. lccコンパイラ使うためってことらしく他の32ビットツールとの連携もやすそう.

VTDOSのほうはv-text環境込みのdos窓(shellコンソール)みたいなもののよう. v-text(dos/v)版のvzやfdも使えるらしい. こちらも16ビットexeだけでなく32ビットexeも呼び出せる模様. (それもあってか設定がちょっと面倒そう...己は上手くいってませんorz)

で、まあ、双方のサンプルに mg.exeって記述があって思わず笑ってしまったのでした。 (今でも触って下さってる方がいるなんてありがとうございますです)

ただ、喜んだのはいいのですが、すっかり16ビットdosツールとは 疎遠になってしまっていて、これを機に16ビットツール環境復活...したいけど,どこにバックアップしまったやら. (試すためにこのサイトの16bit-dosツールからmg.exe落としたりとちょっと間抜け)


で、折角だからfreedosからとってきたcommand.comと、こちらのos9/6809 L1 エミュレータ(v1.1)とを組み合わせて

C:\Users\myname\OS9>msdos command.com /c echo hello | os9l1 place \* world
hello world
 world

て具合に msdos(8086) と OS-9/6809 の夢の競演をさせてみました.
ほんと、どうでもいい無理やりですが^^;

※結果がみっともなく余分に worldがついてるのは、DOSの改行はCRLF,os-9はCRのみでplaceが余分なLFを最後の余りだから1行扱いしてるせいかな.

※os9l1はcygwinでコンパイルしたもの. os9l1は標準入出力以外の通常のファイルアクセス等未サポートだから、まともに動く実行ファイルがほとんどなかったり...おかげで、たったこれだけのことするのに酷く手間取ったorz



2009-12-20[日] 古PC復活メモ

(遅延書込)

最近、古い5インチFDDや3.5インチMOをサルベージしたく バラしたままだった古PCを1台復活させたが、 この手のことはやってるときは楽しく、 つい他の古PCの復活もやってしまったのだった.

pen3 800MHz前後

まずは、NetVista6842(pen3 866MHz i810E mem512MB hdd:120GB) とか NetVista6881(celeron 700MHz i810 256MB 80GB)とか Mate MA07H(pen3 800MHz 810 256MB 80GB)とか (昔中古で安いからと買いすぎた代物).

NetVistaは家用サーバーで使っていたのを引退させたものだから、 いまさらそんなモノにするのもつまらなく、 デスクトップな linux ディストリビューションを 試すことにした. あと、PCI付のNetVistaにはPCIのRivaTNT(やG400)が残っていたので、 それをつけてみた.

結論から言えば、このスペック程度でデスクトップ利用するのに 一番いいOSは、やっぱり Win2K、だろうというのが実感.

最新のwin7(rcだけど)をNetVista6842 に入れたら、
 CPU 1.3, Mem 1.4 gra 1.0 game-gra 1.0 HDD 4.6
といった感じだった.
グラフィック関係は、古くて遅い上にドライバーないのが致命的.

linux等フリーosも、グラフィックアクセラレータ対応ドライバーの有無がネックだろうか.
というか手持ちのボードや周辺機器がどの程度使えるかどうかが.
枯れたハードならlinuxとかのほうがずっとサポートされてるような 幻想をいだいてしまっていたけれど、 それはチップ情報がオープンになっていて、 かつ、それをサポートしてくれる人がいての話.

nVidiaの古いチップは、オープン(あるいは解析済)というわけでは ない模様. メーカー製ドライバは古いxに対応のものは存在しているが、 最近のXorgには未対応のよう. このために古いディストリ入れるのも楽しくないので、 また810は多少はアクセラレーション効くのかAGPx2なのがPCIよりも有利に 働くのかマシな状況だったため、結局TNT(PCI) はお払い箱にした.

ちなみに ATIのだと、数年前に情報オープンになってて最近 よくなってきているらしく、 Radeon9600gtをつけた別のマシンで試しに ubuntu(gnome) いれたときは、アクセラレーション有効になるとまずまずの感じだった (それでも検索するとメーカー製ドライバのほうがよいような記述も みかけたが、インストールの面倒を思うとフリー版でよいかと)

と思っていたら こちらの記事からすると、 Kernel 2.6.33 あたりでnVidiaの古いチップ対応がマージされるらしい? ということはもう数ヶ月まてばマシになるのかもしれない. というか、Fedoraだと今、対応済みってことなのだろうか? 気力ができたら試そう (debian系に慣れたため、他を弄る気が薄く...)

ただ、グラフィックドライバーの問題を抜きにしても ubuntuは pen3 866MHz 512MB程度のスペックで使うには重かった. (不要なプロセスも多少殺したが、いまいち)

メモリ256MBのほうに, debian+lxde や u-lite(ubuntu+lxde) を 入れたときは結構よく思えたので、 じゃあとgnome版を試したのだが、レベルが違った. あきらめたほうがよさそうだ.

日本語対応を思うと ubuntuは魅力的なんだが... u-liteになると結局日本語関係いまいちな感じになるので、ううむ.

その他 ReactOSは、うまくインストールできず. 他にもLiveCDモノもいくつか..でpuppyは結構よい感じだった(後述). 日本語整備されたものをみちゃうと、堕落してしまう

ただ結局のところ、512MBのPCはdebian入れてサーバー的にLAN接続、 他はpuppyとか入れっぱなしで放置という結果になった (放置分だれか引き取ってくれないかしらん)

puppy linux

軽いといううわさの Puppy Linux も HDDにFULLモードで入れてみたが、たしかに軽いようだ.

先のlxdeな環境に比べても、頭一つ抜き出ている印象をうける. jwmというのも軽いのだろうが、全体で上手く調整されているのだろうな. (窓移動で中身表示せず枠だけってのは遅いマシンでは嬉しい. みっともない窓描画みせられるよりか、ずいぶん印象がよくなる)

なにより日本語対応が思いのほか行われていたのがうれしい.
入っているソフトで十分なら これは、かなりいい選択なりそう.

ただ個人的には標準のファイラが好みでなかったのが痛かった.
ワンクリック動作については、こちら等いくつもの サイトでダブルクリック設定かかれていて対処可能だし、 その他の表示も調整すればマシになるが... やっぱり微妙だ.

パッケージシステムも、 基本的に1CD起動、RAMディスク運営のシステムとして 調整されているものだから、 そもそもdebianやubuntuと比べるのはお門違いなのだが、 なまじまとまったシステムのせいか(まあ面倒だし)、 ソース落としてきてまでインストールという気にもなれず.

RAMディスクベース用にロードモジュールを用意するのは、 os-9のロードモジュールを連想してある意味楽しいそうなんだが.

x,gtk+?

ubuntu(9.10)の外観の設定、では視覚効果の指定で3つの状態が選べるが、 radeon9600gtを入れたPCで試していると、 効果無しを選ぶとアクセラレーションが効いていないようにみえる. 逆に通常効果(追加効果)を指定したほうがきびきび動いてるようだ (810だと通常効果を選べなかった).

あとdebianで、ためしにmac4linを入れたのだが(窓まわりはそれらしくなったけどドック関係は失敗)、非常に激重になった. 使い物にならないのでアンインストールしたが、元どおりにならず、マシになったとはいえ描画が非常に重い状態. よくみると、窓に半透明影が残っている...非力でないPCでubuntu動かした ときはmac4linいれるまでもなく影付きなので、元々の機能でon/offできるのか? こちらをみてて

> gconftool-2 --type boolean --set /apps/metacity/general/compositing_manager FALSE

でoffできた. offできると今度はインストール前よりも速いような?気も. (アクセラレーションがきいた? わからない)

xとかgtk+,gnomeの設定がちゃんとしてあげられたら 非力なマシンでももっとよくなるのかな? このへんのところ調べたほうがよいのだろうが...疲れた.

DynaBook GT475

msdos playerとかに触発されたこともあって、 調子乗って、十数年前の win95 なnote機 DynaBook GT475(486 75MHz 24MB) も弄ってしまった.
これでも16MB増設した状態だけれど、 メモリの24MBってのは微妙だ. win95でも使うのがしんどいスペックだった. (元々は親が使っていたもの)

linux等でコンソールのみだとしても、よほど古いディストリ等でないかぎり 辛いサイズに思う(一度入れたが日本語使えないのはやっぱり嫌で)

もちろん dos/v 入れる分にはそこそこ十分だ.
実際 こちらのFreeDOS/V入れて無事起動.

HDDは元の500MBのものから、余ってた30GBのモノに付け替えた. マシンのばらし方はこちらのサイトがまだあったのでありがたく. E-IDE と表示されてるので 8G までいけるとおもいきや BIOS的には 500MBまでなのか、GT475につなげて fdisk等すると 誤った容量が表示されそのまま作業すると不味い状態.

まあBIOS で大容量HDDをちゃんと認識できなくても、 起動したosがサポートしていれば通常で利用できることが多いので、 あらかじめ 別PC で freedosにて fdisk&format (念のため起動ドライブは8GB以内の4GBに設定) してから GT475につなげたところ 4GB,24GB にアクセスはできて一安心.
※BIOSのためか fdisk だけでなくformat も大容量に対してエラーになるので 別PC側でformatまで済ませておく必要アリ.

折角だからとパーティションきってlinux等もいれようとしてみたけれど、 biosが想定外なのか grubやliloを使っても2つ目以降のパーティションからの起動が 無理のよう. ブートできないシリンダだとおこられる. 2つ目のパーティションが500MB以内にくるように 1つ目のパーティションを100MBにした状態でも駄目. なので複数インストールはあきらめて一つだけにした.

で、結局いれたのは、Win98...orz
別のマシンでHDDにインストールしたあと、 そのhddにインストールCDの中身もコピーして、 GT475につなげなおして、ハード再設定でなんとか. (swapファイルを64MB固定設定にしたり).

FreeDOS関係でなんとかしたい、と思ったが、 lfnのサポート具合のこともあるし、 ネット関係を思うと、 LANカードのドライバー等はなんとかなるにしても、 LAN内の他のPCとのやり取りの利便を考えれば 結局win機がベターなのだった. (ただwin95無印はfat32無しだしその他ドライバーが見つからず... win98で自動認識されてインストールというのが吉だった)

また、せめてtelenet端末として、と思う場合も、 utf8が使えるdos/v用の端末ソフトがあるや否や、 で、移植や改造が頭によぎりバカらしくなり.

とりあえずwin98ならば teraterm 動作ということでok.
(ほんとはMIYAZAKI師匠のrloginがよかったがnt系用だし puttyごった煮版はwin98だとstatic labelの文字化け激しく, 対処方法で示されてるフォント指定でも効かずで).

*

まあ、使えないマシンを復活させるのは楽しくここ2週間ほどちまちま弄ってたけど、 ふと我に代えると非常にむなしいもので…… 次またやってしまう率を減らすためにメモといったところ.

思い返すと古PCは osお試しインストールすることこそが 目的なのかもしれないと思えてくるが...

最近は、 メモリもCPU速度もありisoイメージ直インストールできる メインマシン上の VirtualBox での作業するほうが吉だものな.




2009-12-24[木] mg.exe LFN対応

今更ながら mg.exe を LFN対応してみた.(これ)
ちょっと試すだけでも 8.3 形式はうざく、つい、カッとなった.

が、msdos player はLFN未対応だったらしく..orz

vtdosのほうは、動いてくれた.
以前 vtdos がうまくいかなかったのは command.comをちゃんと入れてなかったからのようだ.

command.com は、PC DOS J7.0/V のCD発掘できたので、それを利用.
win95以降, freedos 1.0, dr-dos7 あたりの command.comは、 駄目だった.

しかし、ドキュメントを読む分には素でも動きそうなのだが. ドキュメントやCOMSPECを見ると vtdcmd.exe というものを実行していそうだが、 配布物の中にそのexeファイルはなく. 仮想名かもと思うが、動かないとこみると、やっぱり必要なのかも? ...が、とりあえず command.com 入れて動いたのでよしとしておこう.


(追記)
オプション指定せずとも dos環境がLFN対応しているかどうかを判別するように修正してみた.

といっても、ax=71a7h; int 21h (win32なファイル時間をdosファイル時間に変換するLFN用システムコール)を実行してみて、エラーがax=0x7100になるかどうかを 見てるだけ.
(※I/Oアクセスが発生しないLFNシステムコールならなんでもいい)
例によってろくに確認してない.

あっと、lfnのシステムコールは こちらを参考にしてます.




<<20082010>>