どうにか回復。そして日付け越え。
snapshotの10/30版が出ていたのでダウンロード。
眠くて死亡。
ダウンロード完了後、configure&makeを仕掛けて再死亡。
回復できず、もう一回休み。昨日より悪くなっている感じ。
ぐったりしながらCygwinの最新版を探った所、置かれていたようなので
ダウンロード。先日失敗したgccも何故かうまくダウンロードできる
所が謎。
で、注目のfork問題が直っているかという所ですが、取りあえず
エラーするかという所は置いといて、
以前書いたテストを試してみたのですが、Winが固まる
(正確には固まったかのような遅さ)現象は変わらず。
10月23日付けのsnapshotをダウンロードしてmakeしてみたのですが、
newlibのコンパイルでコンパイルエラー。
風邪で一回休み。一日寝て過ごすけどあまりよくならず。
mmapの件、冷静に考えてみますにホストOSでネイティブにmmap()を
実行するのはダメダメですよ。アドレスを取得したところで、
シミュレーションコアはシミュレータメモリしかアクセスできない
のですから。
で、シミュレータメモリをブロック管理して、開放ができる様に
してみました。でも、結局NGという事が判明。
2MB確保→1MB開放→2MB確保→1MB開放→....を繰り返している
ようで、結果、開放された1MBの穴は埋められる事なくどんどん
穴だらけになって行き、最後はメモリ領域不足になってしまうと
いう感じ。それにしても、少しくらい使えば良いのに2MB確保後、
すぐに1MB開放しているっぽいところが納得いかんです。
Cygwinの新しいのをダウンロードしようとするも、最新は
まだ国内のサーバーに置かれておらず。一つ前のをダウンロード
しようとした所、何故かgccのダウンロードができず。gccの
パッケージを100%取った所で、そのまま無反応状態。でも
キャンセルは可能。なんでや。
日付け越え。
gccのPPCネイティブに自力コンパイル。自力というのは、ソース自動生成
を行うgen*系の実行をppcsimを使って行ってみるというもの。
insn-attrtab.cの生成がうまくできなくてNG。メモリが足りなくなって
いるみたい。
gcc> make insn-attrtab.c ppcsim -L -a ./genattrtab.exe ../../gcc/config/rs6000/rs6000.md > tmp-attrtab.c Cannot allocate 16 bytes after allocating 4025954124 bytes
10031bd0:Syscall_NO=90 mmap(00000000,00200000,00000000)===> ret(0x00404000) 10031be0:Syscall_NO=91 munmap(0x00404000,0x000fc000) 10031be0:Syscall_NO=91 munmap(0x00600000,0x00004000)
昼頃起床。かなり微妙な体調。
ここ二週間の確認結果を元に、クロスツールのビルド方法をまとめて
みました。御参考まで。
何気にネイティブツールを生成する為に、先日の方法で
binutilsをconfigure/makeしてみたり。.exeが付くのがアレですが、
エラー無くネイティブPPC実行ファイルの生成に成功。
gas/as-newを実行してみた
所、UnknownSyscall(77)。_getrusage()。なんだこりゃ?infoを
みてみると、
- Function: int getrusage (int PROCESSES, struct rusage *RUSAGE) This function reports resource usage totals for processes specified by PROCESSES, storing the information in `*RUSAGE'.
binutils> ~/develop/ppcsim/src/ppcsim.exe -L PPC> exec objdump.exe -d objdump.exe
ppcsim.exe -L -a objdump.exe -d strip-new.exe > foo.dis
昼過ぎ起床。なんかまた調子悪げ。でも休出。
PPCクロスbinutils,gcc,glibcをクリーンインストールするテスト。
最初からやるとほとんどまる一日かかるような感じ。
glibcビルドの為のパッチを生成したり。確認したり。
何気にIJGのjpegツールをconfigureから実行してみたり。
AR=powerpc-linux-ar CC=powerpc-linux-gcc RANLIB=powerpc-linux-ranlib ./configure make
日付け越え。
先日のgcc-3.2の再ビルドは結局失敗。glibc-2.3.1pre2と同じエラー。
結論。glibc-2.2.2をどうにかコンパイルして使用する以外の選択肢は
今の所無さそう。
うーん、クロス環境のbuildについてまとめようと確認するのに
二週間くらいかかってしまってこれかよって感じ。まぁ、しかた無し
とした所か。
日付け越え前に帰着。
elf/dl-machine.cのコンパイルでエラー。それを例のごとく修正すると、
あとはエラー無しでコンパイル完了。make installでinfoのインストール
に失敗したので、それも適当に直してインストール完了。
gcc-3.2の再ビルド中。
終らず。
日付け越え前に帰着。
glibc-2.2.2とglibc-2.3.1pre2とで、locale.ccをコンパイルした
時、問題の__ctype_bの違いの部分は以下の通り。
# 81 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3 | # 75 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3 extern __const unsigned short int **__ctype_b_loc (void) | extern __const unsigned short int *__ctype_b; __attribute__ ((__const)); | extern __const __int32_t *__ctype_tolower; extern __const __int32_t **__ctype_tolower_loc (void) | extern __const __int32_t *__ctype_toupper; __attribute__ ((__const)); | # 91 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3 extern __const __int32_t **__ctype_toupper_loc (void) < __attribute__ ((__const)); <
日付け越え。
glibc-2.2.2をインストールしてgcc-3.2をbuildしてみると、やはり
libc++のmakeには成功する模様。で、glibc-2.3.1pre2でずっこけた
locale.ccをコンパイルするところを見てみたところ、少し様子が違っている
模様。-E付きでプリプロセッサを通した後のソースを見てみると、
# 75 "/usr/local/ppc/powerpc-linux/include/ctype.h" 3 extern __const unsigned short int *__ctype_b; extern __const __int32_t *__ctype_tolower; extern __const __int32_t *__ctype_toupper; : <中略> : # 43 "/tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-li nux/bits/ctype_noninline.h" const ctype_base::mask* ctype<char>::classic_table() throw() { return __ctype_b; }
Changes since 1.4: +47 -28 lines Diff to previous 1.4 (colored) 2002-09-01 Roland McGrath <roland@redhat.com> * ctype/ctype.h (__ctype_b, __ctype_toupper, __ctype_tolower): Variable declarations removed.
朝起きると状態悪化。一回休み。
gcc-3.2のbuild失敗の件。
libstdc++-v3/src/locale.ccのコンパイルで、
In file included from ../../../../libstdc++-v3/src/locale.cc:406: /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h: In static member function `static const short unsigned int* std::ctype<char>::classic_table()': /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:45: ` __ctype_b' undeclared (first use this function) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:45: (Each undeclared identifier is reported only once for each function it appears in.) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h: In constructor `std::ctype<char>::ctype(int*, const short unsigned int*, bool, unsigned int)': /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:61: ` __ctype_toupper' undeclared (first use this function) /tmp/tooltest/gcc-3.2/build2/powerpc-linux/libstdc++-v3/include/powerpc-linux/bits/ctype_noninline.h:61: ` __ctype_tolower' undeclared (first use this function)
37 #if _GLIBCPP_USE_SHADOW_HEADERS 38 using _C_legacy::__ctype_toupper; 39 using _C_legacy::__ctype_tolower; 40 using _C_legacy::__ctype_b; 41 #endif 42 43 const ctype_base::mask* 44 ctype<char>::classic_table() throw() 45 { return __ctype_b; }
昼頃起床。休出。
glibc-2.3.1pre2 という奴を拾ってコンパイルしてみました。
elf/dl-machine.cに手を入れる必要がありましたが、その他
でコンパイルエラーをする事は無く、結果的にはこれが一番
良さそう。でも、make installすると、infoの生成でエラーして
installに失敗したり。infoのinstallだけをすっ飛ばして
取りあえずインストール完了。結局、手放しでbuildできる
glibcは世の中に存在しないみたい。
そういや、時々shellが気を失って無反応状態になることが
あるらしく、configureやmake実行を放置しておくと、途中で
止まっている事がありました。forkコードに改造を入れたのが
関係しているのかは不明。
で、glibcのインストールよりも、問題はgccの再ビルドが
うまくできるかという点。.......
失敗(涙; うーむ。
KOJIさんと長電話。
メモ。文字で書くと意味がすぐ取れないなぁと思ったので
気を付けようと思った言いまわし。「○○でない」は
否定の意味「○○ではありません」として受け取れそう。では、
「○○でない?」は否定の意味で疑問形「○○ではないのではなかろうか?」
でしょうか?
それとも肯定の意味で同意を求める疑問形「○○なのではなかろうか?」
でしょうか?
昼頃起床。休出。
glibc-2.2.5のmakeで、misc/syslog.cのコンパイルがずっこける方を調査。
どうやら、/sysdeps/generic/bits/libc-lock.h内で定義
しているマクロが、2.2.2ではただの空マクロになっているのですが、
2.2.5では実体が書かれていて、それだとエラーしてしまうと
いう事みたいです。私自身がよく使う「直したら壊れた」という
状態になっているっぽい。
touch syslog.o で先に進めたところ、nss/nsswitch.cのコンパイル
エラーが発生。結局2.2.2と同じ話があるようですが、
2.2.2ではsyslog.cのコンパイルではエラーしなかったので、
2.2.5はやっぱNG。
風邪で急速に体が動かなくなってきたり.........
日付け越え。
以前makeに成功したglibc-2.2.2のgnu/lib-names.hの中身を見てみると、
sharedライブラリ関係臭かったので、--disable-sharedを外すと
gnu/lib-names.hを生成してからコンパイルを開始するという
仕掛けになっているようでした。取りあえずコンパイルが開始される
所で一度止めて、--disable-sharedを付けて再度configure&make
を実行する事で、nss/nsswitch.cのコンパイルはOKとなりました。
次に突っかかるのは、elf/dl-machine.cのコンパイルで、これは
以前直した方法で
乗り越え。それ以外で突っかかることは無くmakeは終了。
うーむ、手を入れなきゃいけないのが面倒臭い.......
何気にCygwin関連サイトをぐるぐるしていたら、
rxvtの日本語パッチ関連サイトに行きつきました。
rxvt-2.7.xベースになっているのが良い感じ。他にも色々不具合
が修正されているようです。ただ、デフォルトフォントが明朝
になっていて、私的に少々読みにくく感じたのでフォントを変更
しようとしたのですが、フォント名の指定の仕方がよくわからず。
うーむ。
一回休み。
gcc-3.2の方はconfigureに--disable-sharedを追加したら取りあえず
エラー無しにmake成功。
で、glibcのmakeを行う事にしましたが、glibc-2.2.2ではgcc-3.2には
正式に対応していないので、glibc-2.2.5をダウンロードしてconfigure
スクリプト内をチェックしてみました。3.xの文字列を引っ掛けて
いるようなので、一応対応されている模様。で、configure/makeを
実行した所、2.2.2で問題となったnss/nsswitch.cのコンパイルよりも
手前misc/syslog.cのコンパイルでコンパイルエラーになってヘコリ。
しかた無いので、2.2.2のconfigureを少し直す事して、nss/nsswitch.c
のエラー原因を探る事に。
先日の様に、
単純にgnu/lib-names.hが無くてエラーしているだけなのですが、
本当に存在していません。しかし、以前コンパイルしたものでは
ちゃんとgnu/lib-names.hが生成されているようなので、何か
手順が抜けていると思われます。うーむ。
日付け越え前に帰着。
glibcのmakeをそのままほっといたのですが、空ファイルを作った
nsswitch.oの影響と思われるリンクエラーでずっこけ。でも、
gcc-2.95.2でコンパイルしていたから.exeの付くppcネイティブ
バイナリが生成されるのは変わらなかったので、やっぱgcc-3.2
でどうにかmakeする方法を探る方が後々面倒でなくて良さそう
な気がします......いや、気のせいかも(ぉい;
で、そのgcc-3.2の方は結局libgccのmakeで使用するヘッダが
glibcのヘッダである事を期待している部分があるため、仕方なく、
今makeに成功しているglibcのヘッダファイルをそのまま使って
configure/makeしてみました。一応コンパイルエラーでずっこけて
いた個所をクリア。でもリンクで失敗。crti.oファイルが見つからない
らしい。んー、なんで?
コンパイルログを取って文字列サーチしてもcrti.oをリンクしている
痕跡が見当たらないのですが。うーむ。
雷雨の中、日付け越え前に帰着。
前はgcc-2.95.2をppcクロスでbuildしてもエラーしなかった気がする
のですが、何故かエラー終了している模様。しかたないので、
libgcc.aが出来ているのを確認してそのままmake install。
そしてglibc-2.2.2をconfigure&make。
以前makeした時は
nsswitchのコンパイルでgccがInternalエラーをぶっこいていた
のですが、今回は
nsswitch.c:37: gnu/lib-names.h: No such file or directory make[1]: *** [nsswitch.o] Error 1
一晩中鼻水生産機になってました。休出予定だったけど出来ず。
buildチェックの続き。Cygwin上でgcc-2.95.2を使用してglibcを
buildすると、一部のネイティブツールに.exeが付いてインストール
時に大量の手作業を必要とする為、gcc-3.2をいきなり使用できないか
とconfigure&makeを実行した所、libgccのコンパイルで
glibcのヘッダファイルを使用できる事が期待されていてbuild
失敗。しかたないので、gcc-2.95.2をコンパイルして、最後
.exeが付くところを事前にどうにかしておこうと思いbuildを
行ってみたところエラーしてうまくゆかず。なぜに?(汗;......
風邪が悪化し一日病人。
少し動けそうになった所でちょこーりお出かけ。
何故どの本屋にも「銃夢 LastOrder」の二巻だけが無いのか不思議に
思いつつ三巻を買ってみたり。
やっぱダメ気味なので、PPCクロスgccやglibcのbuildについてまとめ
る為の確認とかしてみたり。現在のbuildしたツールやライブラリは
エラー&リトライで組上げたものなのですが、最初からやると
うまくいかなかったりしてへこり。
何気にXFree86 on Cygwin上で
tgifをコンパイルしてみました。一応使えるようですが、
御存知の方は判ると思いますが、tgifは3ボタンマウス使用デフォルト
のソフトウェアな為、XFree86 on Cygwinで本気で使うのは
少々無理がありそうな気分。tgif関連ページを検索していて、
このようなページを発見したり。Tgifでギャル画を描く!は、
やり過ぎ(笑 あぁ、でもTgifをベースにイラストレーター風の
ソフトに仕立て上げるとかいうのはアリかも。
寒くて起床。
最後のリンクはg++コマンドを使用して行うのですが、何気に
-staticオプションを付けると開始アドレスが同じになりました。
で、実行。UnknownSyscall(173)。rt_sigaction()の模様。でも、
何者か判らず。signal関係っぽいので、取りあえず-1を返すように
スタブ実装して再度実行。簡単なシーンファイルの
レンダリングに成功(^^)v。
以前、
MegaPOVやWin版POV-Ray3.5でレンダリングしたPhotonMapを使用した
シーンファイルをレンダリングしてみました。一発目は
シミュレータ割り当てメモリが足りなくて失敗。割り当てメモリ
を増やして再実行.........
待っている間に風邪が悪化気味で死亡。
povray-3.50b> ~/develop/ppcsim/src/ppcsim.exe -L PPC> exec povray -Linclude -IMegaPov/spherecyl_for3.5.pov +W320 +H240 +A -Ospherecyl_ppcsimpov3.5.png : <中略> : Displaying... 0:01:01 Rendering line 1 of 240 o supersampled 0:43:11 Rendering line 11 of 240 ..*o.. ......... .oooooo. o supersampled 1:58:36 Rendering line 21 of 240 ..oo... ....... oo..... o supersampled 2:46:32 Rendering line 31 of 240 ..oo... ........ ..oooooo ... supersampled 3:21:58 Rendering line 41 of 240 ..oo... . ..oooo....o supersampled 4:14:47 Rendering line 51 of 240 ..oo.. ..oo*oo...oo supersampled 5:18:12 Rendering line 61 of 240 . ..ooo.... oo...oo. . supersampled 5:57:19 Rendering line 71 of 240 ....oMM@o... oo*ooo*o...o supersampled 6:32:43 Rendering line 81 of 240 ......@M... .. *ooooooo.ooo. supersampled 7:07:29 Rendering line 91 of 240 ..... ...MMMMM. o*****@@*oooo supersampled 7:46:45 Rendering line 101 of 240 ........... oooooo ...........o*@@@@@@@@@@ooo. supersampled 8:18:13 Rendering line 111 of 240 ............oooooooooo . .o@@@@M@@ooooo supersampled 8:44:08 Rendering line 121 of 240 ......ooooooooo........oooooooooooooo. supersampled 8:48:36 Rendering line 131 of 240 ...ooooooo............ooooooooooooooo supersampled 8:52:32 Rendering line 141 of 240 ooooo.................ooooooooooooooo. supersampled 9:18:43 Rendering line 151 of 240 .............oooo.................ooo.......ooooooooo supersampled 9:44:56 Rendering line 161 of 240 ..........oooo...................o..........@..ooooooo. supersampled 10:02:18 Rendering line 171 of 240 .......ooo.....................................oooooooo supersampled 10:21:27 Rendering line 181 of 240 ....................... . ..........oooooooo supersampled 10:44:53 Rendering line 191 of 240 ................. o. ...ooooooooooo supersampled 11:08:42 Rendering line 201 of 240 .............. oMM@*oooo@ . ..ooooooooooooo supersampled 11:24:43 Rendering line 211 of 240 .......... oMMMM@MM o...oooooooooooo supersampled 11:35:03 Rendering line 221 of 240 .......... ........oooooooooo supersampled 11:50:16 Rendering line 231 of 240 supersampled 11:51:03 Rendering line 240 of 240 supersampled 0 times. Done Tracing Statistics for MegaPov/spherecyl_for3.5.pov, Resolution 320 x 240 ---------------------------------------------------------------------------- Pixels: 77120 Samples: 168152 Smpls/Pxl: 2.18 Rays: 1417650 Saved: 3 Max Level: 4/4 ---------------------------------------------------------------------------- Ray->Shape Intersection Tests Succeeded Percentage ---------------------------------------------------------------------------- Box 875989 457194 52.19 Cone/Cylinder 915023 522700 57.12 Sphere 399515 263188 65.88 Bounding Box 8205875 3383525 41.23 Light Buffer 3257386 1537976 47.22 Vista Buffer 531713 365415 68.72 ---------------------------------------------------------------------------- Calls to Noise: 0 Calls to DNoise: 10 ---------------------------------------------------------------------------- Shadow Ray Tests: 722427 Succeeded: 235148 Reflected Rays: 536445 Total Internal: 26642 Refracted Rays: 496436 Transmitted Rays: 27451 Number of photons shot: 189166 Surface photons stored: 453289 Priority queue insert: 53261589 Priority queue remove: 22269685 Gather function called: 327723 ---------------------------------------------------------------------------- Smallest Alloc: 13 bytes Largest: 327688 Peak memory used: 9372215 bytes ---------------------------------------------------------------------------- Time For Parse: 0 hours 0 minutes 2.0 seconds (2 seconds) Time For Photon: 0 hours 48 minutes 0.0 seconds (2880 seconds) Time For Trace: 11 hours 51 minutes 4.0 seconds (42664 seconds) Total Time: 12 hours 39 minutes 6.0 seconds (45546 seconds)
大幅に日付け越え。
先日仕掛けたまま放っておいたppcクロスgccのmakeはlibc++も含めて
成功していた模様。make installでもエラーせず。バッチリです(^^)v
そしていよいよ本題のPOV-Ray3.5のコンパイルに挑戦。
途中、pnglib,zlib,jpeglib,tifflibのヘッダを要求されたため、
それぞれのライブラリをmakeしながら進めてリンク成功。
そしてppcsimで実行した所、いきなりunknown_instruction。
objdumpで見てみると、スタートアドレスがなんかずれていますよ。
なんで?
日付け越え前に帰着。
いやいや、CreateProcess()には入力は無いので、heapサイズの
違いでかかる負荷が変化することは無いハズ....と思い直し。
ということは、やはりWriteProcessMemory()が重いという事
以外に考えられなくなります。で、試しに、書き込みサイズを
4096byteに分割してメモリサイズに達するまでWriteProcessMemoryを
何度か実行するという「そりゃナシだろ」という方法を試してみました。
所が、このコードに書き換えた途端、先日書いたテストコードが
ウソのようにあっさり実行完了するようになりました(激汗;;;;;;
推測しますに、WriteProcessMemoryでプロセスサイズを増やしながら
メモリ書き込みを行う際、できるだけ大きなサイズを取りながら
割り当てているのではなかろうかと思います。その際、メモリ管理
テーブルをリニアサーチのような、あるサイズを
越えた途端、驚くほど遅くなるアルゴリズムで検索しているのでは
ないかと思われます。
一般的に、OSのSystemCall実行はコストの高い実行とされる為、
ブチブチ刻んでいちいち呼ぶよりは、まとまったサイズになるまで
プロセス側のメモリ領域で溜め込んでおき、一気に吐き出す
というのが普通(mallocしかりfread/fwriteしかり)だと思うのです
が、WriteProcessMemory()は例外らしいです。ふーん。
過程はともあれ、gccに限らずconfigure実行を開始すると全体的に
動きがスローになってイライラすることこの上なしだったのですが、
全然突っかかることが無くなりました(^^)。かなり幸せ。
御参考まで、
winsup/cygwin/fork.cc:fork_copy()を、
以下の様に実装しました。冗長でダサいコードですが、
結果オーライという事で(^^;
/* Copy memory from parent to child. The result is a boolean indicating success. */ #define MEMDIVSIZE 4096 static int fork_copy (PROCESS_INFORMATION &pi, const char *what, ...) { va_list args; char *low; int pass = 0; va_start (args, what); while ((low = va_arg (args, char *))) { char *high = va_arg (args, char *); DWORD todo = wincap.chunksize () ?: high - low; char *here; int blk ; int mod ; int i ; for (here = low; here < high; here += todo) { DWORD done = 0; if (here + todo > high) todo = high - here; blk=todo/MEMDIVSIZE ; mod=todo%MEMDIVSIZE ; for( i=0 ; i<blk ; i++,here+=MEMDIVSIZE ){ int res = WriteProcessMemory (pi.hProcess, here, here, MEMDIVSIZE, &done); if (!res || done != MEMDIVSIZE ){ if (!res) __seterrno (); /* If this happens then there is a bug in our fork implementation somewhere. */ system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E", what, pass, low, high, done, pi.dwProcessId); goto err; } } if( mod!=0 ){ int res = WriteProcessMemory (pi.hProcess, here, here, mod, &done); if (!res || mod != done){ if (!res) __seterrno (); /* If this happens then there is a bug in our fork implementation somewhere. */ system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E", what, pass, low, high, done, pi.dwProcessId); goto err; } } } pass++; } debug_printf ("done"); return 1; err: TerminateProcess (pi.hProcess, 1); set_errno (EAGAIN); return 0; }
一回休み。
fork()のどこで時間を食っているのか調べてみる事にしました。
winsup/cygwin/fork.cc:fork_parent()の中でくっていそうなの
ですが、CreateProcessを実行する前後のsystem_printf()
によるメッセージ出力タイミングが実行する度に異なったりして
時間関係がなんだかよく判らず。
恐らくメッセージ出力がバッファリングされている都合だと
思われます。でも、システムが硬直するところから考えると、
Win32APIの実行が契機になっているという気はしますが.....
んーー、やっぱCreateProcessが全体を止めているような気が
するなぁ。
日付け越え。
heapの増やし方調査。どうやら、malloc()一発ではダメで、
何度もmalloc()を実行すると良かったらしい。で、以下のような
テストプログラムを書いてみたところ、fork()ずっこけが再現
する場合が(確実ではない)あるようです。
#include <stdlib.h> #include <stdio.h> #define MALLOCSIZE 4096 #define BLOCK_COUNT 4096 #define FORK_COUNT 16 int main() { unsigned char *p[BLOCK_COUNT] ; int i,j ; int pid ; for( i=0 ; i<BLOCK_COUNT ; i++ ){ p[i]=malloc(MALLOCSIZE) ; if( p[i]==NULL ){ printf("malloc faild\n") ; exit(-1) ; } } for( i=0 ; i<FORK_COUNT ; i++ ){ printf("Enter fork()\n") ; pid=fork() ; if( pid==0 ){ printf("Leave fork() child %d\n",i) ; for( j=0 ; j<BLOCK_COUNT ; j++ ){ free( p[j] ) ; } exit(0) ; }else if( pid>0 ){ printf("Leave fork() parent\n") ; wait(0) ; continue ; }else{ break ; } } exit(0) ; }
日付け越え。
heapの増やし方がよくわからなかったので調査。コンパイル後の
実行ファイルをobjdumpで逆アセンブルしてみても、sbrk|brkの
文字列は見つからず。
直接sbrk()を書いて、コンパイル&実行した所、Cygwin網掛け
には引っかかったので、sbrk()を呼び出すことで実行されること
には間違い無さそう。
テストで書いたプログラムではsbrk()を実行している様子が無い
のでppcsimを実行してみた所、これはsbrk()を実行していました。
でも直接sbrk()を使ってはいないので、当然の事ながらobjdump
の逆アセンブル結果にはsbrk|brkの文字列は見つからず。
gdb上でppcsimを実行。run実行前にb _sbrkを実行してもシンボル
見つからず。b main(),run を実行し、停止しているところで
b _sbrk を実行すると、ブレークポイントの設定に成功。
(gdb) b main Breakpoint 1 at 0x401080 (gdb) run Starting program: /cygdrive/c/tane/develop/ppcsim/src/ppcsim.exe Breakpoint 1, 0x00401080 in main () (gdb) b _sbrk Breakpoint 2 at 0x61041927 (gdb) c Continuing. Breakpoint 2, 0x61041927 in _sbrk () (gdb) where #0 0x61041927 in _sbrk () #1 0x610bd6b2 in sbrk () #2 0x61046471 in sYSMALLOc () #3 0x00402259 in memal (mres=0x42d258, seg=0, size=65536) at memal.c:29 #4 0x00407f59 in create_proc () #5 0x004016a4 in init_system () #6 0x0040132b in main () #7 0x61007983 in dll_crt0_1 () #8 0x61007d71 in _dll_crt0@0 () #9 0x61007dc9 in dll_crt0 () #10 0x0041d042 in cygwin_crt0 () #11 0x0040103c in mainCRTStartup () #12 0xbff8b6e6 in _system_dlls__ () #13 0xbff8b598 in _system_dlls__ () #14 0xbff89f5b in _system_dlls__ () Error: Cannot access memory at address 0x8ee61fec
(gdb) s Single stepping until exit from function _sbrk, which has no line number information. 0x610bd6b2 in sbrk () (gdb) s Single stepping until exit from function sbrk, which has no line number information. 0x61046471 in sYSMALLOc () (gdb) s Single stepping until exit from function sYSMALLOc__FUiP12malloc_state, which has no line number information. 0x610471b6 in dlmalloc () (gdb) s Single stepping until exit from function dlmalloc, which has no line number information. 0x610485f5 in malloc () (gdb) s Single stepping until exit from function malloc, which has no line number information. memal (mres=0x42d258, seg=0, size=65536) at memal.c:30 (gdb) l 25 free(mres->mem[j]) ; 26 mres->mem[j] =NULL ; 27 mres->mem_size[j]=0 ; 28 } 29 mres->mem[j]=malloc(k) ; 30 if( mres->mem[j]==NULL ){ 31 return(MEM_ALLOC_ERROR) ; 32 } 33 mres->mem_size[j]=k ; 34 memclear( mres, j, k ) ; (gdb)
#include <stdlib.h> #include <stdio.h> #define MALLOCSIZE 0x10000000 int main() { unsigned char *p ; int i ; p=malloc(MALLOCSIZE) ; if( p==NULL ){ printf("malloc faild\n") ; exit(-1) ; } for( i=0 ; i<MALLOCSIZE ; i++ ){ p[i]=i%256 ; } printf("mem fill complete.\n") ; exit(0) ; }
昼頃起床。休出
帰りに「ヒカ碁(19)」査収。一気読み。このマンガ2〜3巻くらい
まとめて読まないと続きが気になってしかたないですよ。
_sbrk()で網掛けを行ったところ、本当に4096Byte単位で2MB分
メモリを要求していました(^^; そして、大きくなったshを
forkする為、動きがスローになってしまっている模様。しかし、
それを繰り返すとリソース不足に陥るのはやはり解せません。
なんだか追いかけているうちに、だんだんheapbaseとheaptopの区別が
つかなくなってきた(^^;
winsup/cygwin/cygheap.cc:cygheap_setup_for_child()の
CreateFileMappingなどに網を仕掛けてみましたが特にエラーせず。
このAPIの戻り値で「#define ERROR_ALREADY_EXISTS 183L」が
戻る場合があるらしいのですが、一番最初のhFileに
INVALID_HANDLE_VALUE を指定がしていされていると、
新規のファイルマッピングオブジェクトを生成するようなので
問題なさげ。ただ、ディスク容量が足りないと「ERROR_DISK_FULL」
を返すようですが、それはチェックされていない模様。
戻り値のハンドラもNULLが返るという事なので、その先で
NULLを食って正しくずっこけるからOKという説はありそうですが。
うまくいったりいかなかったりする所を見ると、何かヘンなもの
を食わせているか、プロセス動作タイミングの時間関係が
ずれたりとかそんな感じがしなくもないですが........
それよりも、そもそもC++ライブラリを入れる事が目的だったのに、
脱線してCygwin本体を調べるところまでずらされているのですが、
たまにうまく通ったその先でコンパイルエラーになっている
事の方が深刻かも(汗;
heapが大きくなっていることでforkが重くなっているようなので、
簡単なテストプログラムで再現しないか考えてみました。
所が、heapをどうやったら消費できるのか判らず(汗;
単純にmalloc()で巨大なメモリ割り当てを行ってもちっとも
_sbrk()に触れていない模様。
#include <stdlib.h> #include <stdio.h> int main() { unsigned char *p ; int i ; p=malloc( 2*1024*1024 ) ; if( p==NULL ) exit(-1) ; for( i=0 ; i<3 ; i++ ){ int pid ; pid=fork() ; if( pid==0 ){ printf("pid=%d\n") ; exit(0) ; }else if( pid> 0 ){ continue ; }else{ exit(-1) ; } } exit(0) ; }
964958442 [main] bash 1810511 _sbrk: sbrk= 4096 ( 86016) 964959198 [main] bash 1810511 _sbrk: sbrk= 4096 ( 90112) 964967021 [main] bash 1810511 cygheap_setup_for_child: cygheap_setup : 0 586 [unknown (0xFFE21A49)] A 1810511 _sbrk: sbrk= 4096 ( 0) 1724 [unknown (0xFFE21A49)] A 1810511 _sbrk: sbrk= 0 ( 4096) 5421 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0 164921 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020 815 [main] A 1958811 _sbrk: sbrk= 4096 ( 4096) 1345 [main] A 1958811 _sbrk: sbrk= 0 ( 8192) 175780 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32 176274 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16 176727 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096 177116 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100 177901 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936 400044 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512 401165 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0 pid=-2121000100 564904 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020 155 [main] A 1835655 _sbrk: sbrk= 4096 ( 4096) 620 [main] A 1835655 _sbrk: sbrk= 0 ( 8192) 573620 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32 574070 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16 574505 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096 574857 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100 575614 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936 581351 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512 582231 [main] a 1810511 cygheap_setup_for_child: cygheap_setup : 0 pid=-2121000100 745800 [main] a 1810511 fork_parent: C:\TANE\DEVELOP\CYGWIN\TEST\A.EXE: 00000020 597 [main] A 1835471 _sbrk: sbrk= 4096 ( 4096) 1644 [main] A 1835471 _sbrk: sbrk= 0 ( 8192) 754260 [main] a 1810511 fork_copy: pass 0 : res= 1 s= 32 done=32 754772 [main] a 1810511 fork_copy: pass 1 : res= 1 s= 16 done=16 755235 [main] a 1810511 fork_copy: pass 2 : res= 1 s= 4096 done=4096 755760 [main] a 1810511 fork_copy: pass 3 : res= 1 s= 1100 done=1100 756638 [main] a 1810511 fork_copy: pass 4 : res= 1 s= 20936 done=20936 978652 [main] a 1810511 fork_copy: pass 5 : res= 1 s= 226512 done=226512 pid=-21210001002002/10/05
昼頃起床。
winsup/cygwin/fork.cc:fork_copy() にはあまり見る所が無くなって
来た感じがしたので少し捜索範囲を広げてみたり。因みに、
先日のエラーコード183は以前に実行されてWinAPIの結果っぽい。
というのは本来ならエラーしたときにその詳細を知るために
見るという手順からいくと、実行自体が成功しているなら見なくても
良いからという気がしてきたため。でも、エラーしたときだけ
コードを入れなくても、エラーしなければエラー無しというコード
を入れてくれれば良い気がしなくもありません。真相は不明。
本屋でWin32APIのリファレンス本を買って来たり。
winsup/cygwin/fork.cc:fork_parent() のCreateProcess()を
疑ってみたり。以前、ppcsimでスレッドを使用したときに
スレッド上で初期化されるグローバル変数に別スレッドから
アクセスに行って死ぬなんて事がありましたが、それに似た
現象が起こっていないか疑ってみたため。
CreateProcess()自体はプロセスを生成すると、すぐに
戻ってくるという事なので、プロセス自体が生成されたばかりで
準備中のところにWriteProcessMemory()がぶつかってしまった
のではなかろうかと疑ってみました。CreateProcess()の後ろに
Sleep(100)(100ms)とか入れてみたのですが、特に何かが変わる
といった感じではなさそう。因みにデバッグコードを仕込んで
実行すると、エラーしないでうまくいったりする場合があったり
してイマイチ。
先日2MB程度の領域確保で死ぬか?と書いたのですが、この2MBは
heap領域のサイズ(pass 2がそれ)の様で、逆に たかだかshで
2MBもheapを使うか?という点に疑問が移ってきたのでそこを
狙って追っかけてみることにしました。
網をかけて眺めていた所、通常は80kB〜150kBなのですが、
ある点を境にいきなり2MBになるようで、実際にこの2MBの
heapサイズでforkが始まるとカーソルが動かなくなるなどの
副作用が発生するようです。
winsup/cygwin/heap.cc:_sbrk()に網を仕掛けて調査してみる
事にしました。newlibのmalloc()での割り当て単位は
4096Byteのようで、それ以下での要求は無いようです。また、
Cygwinのsbrk()システムコールではサイズにマイナスを入れる
場合にも対応されているようで、不要ブロックはOSに返す
ように実装されているようです。Win32API的には
VirtualAlloc/VirtualFreeを使用して実装しているようです。
取りあえず_sbrk()が実行されたら要求サイズと現在のheap
サイズを表示してみることにして実行してみた所、
再現しなくて失敗。うーむ。
ハングらかしてSCANDISKだったりMATRIXを観たり。
日付け越え。
エラーメッセージの「Win32 error 8」の8はGetLastError()の
エラーコードと同じものを示していることが判明。
/usr/include/w32api/winerror.hを見てみると、
「#define ERROR_NOT_ENOUGH_MEMORY 8L」という事らしい。
ちゅうことは本当にメモリが足りないとのたまわっている
らしい。むぅ、なんでだ?確かにforkずっこけが起こると、
Meadowはメモリが不足しているという旨のエラーを出して
起動失敗するので、システムがおかしくなっている事は
確からしいのですが......
因みに183は「#define ERROR_ALREADY_EXISTS 183L」という
事らしい。勝手な想像ですが、データの転送先プロセス
が既に消滅しているときにこうなるのかしら?てゆーか、
そんな事あるのか?
日付け越え。
-O0にしてCygwinコンパイル。なんか微妙に状況が変わるけどエラーずっこけ
は変わらず。
日付け越え前に帰着。
先日のCygwinのコンパイルは成功。そんな感じでデバッグコードを
少し仕込んで再コンパイル。そして実行した所、
662372290 [main] sh 1759717 fork_copy: user/cygwin data pass 1 failed, 0x47C000..0x483570, done 30064, windows pid 4293173107, Win32 error 0 662382288 [main] sh 1759717 fork_copy: user/cygwin data pass 2 failed, 0x9F0000..0xC0A000, done 2203648, windows pid 4293173107, Win32 error 8 662385344 [main] sh 1759717 fork_copy: user/cygwin data pass 2 failed, 0x9F0000..0xC0A000, done 0, windows pid 4293173107, Win32 error 8
台風のため早めに帰着。
何気に買ったまま置いといた「GRADIUS III and IV」のベスト版
などをやってみたり。やっぱむずいわ(^^;
IIIもIVもアーケードでは全くやった事がなかったりします
(何故か置いてある所が少なかった)。IIIの出た'89頃というとシューティングゲーム
は上手い人とそうでない人との差が付いて、結局 難しくなる方向に
進んで行った辺りだと思います。それと比べると、
今の弾幕系シューティングって最初の方は結構遊べるように
思ったりして。スーファミ版のIIIは結構やった記憶が
ありますが、あれはゲームバランスがEasy気味に調節されてて
(オリジナルがハード過ぎるというのはおいといて(汗;)
結構遊べた記憶があります(上上下下.....が使えたという説はありますが(^^;)。
IVは怒首領蜂とか弾幕系シューティングが幅を利かせ始めた
頃に出たと思いますが、すぐ無くなっちゃいましたよね(ぉい;
でも弾の出が悪く、素っ裸だと全く歯が立たない、それが
GRADIUSって感じなのかも知れません。
そんな感じでIIIの1面をクリアするのにえらい苦労した所
のTANEでした。でも「あぁ、これこれ、GRADIUSって感じ」だから
「こういうもの」だと思ってプレイしてたりする自分(笑。
ふと思ったのが、折角のBEST版なので、オマケで全面ノーミス
リプレイデータとか入れてくれると良かったのになぁなどと贅沢を
言ってみたり。IIIだと見るだけで1時間くらいかかりそうですが(^^;
Cygwinのconfigure/makeについて検索してみた所、
このようなTIPSページを発見しました。
どうやらconfigureの実行方法に暗黙の了解があるらしい。
configure使ってずっこけると訳わからないので、
ソースと同じディレクトリで実行できないならconfigureの最初に
自動的にディレクトリを掘ってその中で実行するように
しといてくれれば良いのに。何の為のシステム自動検査
スクリプトなんだか。ぷんぷん(ぉ
configureの実行終了後、make実行.......うまくいってそう
な予感。