Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

You cannot set CPU affinity of PostgreSQL instance started through pg_ctl with Start-Process and Process.ProcessorAffinity

Background:

In Windows, you can set the CPU affinity of an user process with Start-Process PowerShell cmdlet and System.Diagnostics.Process.ProcessorAffinity property like this:

$app = Start-Process -FilePath C:\Windows\System32\mspaint.exe -PassThru
$app.ProcessorAffinity = 0x3

Problem:

You cannot set CPU affinity of an PostgreSQL instance with Start-Process cmdlet and System.Diagnostics.Process.ProcessorAffinity property, when you start the instance through pg_ctl.

You will get SetValueInvocationException like this:

$app = Start-Process 'c:\path\to\PostgreSQL\12\bin\pg_ctl.exe' 'start -D C:\path\to\PostgreSQL\12\data' -PassThru -NoNewWindow
$app.ProcessorAffinity = 0x3

"ProcessorAffinity" の設定中に例外が発生しました: "プロセス (15860) が終了したため、要求を処理できません。"
発生場所 行:1 文字:1
+ $app.ProcessorAffinity = 0x3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

Cause

In PowerShell, it seems there are no ways to set CPU affinity of an user process when it starts. ProcessorAffinity property sets CPU affinity of an user process through Process object retrieved before it accessed.

In PostgreSQL, pg_ctl command exits immediately after it starts an PostgreSQL instance. If the process is exited before you set ProcessorAffinity, you cannot set CPU affinity.

Solution

You have to use start /affinity command in cmd.exe instead of Start-Process. For example, you can start PostgreSQL instance with CPU affinity from PowerShell like this:

cmd.exe /c "start /affinity 3 /B c:\path\to\PostgreSQL\12\bin\pg_ctl.exe start -w -s -D C:\path\to\PostgreSQL\12\data"