久しぶりにTophatをいじったら一発目でエラーで落ちてしまい,出鼻をくじかれてしまった….原因を調べてみると,どうやらTophatのコマンド実行時に指定する-pオプションの数字を調子に乗って上げすぎたのが良くなかったらしい.といっても計算機のリソースに問題があったわけではなく,ユーザが使えるシステムリソースの制限を超えてしまったために,Tophatが停止してしまったようだ.この問題はTophatの公式サイトのFAQでも取り上げられているが,このBlogでもエラーメッセージとともに原因と対策を書いておこうと思う.

Tophatの標準エラー出力のメッセージ

今回の場合は,Tophatのログの最後で以下のようなエラーメッセージが表示される.

1
2
3
4
5
6
7
[...]
[2013-06-23 00:22:33] Mapping right_kept_reads_seg3 to genome chlamydomonas_236 with Bowtie2 (3/4)
[2013-06-23 00:33:09] Mapping right_kept_reads_seg4 to genome chlamydomonas_236 with Bowtie2 (4/4)
[2013-06-23 00:44:57] Searching for junctions via segment mapping
        [FAILED]
Error: segment-based junction search failed with err =1
Error opening SAM file output/tmp/right_kept_reads_seg1.bam

これだけでは何のことだかよくわからないが,Tophatが出力するログのlogs/segment_juncs.logを見ると,このエラーに関してもう少し詳細な記述が出力されている.

1
2
3
4
5
6
7
8
9
    Loading scaffold_53...done
    Loading scaffold_54...done
    Loading ...done
>> Performing segment-search:
Loading left segment hits...
done.
Loading right segment hits...
open: Too many open files
Error opening SAM file output/tmp/right_kept_reads_seg2.bam

これを見ると,どうやらsegment_juncsの実行中に「open: Too many open files」が原因で実行が落ちたようだ.

原因と対策

このエラーに関しては,実はTophatの公式サイトのFAQに「What should I do if I see a message like “Too many open files”?」という,まさに先ほどのエラーメッセージの内容そのままの項がある.

This usually happens when using “-p” option with a large value (many threads). TopHat may produce many intermediate files, the number of which is proportional to this value; sometimes the number of the files may go over the maximum number of files a process is allowed to open. The solution is to raise the limit to a higher number (e.g. 10000). For Mac, you can change this using a command, “sudo sysctl -w kern.maxfiles=10240”.

TopHat :: Center for Bioinformatics and Computational Biology

ざっと要約すると「Tophatは中間ファイルを大量に作るから時々許容数超えちゃうんだよね.扱えるファイル数の上限上げるか,Macなら次のコマンドで対処してね」ということになる.さすがにこれだけではよく分からないと思うので,SEQanswersの以下のスレッドも参考にしつつ,もう少し詳しく見ていこうと思う.

Tophat segment junction error 1, invalid BAM binary header - SEQanswers

limitとファイルディスクリプタ数の制限

さて,公式サイトのFAQにおいてファイル数の上限といった言葉が出てきたように,LinuxやMacではユーザごとに使用することのできる各種システムリソースに制限が設けられている.具体的にはユーザが使用できるCPU数やメモリの容量,プロセスの数などがそれに該当するのだが,その中に「ファイルディスクリプタ数」という項目があり,1プロセスが同時に開くことのできるファイル数の上限を定めている.これは主にひとつの計算機を複数人が使用するマルチユーザシステムにおいて,一人がリソースを独占するのを防いだりアプリケーションの暴走を止めたりするのに役立つのだが,今回のような大規模な計算を実行する際にはこれが邪魔になってしまう.

システムリソースの制限を確認したい場合には,「ulimit -a」または「limit」というコマンドを使う.例えば,私の環境では以下のようになる.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ソフトリミット
$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-m: resident set size (kbytes)      unlimited
-u: processes                       1024
-n: file descriptors                1024
-l: locked-in-memory size (kbytes)  64
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 127413
-q: bytes in POSIX msg queues       819200
-e: max nice                        0
-r: max rt priority                 0

ここで表示されるのは厳密にはソフトリミットと呼ばれ,ユーザごとに設定されている制限である.一方でハードリミットと呼ばれる制限もあり,これは管理者(root)が定める制限となっている.ソフトリミットは,このハードリミットの範囲内でしか自由に制限値を変更することはできない.ハードリミットを確認したい場合には,-Hオプションを付ける.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ハードリミット
$ ulimit -aH
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             unlimited
-c: core file size (blocks)         unlimited
-m: resident set size (kbytes)      unlimited
-u: processes                       127413
-n: file descriptors                4096
-l: locked-in-memory size (kbytes)  64
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 127413
-q: bytes in POSIX msg queues       819200
-e: max nice                        0
-r: max rt priority                 0

さて,今回問題になっているファイルディスクリプタ数は「-n: file descriptors」で表示されている.上の例の場合,ソフトリミットでは1024,ハードリミットでは4096となっている.つまり,Tophatは1024個以上のファイルを1スレッドで開こうとしたために,このソフトリミットに引っかかってしまったようだ.

フィアルディスクリプタ数の制限への対策

この問題を回避するには主に2つの方法がある.

1.Tophatの-pオプションの値を小さくする

2.ソフトリミットのファイルディスクリプタの値を大きくする

まず1.では,Tophatが使用するスレッド数を少なくすることで,ファイルディスクリプタ数の上限に引っかからなくするというもの.一度-pオプションを無くして実行してみれば,おそらく今回のエラーには引っかからなくなるだろう.一度に開くファイル数が少なくなりほぼ確実に実行できるようにはなるが,並列処理数が減ってしまうのでTophatの実行時間は長くなってしまう.

そこで2.のようにの制限を無くして,-pオプションはそのままにファイルディスクリプタの上限を回避するという方法もある.実行コマンドや実行時間はそのままにエラーを回避することができる一方で,上限を上げたからといってもTophatがそれ以上の同時ファイルオープンをしてしまえば同様のエラーに引っかかってしまうほか,制限を上げたことにより計算機に負荷がかかる恐れもある.つまり,時と場合によっては成功するが確証は無いという感じだろうか.

ちなみに,私の場合はファイルディスクリプタ数を上げても以下のような別のエラーが出て実行できなかった.

1
Error: ReadStream::getRead() called with out-of-order id#!

ということで,結論としてはTophatの実行時間との兼ね合いを考えて,どちらかを選択したほうが良いだろう.素直に-pオプションの値を下げるほうが無難な気がする.

ちなみに,制限値を引き上げるには,ulimitで以下のように値を変更する.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ulimit -n 2000
$ limit
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-m: resident set size (kbytes)      unlimited
-u: processes                       1024
-n: file descriptors                2000
-l: locked-in-memory size (kbytes)  unlimited
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 16545839
-q: bytes in POSIX msg queues       819200
-e: max nice                        0
-r: max rt priority                 0

ulimitの後ろに該当するパラメータの値を指定することによって,上限を引き上げることができる.ただし,先ほど述べたようにハードリミットより上は指定することができないので注意が必要になる.

まとめ

Tophatのエラー「open: Too many open files」は,スレッドが一度に開くことのできるファイルディスクリプタ数がソフトリミットの上限に引っかかってしまったために起こる.-pオプションの値を下げて実行するか,ソフトリミットのファイルディスクリプタの上限を引き上げることによって回避することができる.まずは,-pオプションを指定せずに実行してみよう.

参考

実行環境

  • OS:RHEL 6.3
  • Tophat:v2.0.8b
  • Bowtie:version 2.1.0
  • Samtools:0.1.19.0