Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ファイル読み込み高速化(行レイアウト化処理のマルチスレッド対応) #1994

Conversation

suconbu
Copy link
Member

@suconbu suconbu commented Feb 16, 2025

PR対象

  • アプリ(サクラエディタ本体)

カテゴリ

  • 改善

PR の背景

#1988 の第2弾対応です。

ファイル読み込み時の処理で一番時間の掛かっている CLayoutMgr::_DoLayout の処理時間の短縮を図ります。

CLayoutMgr::_DoLayout では、前段の処理にて改行単位で分割されたテキストデータを入力として、見た目上の行単位 (レイアウト行) に分割する処理を主にやっていますが、その部分を yoshinrt/SakuraVz34d5593d の対応を参考に複数のスレッドで並列実行できるようにします。

仕様・動作説明

対応内容:

  1. CLayoutMgr::_DoLayout のマルチスレッド対応
    CLayoutMgr::_DoLayout の実質の処理を CLayoutMgr::_DoLayoutSub (新規) に移し、それを複数スレッドから実行できるようにします。

  2. CLayoutMgr::_MakeOneLine の高速化
    ループ処理の手前で色分けや禁則関係の設定有無をあらかじめ確認、フラグに保持しておき、ループ内での不要な関数呼び出しをスキップします。

  3. CPoolResource クラスの排他制御対応
    対応「1」により、CLayoutMgr クラスが持つ1つのメモリプールを複数スレッドから同時に操作することになるため、CPoolResourcedo_allocate, do_deallocate メソッドに対して std::mutex を使った排他制御を追加します。

4スレッドで処理する場合のイメージ:
image

参考元対応から変えた主な点:

  • 行をまたぐ色分け設定 (/*...*/ など) のいずれかが有効の時はマルチスレッド処理を無効化
    有効時はひとつ前の行の色分け状態を連鎖的に考慮する必要があり、色分け区間の途中で処理が分割されると正しく色分けできなくなる懸念があったため、設定有効時は従来通りシングルスレッドで処理させます。
    (巨大となりがちなログファイルなどの拡張子に対して、行をまたぐ色分けの設定がされることはまれだろう・・・という想定とします)
    (参考元ではマルチスレッド処理するのは一部機能制限があるとする「巨大ファイルモード」の場合に限定)

  • CLayoutMgr クラスにおけるメモリプール (CPoolResource) の使用を継続
    排他制御を追加したとしてもメモリプールを使った方が直接 new/delete するよりも処理時間が短くなることが確認できたので引き続き使うことにしています。
    (参考元では 4f5c0285 にてメモリプールを廃止)

各区間の処理時間 (計測条件などは #1988 を参照):

区間 対応前 (d9d3242) 本PR対応後
A. CLoadAgent::OnLoad 開始から ReadFile_To_CDocLineMgr 完了まで 1528.936 1458.327
B. そこから CLoadAgent::OnLoad 完了まで (レイアウトデータ化処理) 4469.037 676.073
C. CLoadAgent::OnAfterLoad 開始から完了まで 9.104 16.088
合計 6007.077 2150.488 (-64%)

PR の影響範囲

  • 巨大なファイルを読み込む時のCPU使用率が著しく増加しますが、その分処理時間は短くなるので消費電力量はほぼ変わらないと思います。

テスト内容

test.zip 内のファイルを使って以下を確認します。

  • 「test_1000lines.txt」を開き、各行の数字が行番号と一致していること。👈レイアウト処理後のCLayoutMgrの集約が正しい順序でできていることの確認
  • 「test_1000lines.cpp」を開き、ファイル先頭から末尾まで文字色がコメントアウト色 (緑色) になっていること。👈マルチスレッド処理の対象外の判定ができていることの確認

関連 issue, PR

参考資料

@AppVeyorBot
Copy link

Build sakura 1.0.4405 failed (commit 8c05729532 by @suconbu)


constexpr DWORD userInterfaceInterval = 33;
DWORD prevTime = GetTickCount() + userInterfaceInterval;
ULONGLONG prevTime = GetTickCount64() + userInterfaceInterval;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

対応内容と関係ないですが、C28159 が指摘されていたので修正

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(指摘外) ULONGLONG でなく auto で良いような。

あと「userInterfaceInterval = 33」を仮置きした基準を残すと「より良く」なるような。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「userInterfaceInterval = 33」を仮置きした基準を残す

userInterfaceInterval の意味/用途説明があった方が良いんじゃないか?ってことですかね?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よくよく考えると、prevTime の初期化で userInterfaceInterval を加算するのはおかしいような。
1回目は 66ms 間隔、2回目以降は 33ms 間隔となる。意図通りではなさそう。
(直したところで動作の違いは体感できないと思いますが)

@suconbu suconbu force-pushed the feature/speedup_fileopen_multithread_layout branch from eff4747 to 522f22c Compare February 16, 2025 16:51
@AppVeyorBot
Copy link

Build sakura 1.0.4406 failed (commit 0544092c52 by @suconbu)

@beru beru added the 🚅 speed up 🚀 高速化 label Feb 16, 2025
berryzplus
berryzplus previously approved these changes Feb 17, 2025
if(_DoKinsokuSkip(pWork, pfOnLine)){ }
// 禁則処理中ならスキップする @@@ 2002.04.20 MIK
// 禁則関係の設定が全部OFFの場合もスキップ
if(!bKinsokuEnabled || _DoKinsokuSkip(pWork, pfOnLine)){ }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sonarcloud指摘) 「空の分岐は分かりづらいから、なんで空なのかコメントしようね」的なやつ。
メンテナンス性が上がりそうだけど対応は不要。

