巨大ファイルの読み込みを検証する
さて、要件定義やどうやって実現していくのかの検討が終わりましたので、次は実際にそれが実現できるかの検証作業に入りましょう。
まず最初にファイルの随時読込みで、本当にエディタとして十分なレスポンスが得られるのか、一度にどの程度の大きさのデータを読み込むのがいいのか検証していきたいと思います。
なにしろエディタですので、ファイルの読み書きができないとお話になりません。
そして今回のテーマが「巨大ファイルを快適に編集」ですから、快適であることが最重要となります。
HDDというのは一度に読み込むバイト数によって、その効率は大きく違ってきます。
例えば1バイトずつ読み込むのと1Mバイトずつ読み込むのでは、その速度差は歴然。
関数コールやシステムコールも、回数が増えれば当然処理時間もかかりますし、HDDは特に1度に大きなデータを転送したほうが効率がいいのです。
データが連続している場合、HDDはトラック単位、あるいはシリンダ単位などでデータを読み出したりして、データ読み取りを高速化するような機構が入っています。
しかし、いくらデータが連続していても、読み出し命令が小分けで来ると、次のセクタ読み出しタイミングに間に合わずに、次にそのセクタが一周してくるのを待たなければなりません。
いわゆる回転待ちと言われる現象ですね。
HDDは高速で回転していますから、1セクタ分読んで処理して、次のセクタ読んでなんてやってたら、この読み出しタイミングに間に合いません。
なので、大抵の処理はある程度まとめてファイル読み出しをします。
まあ大抵は、コンパイラに付属のファイルアクセス関数やらシステムコールやらの中にバッファを持っていて、1バイトごとのアクセスでも、予め内部バッファにまとめて読み込んでいたデータを小分けにして出してくれるのですが、そのバッファもそんなに大きいわけでは無いので、効率は落ちます。
かと言って、大きなサイズを読み込むと効率は上がりますが、やはりそれなりに時間がかかる。
なので、大きすぎずそして小さすぎない大きさを設定する必要があります。
最初はとりあえず、スクロールが快適にできることを目標とします。
編集操作は基本的に予め必要な部分を読み込んだ内部バッファでやるので、次にファイル読み込みが必要になるのは、表示範囲がバッファ内から出た時。
つまりスクロール時です。
このスクロールが十分快適にできなければ、そもそもエディタの操作も快適になるはずがありません。
なのでスクロールバーと、エディットコントロールを貼り付けただけのフォームを用意します。
C++Builderなら簡単ですね。
メモコントロールとスクロールバーをフォームに貼り付けるだけ。
VC++ならご愁傷さまw
ファイルを任意に変更したいのであれば、ファイル選択ダイアログボックスを出すボタンでも付けておけばいいでしょう。
あとは、1度に読み出す大きさを決めて、スクロールバーの変動量と、ファイルのシーク位置を連動するようプログラムします。
1度に読み出す大きさもソースコード上ではなくテストプロフラム上で変更したいのであれば、エディットコントロールを貼り付けて、更新されたら読込みサイズを変更します。
ここでは、ファイル読み込みのレスポンスを確認するだけですので、行頭の検知等はひとまず行いません。
設定された大きさのデータをひたすら読み込むだけ。
簡単ですね!
あとはスクロールバーの変更に合わせてファイルシークして既定の量を読み出し、メモコントロールに貼り付けるだけ。
ただし、メモコントロールへの貼付けも、データが大きくなると結構時間がかかるので、読込むだけで、表示はスキップするモードもあったほうがいいかもしれません。
それから、CPU性能やHDDの読込み速度もレスポンスに大きく関わってきますので、自分の環境では問題なくても、他の人の環境では問題が出るかもしれません。
最終的には環境に合わせて、読込みサイズをユーザーが変更できるようにする必要があるかもしれませんが、デフォルトでいじらなくて良い数値を設定したいところ。
著作「異世界のジョブズ~」でも言っているように、自分で色々設定することが好きな人、やれる人もいる一方で、それが嫌いな人、できない人もいます。
嫌いな人できない人のためにも、基本的にデフォルト状態で快適に使えるに越したことはありません。
ということで、さっさと最適値を決めていきましょう。
今回使用するHDDは7200回転のものですが、USB3.0接続だったりします。
現在使用しているPCは、超小型なので、内蔵できるHDDは2.5インチのものだけ。
SSDも内蔵できますが、テストのためだけに買うのはもったいないし、外付けのUSB接続HDDはその辺にゴロゴロしているので、テスト用に確保。
直結のHDDよりは遅くなりますが、まあ、遅いのに合わせて調整すれば、より早い環境ならより快適になるってことでしょうから、とりあえずはこれで調整していきます。
ところで、なぜそんな物がゴロゴロしているかと言えば、それもこれも、レグザサーバーが壊れたせい。
修理に出すのもめんどいのでそのまま捨てたら、録画していたHDD10台くらい全部読めなくなったw
今はもうサブスクの映像配信使ってるから、TV番組を録画することなんてまず無いのでいいんですが、使っていない2TB HDDが山のように!
そのうち、中のディスクだけ取り出してRAIDでも組もうかと思っている次第。
そんな中からUSB3対応のHDDを今回のテスト用に引っ張りだしてきて、テスト用データを作成。
ちゃんと読み込んでいるのがわかるように、シーケンスナンバーをひたすら書き込んだファイル、なんと800Gバイト!
上書き保存とかするときは一旦テンポラリに書き込むし、.bakファイルも作るので2TBのHDDでは、このくらいが限界でしょう。
それでも800Gバイトものテストデータを作るだけでほぼ半日(寝ていたので正確な時間は不明w)?を要しました!
テストプログラムを作っている時間より長い!
まあ、HDDのほぼは半分ですからねぇ。
そのうち他のテストでも使用するでしょうから、まあ無駄にはならない、といいなぁ。
2.5インチ外付けとか、もっと遅い環境もあるのですが、流石にテラバイト単位のデータを扱おうというのにそんな遅い環境でやろうなんて人はいないですよね。
USB2接続のHDDならまだあり得るか?
ちなみにCPUはIntel(R) Core(TM) i7-7700 CPU @ 3.60GHzってやつで、Windows11には対応していません。
小さいソフト屋め!
今はもう14世代らしいので、世代だけで倍は違いますね!
まあ、遅い方で調整した方が快適に使える人が増えるでしょうから、問題ありません。
問題ないったら問題ないんだよ!
ということで、プログラムもデータも準備できました。
さっそく最適値を決めていきましょう。
しかし何を持って最適というのか。
本当はレスポンスタイムを測って、何ミリ秒以内に反応することとか誰でも検証可能な要件定義にするべきなんでしょうが、これは趣味のプログラム。
自分が快適かどうかで決めてしまいます!
良い子のみんなは真似しちゃだめだぞ。
良い子ではない小さなソフト屋さんは、よくまねっこして、快適じゃないソフトを山のように出していますけど、中の開発者は、それはそれは立派な開発マシンを使っているんでしょうねぇ。
昔は8Gバイトもあれば余裕だと思っていたメモリーも、タスクマネージャーで見てみると、今じゃほとんど、空きがない状態に。
Windows10がサポート切れになる前に買い替えが必要になりそうな感じがします。
また脇道にそれてしまいました。
で、結果です。はや!
まあ、自分の感覚ですから、何をどう試したかいちいち書いても仕方がないですからねぇ。
結論だけなら、3行もいらない。
なので色々と脇道にそれて、文字数を水増ししている所存です。
再び、で、結論としては0x80000バイト。
いわゆる512kバイトですね。
自分の環境ではですが。
意外に小さいのか、それとも意外に大きいのか。
判断が難しい微妙な数字になりましたねぇ。
というかこの数字。
前回の行が好きの回でネタバレしてますね!
ファイルを読み込むだけであればCPUはさほど使わないので、まずはHDDのレスポンスに合わせてこの数字で行くこととします。
管理データが増えてくれば、CPUに掛かる負担も増えてくるので、再び調整する必要が出てくるでしょうが。
さて、スクロールさせるのに最適な読み取りサイズが決まりましたのでデータ管理の最小単位であるブロックの大きさを決めていきましょう。
はい、スクロールと同じ512kバイトですね!
結論はや!
とはいえ3行で終わってしまったのでは、完全にチラ裏なので、もう少し掘り下げていきましょう。
前で検証したのはスクロールが快適に行える最大の読み取りサイズの検証です。
なぜこれの検証が必要だったかといえば、内部バッファに快適にデータが読み込める限界値を見つけるためですね。
内部バッファに一度に読み込める量が多いほど、ディスクへのアクセス頻度は下がり、より快適に使えます。
やはりメモリとHDDではレスポンスが全然違いますからねぇ。
かといってあまり大きなデータをファイルから読み込むと、スクロール時に操作が一瞬止まってしまいます。
これではいけません。
実際のところレスポンスと効率はある意味アンビバレンツな関係にあるといっていいでしょう。
大抵のことは、まとめてやるほうが効率が上がります。
HDDの読み書きもしかりです。
しかし、逆に最低限必要なことに限定したほうがレスポンスは上がります。
余計な処理はレスポンスを下げる原因になりますから、できるだけシンプルかつ最小限にするのがいいわけです。
ここで効率とのせめぎあいが始まります。
効率を上げつつレスポンスも十分確保する。
このバランス調整が結構難しい。
なので、ざっくり決めて、実用段階で再調整すればいいよね!
というわけで適当に決めてますw
スクロールが快適にできるのであれば、ブロックの読み書きも快適にできるだろうとの目論見です。
ファイルの読み書きに付随するCPUの処理時間なんて、大抵の場合ほぼ無視していいレベルの時間しかかかりませんからねぇ。
それほどHDDの処理にかかる時間は大きいとも言えます。
なので、スクロールが快適にできるってのも、スクロールバーを上下に無闇矢鱈動かして、引っかからず、スムーズに追従するかを重視して決めました。
昔はディスクアクセスしたら負けって考えで、CPUよりメモリにお金をかけたものです。今も似たようなものですが。
もちろん増設したメモリーの使い道はディスクキャッシュや、今では聞かなくなったRAMDISKですね。
著作の中でもメインメモリ64kバイトしか無いPC8801FRに1Mバイトの拡張メモリー載せて、CP/Mにディスクキャッシュを搭載したとかいう話(詳細はあとがきに書いたものですが)が載ってますが、そのくらいディスクアクセスが嫌で嫌でたまりませんでした。
まあ、当時はHDDどころかFDDでしたからねぇ。
遅さもひとしお。
ひたすらガッチャンコやってる姿は、何やらわびしいものを感じました。
うん、テープよりは速いよテープよりは。
ただ、コンピュータの進化とともに、大量のファイルを読み書きするようになり、OSの立ち上げが、テープ時代のMZ-80より遅くなろうとは誰が想像し得ただろうか!
ディスクを暗号化したノートPCなんて、立ち上げに2,30分もかかるやつがあったりと、時間通り仕事を始めるには、立ち上げるために30分早く出社しないといけないとか、なかなかカオスなときもあったりします。
HDDはシーケンシャルアクセスは結構速いけどランダムアクセスは苦手なので、細かいファイルがたくさんあるような環境では、格段に速度が落ちます。
なので読み書きはできるだけ大きく、かつ1アクセスに掛かる時間をレスポンス的に許容できる範囲に収める必要があるわけです。
そして今回管理データとして採用したブロックデータ(Rope / PieceTable)は基準の大きさで512kバイトとしていますが、基本的にこれは編集するたびにどんどん細かくなっていきます。
最小1バイトのデータが山のように積み上がった時のレスポンスも把握していきたいところですが、この辺は実証段階に入ってから調整しましょう。
ブロックが細かくなると、あっちを読んでこっちを読んでということが繰り返されるため、HDDのレスポンスも当然だだ下がりの上、管理データもたくさん処理しないといけないのでCPUのレスポンスも気になります。
このあたりは実際にやってみないことにはわからないので、後回しですね。
使ってみて改善する。
これぞアジャイル開発W