2020年4月11日土曜日

Google Code Jam 2020でのSBCLのトラブル

GCJ Round 1Aに出てメモリエラー(?)にハマってしまったのでメモ。

Square Danceのhiddenを落としてしまったのだが、ローカルでいろいろ調べても落ちるケースが見つからない。テストサブミットでしつこく調べていると、どうも入力が大きい時に無条件で落ちているようだった。まさかと思って、dynamic-space-sizeを増やしたSBCLを別に起動して投げてみたら通った。ヘッダを以下のようにする:

(unless (member :child-sbcl *features*)
  (quit
   :recklessly-p t
   :unix-status
   (process-exit-code
    (run-program *runtime-pathname*
                 `("--control-stack-size" "128MB"
                   "--dynamic-space-size" "8GB"
                   "--noinform" "--disable-ldb" "--lose-on-corruption" "--end-runtime-options"
                   "--eval" "(push :child-sbcl *features*)"
                   "--script" ,(namestring *load-pathname*))
                 :output t :error t :input t))))

必要なサイズを調べてみると

  • 1GBに設定 → 落ちる
  • 2GBに設定 → テストケースごとにgcすれば通る
  • 4GBに設定 → 一回gcすれば通る
  • 8GB、16GBに設定 → gcしなくても通る

という感じだった。

しかし、メモリ制約が1GBなのに8GBが必要なのは不可解ではある。たまに起こる現象として、使用量500MBあたりで新たにメモリを確保しようとするときに、1GB以上確保しようとしてheap exhaustedになるというのがあるが、それは2GBや4GBに設定してもだめな理由を説明していない。そもそも、roomとかで調べてもそんなにたくさんメモリを使っているようには見えないし…… ローカルでroswellのsbcl-bin/1.3.14を使っても起きない問題なので、調べるのが難しい。

次のroundの方針は迷うけれど、

  • 最初からdynamice-space-sizeを大きめに設定する。(とりあえず16GB?)
  • 1つ目のテストケースの前に(gc :full t)する。(コンパイルでけっこうメモリを使うので)
  • テストケース数が多すぎなければ一回ごとにgcする。

でいくことにする。

SBCL環境

GCJ 2020のSBCLの詳細は以下の通り:

事前コンパイルはないが、今年も長めのTLでまとめてテストするスタイルなので、コンパイル時間のぶんのロスは気にしなくてよさそう。


上の問題は不運ではあったけれど、そもそもPascal Walkをバグらせてしまったのが悪いとも言える。チャンスはまだあるので、早めに気づけてよかった。