RAD Studio 10.2 Tokyo Update 3
概要
- PDF出力処理の自前実装をしていた
- TeeChartの系列含めた内容をPDF出力
- TStringListへPDFの内容を記載していき、最後にファイル出力 (SaveToFile())
- 最終的に生成されるPDFの行数
- 99458行
- 系列の出力処理で処理時間がかかっている
- 合計処理時間: 34秒
- 系列の出力処理を変更したところ高速化できた
- 合計処理時間: 4秒
実装(概要) > 高速化前: 34秒
高速化前のプロダクトコードの概要を示す。
Note: 名前は非公開のため一部変更している。
std::unique_ptr<TStringList> wrkSL(new TStringList);
...
// 系列以外の内容をwrkSLに追記
...
// 系列の内容の出力
//
for(int si=0; si < kNumSeries; si++) { // si: series index
addlen = XXX::AddXXX_graph_eachSeries(Chart1, si, wrkSL.get());
}
実装(概要) > 高速化後: 4秒
高速化後のプロダクトコードの概要を示す。
Note: 名前は非公開のため一部変更している。
std::unique_ptr<TStringList> wrkSL(new TStringList);
...
// 系列以外の内容をwrkSLに追記
...
// 系列の内容の出力
//
// 高速化のため、wrkSLに足さずにこちらに一度足したものをwrkSLに足す
std::unique_ptr<TStringList> srsSL(new TStringList);
for(int si=0; si < kNumSeries; si++) { // si: series index
// addlen = XXX::AddXXX_graph_eachSeries(Chart1, si, wrkSL.get());
addlen = XXX::AddXXX_graph_eachSeries(Chart1, si, srsSL.get());
wrkSL->Add(srsSL->Text);
srsSL->Clear();
}
高速化の理由 (推測)
今回の高速化の理由として2つの可能性が考えられる。
過去の実装の経験からは、要素の多いTStringListへのAdd()の回数を減らすことがパフォーマンス改善に大きく貢献している、と思われる。
1. 要素のアクセスの改善
TStringListのAdd()の内部的な処理は分からないが、要素のはじめからアクセスする処理が含まれるのではないかと思われる。
配列処理をポインタ処理に変更することで、要素の先頭からのアクセスでなく最後尾からのアクセスになる。それにより処理の高速化をしている例は本で読んだことがある。
引用: プログラミングでメシが食えるか!? by 小俣光之 (こまたみつゆき)さん
p117ポインタを使用して書き直すと、若干ですがより高速になります。配列アクセスは、毎回「配列の先頭アドレスにアクセスしたい場合のオフセットを加える」という演算をしながらアクセスします。これに対してポインタを使用すると、このような連続処理ではポインタの差し先を1つ進めるだけで、アクセスする場所はすでに決まっているので演算が不要なためです。
int count;
char buf[4096];
char *ptr; // 高速化ポイント
for(ptr=buf, count=0; *ptr!='\0'; ptr++) {
if (*ptr=='.') {
count++;
}
}
ワーク用srsSLを使うことで、このアクセス処理は走査する回数が減るため改善が見込まれるが、それが実際にどれくらいの効果かは個別計測はできない。
2. 要素数が少ないTStringListでの処理による改善
要素のアクセスとも関係するかもしれないが、TStringListのような重いオブジェクトを扱う時、要素数が増えるにつれ処理性能が落ちる。
処理性能を落とさないためには、負荷の少ない状態で追加処理を行う。
ワーク用srsSLに対するAdd()処理は要素が少ないため負荷が小さく、その結果を一回のAdd()で要素の多いwrkSLに追加したのはその観点から。
関連
- C++ Builder 10.2 Tokyo > FastReport > TfrxLineViewerで線を引く > performance:20万本の描画は不可能
- C++ Builder XE4 > 文字列操作 > 文字列の抽出方法 3つの処理比較 > 1:TStringList使用 2:Pos()使用 3:charとポインタ操作
- C++ Builder XE4, 10.2 Tokyo > TMemo > TStringList型のリストをTMemoに割当てる実装 > TMemo.Assign()など | link:パフォーマンス
- c++ builder > TStringListの上限 > TStringList can hold up to 134,217,728 strings (MaxListSize+1).