Windows で ionice

Windows で、ビルド(特にリンク)とかディスクアクセスが多い処理をさせている最中、他の作業をやろうとしてもディスクアクセスが遅くてイライラすることがありませんか?

CPUの優先度を下げるのは start /low や cygwin の nice を使えばできますが、IOの優先度を下げるコマンドは無いみたいです。

Windows Vista から Windows API 関数 SetPriorityClass の2つめの引数にPROCESS_MODE_BACKGROUND_BEGIN, PROCESS_MODE_BACKGROUND_END が追加されています。

以下の挟まれた部分のコードが、低いIO優先度で実行されます。

SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN);
// ... 低いIO優先度で実行される
SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);

これを利用して、I/O優先度を下げてコマンドを実行するコマンドを作ってみました。以下をコンパイルして ionice.exe を作ります。

linux の同じ名前のコマンドのようなオプション引数は対応してません。

一応 VC141 (Visual Studio 2017 の Visual C++) と BCC582 (C++Builder 2006) で確認してあります。

#include <windows.h>
#include <process.h>
#include <iostream>

// 定義がなかったら定義する
#ifndef PROCESS_MODE_BACKGROUND_BEGIN
#define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000
#endif

#ifndef PROCESS_MODE_BACKGROUND_END
#define PROCESS_MODE_BACKGROUND_END 0x00200000
#endif

// _spanvp は BCCだと spanvp 引数・戻り値は同じ
#ifdef __BORLANDC__
#define _spawnvp spawnvp
#endif

int main(int argc, char** argv)
{
    using namespace std;
    if (argc < 2) {             // 引数無し
        cout << "書式: ionice <コマンドライン...>" << endl;
        return 0;
    }
    //
    if (!SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN)) {
        cerr << "SetPriorityClass(*, PROCESS_MODE_BACKGROUND_BEGIN) エラー: " << GetLastError() << endl;
        cerr << "でも続行します" << endl;
    }
    int result = _spawnvp(P_WAIT, argv[1], argv+1);
    if (!SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END)) {
        cerr << "SetPriorityClass(*, PROCESS_MODE_BACKGROUND_END) エラー: " << GetLastError() << endl;
        cerr << "でも続行します" << endl;
    }
    return result;
}

使い方

例1

        make nantoka

を低い IO 優先度で実行したい場合に

        ionice make nantoka

例2

場合によっては(バッチファイルとか?) cmd.exe を噛まさないと動かないかもしれません。

        build nantoka

を低い IO 優先度で実行したい場合に

        ionice cmd /c build nantoka