Add call-with-composable-continuation experimentally#1259
Conversation
|
ちょっと心配になったので、ENSURE_SAVE_CONT() を戻しました。 テスト結果は同じです。 |
|
今の作りだと、複数の promptTag があった場合に、 ひとつの原因は、部分継続の実行中に、 |
|
|
私の認識もだいたい同じです。escaoePointをキープしているのも、できるだけ継続フレームのコピーを避けたいという目論見があります。継続フレームをひとつのリンクトリストで管理することになると、部分継続を呼び出した時に再コピーが必要になります。そこで、継続フレームチェイン自体はprompt-tagで終端されるぶつ切りのリストで持っておいて、escapePointがそれらの継続の断片を「つなぐ」役割にできないかなと (ひとつの継続チェインが終端に達したら、現在のescaoePointから続きの継続チェインを取ってきて続行する、というイメージです。(Gasbichler & Sperber論文で"Meta continuation" と言ってるやつに相当) |
|
一応、その考え方でうまくいかなかったことを共有しておきます。 まず、 epcont = vmcont -> prev1 -> prev2 -> prompt -> prev3 -> prev4 -> のように epcont = vmcont として継続フレームをそのまま保存した場合、 このため、 epcont = vmcont -> prev1 -> prev2 -> prompt -> NULL のように切断したところ、メモリリークはなくなったのですが、 このため、 vmcont -> prev1 -> prev2 -> prompt -> prev3 -> prev4 -> また、継続の起動時についても、 結局、これらは、共有しているリストの途中を書き換えたリストがほしくなったときに、 対策としては、(Copilot によると) |
|
詳しく見てみないとわかりませんが、私のアイディアは「継続リストは書き換えない」です。 永続データ構造を使うというのは「リストを書き換えずに再利用したい」という時の一般的な方法ですが、上の2階層リストは今回の用途に特有のやり方になっています。 |
|
なるほど、理屈は分かったような・・・ |
|
すごく長期的な希望としては、通常の継続も軽くしたいんですよね。可能な限りコピー自体を減らしたい。今もまだ残ってるGAUCHE_SPLIT_STACKフラグとかはその一部です。 今は継続も環境もキャプチャ時にヒープに移しますが、呼び出しのエクステントより長く生き延びないと無駄です。コンパイラが頑張ってエスケープ解析をしてアロケーション方法を変えるというのがひとつありますが、Gaucheではコンパイラはあまり重くしたくない。継続、環境のキャプチャ時にスタックのそこから下をポップしないヒープ第0世代として扱って、スタックが足りなくなったりグローバルGCが走るタイミングで必要な分だけコピーする、というのが基本的なアイディアです。が、第0世代ヒープを指すポインタをスタックGCのタイミングで書き換えないとならないのが大変。 |
|
|
少し見直したいので一度閉じます。 |
<<本件は、急いでマージする必用はありません。>>
call-with-composable-continuation と
call-with-non-composable-continuation を追加しました。
resetChain をなくそうとしたのですが、私にはちょっと無理でした。
partialChain とリネームして、今までと同様に使っています。
promptTag の検索に対応しました。
(ScmPromptData の情報を使おうとしたのですが、
どうもいろいろなルートで部分継続が起動されるので、
ScmPromptData の dynamicHandlers 等を使うと、
めちゃくちゃな結果になるようでした。一部だけ切り取ったり
つないだりしたら良いのかもしれませんが、ちょっとよく分かりませんでした)
Scm_VMReset() は、Scm_VMCallWithContinuationPrompt() に統合しました。
また、Scm_VMCallPC() の後半部分は、Scm_VMAbortCurrentContinuation() に統合しました。
このため、Scm_VMCallWithContinuationPrompt() と
Scm_VMAbortCurrentContinuation() の処理は、元の処理より複雑になっています。
ただ、これによって partcont.scm の reset/shift は、
SRFI-226 の本文にある定義に近い形にできました。
Fix reset/shift and eval combination problem v2 #972 と
Change vm error handling #1242 は、
本 PR に統合しました。
現状、冗長そうな関数があります。
現状、promptTag に未対応の関数があります。
new_ep() 内で save_cont() するようにしたので、少し遅くなっているかもしれない。
(これをしないと、いろいろなところで対策が必要になりややこしかった)
部分継続のループ使用でメモリ使用量が増えていく件ですが、
どうも Scm_VMCallPC() の ep->cont で継続全体を捕まえているのが原因のようでした。
Scm_VMCallPC() の ep->cont には、切り取った継続をセットするようにしたら、
変な条件を入れなくても、メモリ使用量が一定になりました。
ただ、そのために ep->cont を途中までコピーする関数 (copy_ccont_frames() と copy_ccont())
を作ったので、パフォーマンスは悪くなったかもしれない。
<テスト結果>
(1) make check ==> OK
(2) Gauche-effects の effects.scm で、
*use-native-reset*を #t にして、各サンプルを実行 ==> OK(3) 以下のメモリリークのテスト ==> OK
(出典 : http://okmij.org/ftp/continuations/against-callcc.html#memory-leak )
(これは (use gauche.partcont-meta) だとメモリリークします)
(4) Kahua の nqueen を実行 ==> OK
(5) https://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3ABugs#H-2dgngv
の pcdemo10.scm を実行 ==> OK