Lower the I/O priority?

Topics: User Forum
Jun 28, 2013 at 9:56 PM
Edited Jun 28, 2013 at 9:59 PM
In my experience, the ExtractingHtmlInfo build step on 102025 HTML files causes so much I/O that it is difficult to get anything else done with the computer at the same time. I have tried changing the CPU priority to Low and limiting the CPU affinity to one processor only, but it doesn't help enough; I guess the process still gets enough CPU time to saturate the I/O.

I expect that putting the working folder on an SSD would help, but perhaps there is another way too. On Windows 7, the Disk tab of Resource Monitor shows an I/O Priority column that typically reads "Normal". If I could get ExtractingHtmlInfo to use a lower I/O priority, that might leave the computer more usable for other purposes during the build.

The relevant Win32 API call is SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN), SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN), or SetFileInformationByHandle(hFile, FileIoPriorityHintInfo, …). These are available from Windows Vista up. I tried switching the entire Sandcastle Help File Builder GUI process to background mode, and Resource Monitor then showed that the disk activity of both SHFB and its child MSBuild and XslTransform processes had Background I/O priority. I don't know whether the child processes inherited the background mode from the parent process or from the parent thread.

I have not yet tested whether background mode helps keep the computer usable during a documentation build. I intend to try that out next week.
Jun 29, 2013 at 2:56 AM
Perhaps you'd be better of spawning MSBuild in a background task with a lower priority. I'm not keen on adding code to the build engine to slow it down arbitrarily because of a single usage scenario. I also won't add code that only works on Vista or later since I know there are still quite a few people that use SHFB on XP and I'm not going to cut them off.

Jul 2, 2013 at 12:08 PM
I was thinking there could be a checkbox in a menu of the Sandcastle Help File Builder GUI. When checked, SHFB would run the build steps at a lower I/O priority. On Windows XP, the checkbox would just be grayed out. I wanted this in the GUI for two reasons: Windows 7 doesn't seem to include a utility program that lowers the I/O priority like START /LOW lowers the CPU priority; and to keep the GUI responsive, it should be run at normal priority even if the child processes have a lower priority.

I have now run two complete builds in background mode, and it indeed greatly improves the responsivity of other applications. Unfortunately, it also greatly slows down the documentation build. At normal priority, the build time was seven and a half hours; in background mode, it was first 14 and then 18 hours. Background mode is clearly not appropriate if a human being is waiting for the build to finish.

While experimenting, I noticed that processes started by Task Scheduler have an I/O priority of Low, rather than Normal or Background. Perhaps this setting would let the build finish faster, without starving interactive processes too much. However, Win32 doesn't seem to provide a documented way to set this priority. I assume Task Scheduler uses some undocumented Native API for that. On some forums, people wrote that Task Scheduler lowers the memory priority as well, and that the CPU priority of tasks can be changed by editing the task as XML. Anyway, I intend to try running the documentation build as a scheduled task.

There might be another way to throttle the I/O, as well. The ExtractingHtmlInfo build step runs thousands of tasks via a TaskScheduler. Perhaps I could replace this TaskScheduler with one that limits concurrency, as in the example at http://msdn.microsoft.com/en-us/library/ee789351.aspx, and then test how different concurrency levels affect the total build time and the responsivity of other applications. That kind of solution would work on Windows XP as well, and would have negligible impact if disabled at run time.
Jul 2, 2013 at 8:47 PM
The Parallel.ForEach() used in the HTML extract already contains a max degree of parallelism option. It may be sufficient to offer an option to adjust that rather than messing with the process priority. I'm still not keen on trying to alter the priority from within the build engine since there doesn't seem to be any call for it. If that's your goal, I'd suggest doing something like creating a wrapper utility that spawns MSBuild to build the project.

Sep 12, 2013 at 5:12 PM
I edited SandcastleHtmlExtract.ParseFiles from changeset 103877 so it passes new ParallelOptions { MaxDegreeOfParallelism = 3 } to Parallel.ForEach. That makes the computer a lot more responsive during the ExtractingHtmlInfo build step. I don't know yet how much it will affect the total build time.

Now though, I'll soon leave this computer and would like to increase parallelism for the rest of the build, because it won't matter if the UI gets slow while I'm away. Does the Task Parallel Library offer some way to change the degree of parallelism on the fly? I suspect that just setting ParallelOptions.MaxDegreeOfParallelism might not affect the Parallel.ForEach operation that has already started; besides, the property is not documented to be thread-safe. However, a custom TaskScheduler might do the trick. If it communicated with SandcastleBuilderGui, then I could have a trackbar control for the maximum degree of parallelism and a label to show the resulting throughput in files per second. Alternatively, the task scheduler could use GetLastInputInfo to automatically detect when the user is idle.

What kind of IPC would make sense between SandcastleBuilderGui and SandcastleHtmlExtract? I think a shared memory section with DWORD MaxDegreeOfParallelism, TotalFilesProcessed; would be fine; no locks necessary. SandcastleBuilderGui would create the section, pass its name to SandcastleHtmlExtract in an MSBuild property, set MaxDegreeOfParallelism, and poll TotalFilesProcessed every couple of seconds while the label is visible.

I'm not sure I get around to implementing that, but it's fun to think about.
Sep 12, 2013 at 11:05 PM
I think you're overthinking it. A simple project option to control max degree of parallelism would be more than sufficient. I see no reason to try and add communication between the GUI and the build tasks or dynamically adjust the value. Besides, the build tasks may be spawned from within Visual Studio or simply from a command line, not just the standalone GUI.

Aug 30, 2014 at 7:17 PM
I filed the issue Excessive parallelism in I/O-bound SandcastleHtmlExtract.

Regarding the I/O priority, I have now used Task Scheduler to set up a task that runs the Sandcastle Help File Builder GUI. The task does not have any triggers but I can run it on demand and the process gets a lower I/O priority then. There are a few problems with this though:
  • Starting the Task Scheduler UI requires administrator privileges. I have those but the UAC consent prompt is inconvenient.
  • The GUI itself also runs at a lower priority, so it sometimes does not draw the window as quickly as I'd like. It would be better to run only the build at a lower priority.
  • Even with the lowered I/O and CPU priorities, the documentation build sometimes makes Firefox not respond for a few seconds at a time.
My excuse for not implementing the maximum parallelism option yet is that I'd first like to upgrade from SHFB to the current version, which requires porting custom plug-ins to the Managed Extensibility Framework.