Saturday, March 27, 2021

Why WaasMedic Agent hammers the disk

After a recent large Windows update I noticed that "WaasMedic Agent Exe", hosting the "Windows Update Medic Service", regularly caused 100% disk usage for over an hour at a time. Since this was hindering my machine's performance I spent a little time looking into what exactly it was doing.

With Sysinternals Process Explorer I saw that the process accessed all kinds of files deep in my user profile, virtually none of which should have anything to do with Windows Update. The only thread that appeared active during the disk usage had a stack including both WaaSMedicAgent.exe (as expected) and SedPlugins.dll. Disassembling and obtaining symbols with IDA 7, the offending call stack seems to be (more recent calls last):

WaaSMedicAgent.exe: PluginAction
SedPlugins.dll:     ?PluginDetectCondition@CSedimentDriverExternalFunctions@CSedimentDriver@WSD@@QEAAJPEBGPEA_N@Z
SedPlugins.dll:     ?DetectCondition@DiskCleanupPlugin@1WSD@@UEAAJPEAH@Z
SedPlugins.dll:     ?CollectCommonDiskInformation@CDiskFileCleanup@WSD@@QEAAJXZ
SedPlugins.dll:     ?CalculateDirSizeInternal@CDirUtil@WSD@@CA_JAEBV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@_J_N@Z
SedPlugins.dll:     (recursive call...)

The update medic service seems to be very modular, capable of hosting different plugins. The calls to PluginDetectCondition and DetectCondition are both indirect. SedPlugins.dll holds "sedimentation" plugins (?), which I imagine is some kind of internal project codename. I speculate that each plugin is supposed to check for and try to resolve a different issue that might interfere with Windows Update functionality. A "disk cleanup" plugin might make sure that a reasonable amount of space is free on the system drive and invoke cleanup of dispensable files if not.

Speculation aside, the disassembly of CollectCommonDiskInformation makes the problem very clear. It calculates and logs the total size of each of several directories: 

  • %WINDOWS%\installer
  • %WINDOWS%\SoftwareDistribution
  • %WINDOWS%
  • %WINDOWS%\serviceprofiles
  • \program files
  • \users
  • \programdata
  • \program files\WindowsApps
  • \$Windows.~BT
  • \Windows10Upgrade

My user profile folder contains a lot of small files in moderately deep directory hierarchies, so this is very slow. Also, some of these checks are redundant - the size of the Windows apps folder is already included in the size of Program Files. More importantly, this approach will spend a lot of time worrying about the size of things that can't be automatically cleaned up - I could purge my Gradle caches if I needed space, but Windows doesn't know that and can't know what's dispensable in general. Even more importantly, I have over 500 GB free on my system drive! Checking the disk free space is very fast (not recursive), so ideally the plugin should notice that cleanup is not necessary and skip expensive calculations.

[Update: I filed a Feedback Hub report.]

Since Windows Update is working as desired, I decided to disable this "medic" service until its disk hammering is fixed. This service seems to get special defense against modification through the services API, so I disabled it by setting the Start value to 4 in its SCM Registry key:

HKLM\SYSTEM\CurrentControlSet\Services\WaaSMedicSvc