-
Notifications
You must be signed in to change notification settings - Fork 171
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
ファイル読み込み高速化(行データ読み出しのマルチスレッド対応) #2021
base: master
Are you sure you want to change the base?
ファイル読み込み高速化(行データ読み出しのマルチスレッド対応) #2021
Conversation
SetTypeByStringForFileの引数nDataLenがオーバーフローしていたため。 関連する処理を含めてintをsize_tに変更する。
@@ -105,11 +103,14 @@ class CFileLoad | |||
/* メンバオブジェクト */ | |||
const SEncodingConfig* m_pEencoding; | |||
|
|||
//! 文字コード自動検出のために読み込む最大サイズ(byte) | |||
static constexpr LONGLONG m_nAutoDetectReadLen = 32768LL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
挙動が変化しないよう旧 gm_nBufSizeDef
と同値としました。
バッファにデータを読み込む | ||
@note エラー時は throw する | ||
*/ | ||
void CFileLoad::Buffering( void ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
メモリマップドファイル化により逐次の読み込みが不要になったため廃止
|
✅ Build sakura 1.0.4461 completed (commit 0a57687cf0 by @suconbu) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
対応ありがとうございます。基本方針賛同です。
{ "\x0d\x00", "\x00\x0d", 2U }, | ||
{ "\x85\x00", "\x00\x85", 2U }, | ||
{ "\x28\x20", "\x20\x28", 2U }, | ||
{ "\x29\x20", "\x20\x29", 2U }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘ではないですが、変更する必要の「ある/なし」で言うと「なし」なので微妙です。
エンディアン変換をするための構造体だと思いますが、もう少しスマートな方法でやれないものか、とか思います。
bool StartsWith(const WCHAR* pData, int nLen) const{ return m_nLen<=nLen && 0==wmemcmp(pData,m_szDataW,m_nLen); } | ||
bool StartsWith(const ACHAR* pData, int nLen) const{ return m_nLen<=nLen && m_szDataA[0] != '\0' && 0==memcmp(pData,m_szDataA,m_nLen); } | ||
bool StartsWith(const WCHAR* pData, size_t nLen) const{ return m_nLen<=nLen && 0==wmemcmp(pData,m_szDataW,m_nLen); } | ||
bool StartsWith(const ACHAR* pData, size_t nLen) const{ return m_nLen<=nLen && m_szDataA[0] != '\0' && 0==memcmp(pData,m_szDataA,m_nLen); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘ではないですが、 util/string_ex.h
に似たような定義がたくさんあるので、そちらで集中管理してもいいんじゃないかと思いました。
@@ -33,6 +33,8 @@ | |||
#include "util/window.h" | |||
#include "CSelectLang.h" | |||
#include "String_define.h" | |||
#include <atomic> | |||
#include <future> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘ではないですが、標準c++のヘッダーファイルは StdAfx.h
でまとめてインクルードする感じにできませんかね。
たぶん趣味の領域なのでどちらでもいいです。
@@ -84,7 +86,7 @@ EConvertResult CReadManager::ReadFile_To_CDocLineMgr( | |||
EConvertResult eRet = RESULT_COMPLETE; | |||
|
|||
try{ | |||
CFileLoad cfl(type->m_encoding); | |||
CFileLoad cFileLoad( type->m_encoding ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
何故変数名を変える? のありがち指摘を入れときます。
理由があるなら教えてください。
理由のない変更は(以下省略。)
pFileInfo->SetBomExist( bBom ); | ||
|
||
/* ファイル時刻の取得 */ | ||
FILETIME FileTime; | ||
if( cfl.GetFileTime( NULL, NULL, &FileTime ) ){ | ||
if( cFileLoad.GetFileTime( NULL, NULL, &FileTime ) ){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
影響が大きいので黙ってましたが、 NULL
を nullptr
で re-define する変更を revert したいと思っています。
理由は「 gdiplus.h
をインクルードしたときエラーになるから」です。
個人的には gdiplus 嫌いなんですけど、ダークモード対応で TortoiseGit のコードの一部を流用しようとしたときに問題になるので、いつか対応入れると思います。
このあたり踏まえて、触る行に含まれる NULL
は nullptr に置換しときたいです。
std::vector<std::future<EConvertResult>> vecWorkerFutures; | ||
std::atomic<bool> bCanceled = false; | ||
|
||
size_t nOffsetBegin = cFileLoad.GetNextLineOffset( (size_t)cFileLoad.GetFileSize() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘じゃないですが (size_t)
に違和感。
キャストが必要なのは縮小変換する場合だけのはず。
cFileLoad.GetFileSize()
の関数名で、返すものがファイルサイズじゃないとすると問題。
//! 元のCDocLineMgrの内容は空になる | ||
void CDocLineMgr::AppendAsMove( CDocLineMgr& other ) | ||
{ | ||
if( other.GetDocLineTop() == nullptr ){ return; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘じゃないです。ほほ趣味ですが、こう書いても同じ意味。
if( other.GetDocLineTop() == nullptr ){ return; } | |
if (!other.GetDocLineTop()) return; // otherが空なら抜ける |
// LPWSTR m_pszFileName; // ファイル名 | ||
HANDLE m_hFile; // ファイルハンドル | ||
HANDLE m_hFileMapping; // メモリマップドファイルハンドル |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HANDLE m_hFileMapping; // メモリマップドファイルハンドル | |
HANDLE m_hFileMapping = nullptr; // メモリマップドファイルハンドル |
const char* m_pReadBufTop; // 読み込みバッファの先頭を指すポインタ | ||
size_t m_nReadBufOffsetBegin; | ||
size_t m_nReadBufOffsetEnd; | ||
size_t m_nReadBufOffsetCurrent; // 読み込みバッファ中のオフセット(次の行頭位置) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘です。最近のC++では クラスメンバー の宣言時に初期値を書いておくやり方が主流なので、想定する初期値があればここに書いて欲しいです。
@@ -154,7 +154,7 @@ inline BOOL CFileLoad::GetFileTime( FILETIME* pftCreate, FILETIME* pftLastAccess | |||
inline int CFileLoad::Read( void* pBuf, size_t nSize ) | |||
{ | |||
DWORD ReadSize; | |||
if( !::ReadFile( m_hFile, pBuf, nSize, &ReadSize, NULL ) ) | |||
if( !::ReadFile( m_hFile, pBuf, (DWORD)nSize, &ReadSize, NULL ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘じゃないです。
メモリマップトファイルに変更したのに ReadFile 使うん?
(ちゃんとソースコード読めよ、のセルフ突っ込みしておきます。)
PR対象
カテゴリ
PR の背景
#1988 の第3弾対応です。
今回の変更対象は
CReadManager::ReadFile_To_CDocLineMgr()
で、この関数では主に以下の処理をしています。これらの処理を yoshinrt/SakuraVz の 1578dc68, e9cbf1b0 の対応を参考に高速化します。
仕様・動作説明
対応内容:
CFileLoad
のメモリマップドファイル対応従来は固定長のバッファに対して逐次ファイル内容を読み込みながら処理をしていましたが、
メモリコピーの負荷を減らすことと、後述のマルチスレッド対応の効果を高める (=マルチスレッド化ができない処理を減らす) ことを目的に、メモリマップドファイルを使ってデータを読み込むよう変更します。
CReadManager::ReadFile_To_CDocLineMgr
のマルチスレッド対応テキストデータを行単位へ分割する処理と文字コード変換の処理を、複数のスレッドで並列実行するようにします。
サイズが2GiB以上のファイルを開いた時に落ちる問題を修正 (参考元の対応にはない修正)
「2」の対応したことで起きるようになったため本PRに含めて対応します。
CEol::SetTypeByStringForFile()
の引数nDataLen
がオーバーフローしていることが分かったため、型を int から size_t に変更します。(関連する変数/引数の型もあわせて直します)各区間の処理時間 (計測条件などは #1988 を参照):
PR の影響範囲
メモリマップドファイルを使うようにした影響で、ファイル読み込み中の瞬間最大のメモリ使用量が増えます。
読み込んだファイルとほぼ同じサイズ分だけ増加します。
(例) 1GiB のファイルを読み込む時の最大メモリ使用量:
テスト内容
関連 issue, PR
参考資料