個人的には、条件を反転して直後の else とくっ付けるのが好み。

//@@@ 2002.09.22 YAZAKI
color.CheckColorMODE( &pWork->pcColorStrategy, pWork->nPos, pWork->cLineStr );
if( bCheckColorEnabled ){
//@@@ 2002.09.22 YAZAKI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(指摘外) こういうコメントを残すかどうか、悩ましいです。

「あると便利か?」を考えるとNoです。
「ないと困るか?」を考えるとNoです。

削ればスッキリしますが、著作権的にもやもやします。
残せば著作権には触れませんが、YAZAKIさんはここ書いてません。

int nLineIndexEnd = nAllLineCount;
CDocLine* pDocLineEnd = nullptr;
for (int i = nWorkerThreadCount; i >= 0; i--) {
const int nLineIndexBegin = (int)((double)nAllLineCount / (nWorkerThreadCount + 1) * i);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sonarcloud指摘) 必ずしも対応不要。

Suggested change
const int nLineIndexBegin = (int)((double)nAllLineCount / (nWorkerThreadCount + 1) * i);
const auto nLineIndexBegin = (int)((double)nAllLineCount / (nWorkerThreadCount + 1) * i);


constexpr DWORD userInterfaceInterval = 33;
DWORD prevTime = GetTickCount() + userInterfaceInterval;
ULONGLONG prevTime = GetTickCount64() + userInterfaceInterval;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(指摘外) ULONGLONG でなく auto で良いような。

あと「userInterfaceInterval = 33」を仮置きした基準を残すと「より良く」なるような。

@@ -65,6 +65,8 @@ class CPoolResource : public std::pmr::memory_resource
void* do_allocate([[maybe_unused]] std::size_t bytes,
[[maybe_unused]] std::size_t alignment) override
{
std::lock_guard<std::mutex> lock(mtx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sonarcloud指摘) 対応必須ではありませんが、メンテナンス性は上がりそう。

Suggested change
std::lock_guard<std::mutex> lock(mtx);
std::lock_guard lock(mtx);

@@ -91,6 +93,8 @@ class CPoolResource : public std::pmr::memory_resource
[[maybe_unused]] std::size_t alignment) override
{
if (p) {
std::lock_guard<std::mutex> lock(mtx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上。

if( nListenerCount != 0 && 0 < nLineCount ) {
if( nLineIndex == 0 ){
const ULONGLONG currTime = GetTickCount64();
const ULONGLONG diffTime = currTime - prevTime;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(指摘外) prevTime を auto にするならここも。

@@ -140,5 +144,7 @@ class CPoolResource : public std::pmr::memory_resource
Node* m_unassignedNode = nullptr; // 未割当領域の先頭
Node* m_currentBlock = nullptr; // 現在のブロック
Node* m_currentNode = nullptr; // 要素確保処理時に現在のブロックの中から切り出すNodeを指すポインタ、メモリ確保時に未割当領域が無い場合はここを使う

std::mutex mtx;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(指摘外) メンバー変数に 「m_」プレフィックスを付けるかどうか、悩ましい。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

気持ち悪いので付けマス

@@ -292,6 +292,7 @@ class CLayoutMgr : public CProgressSubject
// 2005.11.21 Moca 引用符の色分け情報を引数から除去
public:
void _DoLayout(bool bBlockingHook); /* 現在の折り返し文字数に合わせて全データのレイアウト情報を再生成します */
void _DoLayoutSub(CDocLine* pDocLineBegin, CDocLine* pDocLineEnd, int nLineIndexBegin, int nLineCount, std::atomic<bool>* pbCanceled);
Copy link
Contributor

@berryzplus berryzplus Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appveyor のビルドエラーは「 atomic が宣言されてない」というものです。
appveyor(vs2017 community edition) 固有のエラーなので、スルーしてよい気もします。

include <atomic> したら解決する可能性はあります。

@AppVeyorBot
Copy link

Build sakura 1.0.4426 completed (commit 8e655ff590 by @suconbu)

berryzplus
berryzplus previously approved these changes Feb 26, 2025
@suconbu suconbu force-pushed the feature/speedup_fileopen_multithread_layout branch from bd98a09 to 91e4c92 Compare February 28, 2025 16:31
@suconbu suconbu marked this pull request as ready for review February 28, 2025 16:42
@suconbu suconbu force-pushed the feature/speedup_fileopen_multithread_layout branch from 91e4c92 to e1a90b4 Compare February 28, 2025 16:49
@AppVeyorBot
Copy link

Build sakura 1.0.4430 failed (commit a0f45bde03 by @suconbu)

@suconbu suconbu force-pushed the feature/speedup_fileopen_multithread_layout branch from e1a90b4 to 90f8474 Compare February 28, 2025 17:24
@AppVeyorBot
Copy link

Build sakura 1.0.4431 completed (commit 5ebe925ffd by @suconbu)

@AppVeyorBot
Copy link

Build sakura 1.0.4432 completed (commit c8e62dbcb8 by @suconbu)

@suconbu
Copy link
Member Author

suconbu commented Feb 28, 2025

Acceptありがとうございました。
以下2か所を追加修正しましたので、お手数ですが再レビューお願いします。

@@ -292,6 +293,7 @@ class CLayoutMgr : public CProgressSubject
// 2005.11.21 Moca 引用符の色分け情報を引数から除去
public:
void _DoLayout(bool bBlockingHook); /* 現在の折り返し文字数に合わせて全データのレイアウト情報を再生成します */
void _DoLayoutSub(CDocLine* pDocLineBegin, const CDocLine* pDocLineEnd, int nLineIndexBegin, int nLineCount, std::atomic<bool>* pbCanceled);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

指摘外) std::atomic<bool>* pbCanceled のポインタ渡しについて。

参照渡し( std::atomic<bool>& isCanceled )としたほうが可読性、保守性をあげられそうに思いました。

コードベース全体ではポインタ渡しが主流で、[out] をあえて [out, opt] にしてるトコ多いので微妙な指摘になりますが。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pbCanceled については、以下の所で bBlockingHook の値によってnull or 有効値を意図的に使い分けるためにポインタ渡しとした次第でした。(代わりにフラグ+参照でも良かったカモ)
https://github.com/sakura-editor/sakura/pull/1994/files#diff-34d5593d67d75e50e7eb3db6eba862a33a37d3e568a87a21d13970626dab8335R389

ポインタ渡しじゃなきゃならない理由が特になければ、参照渡しが良いだろうという意見には同意します。

@suconbu
Copy link
Member Author

suconbu commented Mar 1, 2025

レビューありがとうございました。マージします。

@suconbu suconbu merged commit 9f9948d into sakura-editor:master Mar 1, 2025
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants