Skip to content

SystemTools: Better GetCasePathName caching

The function GetActualCaseForPathCached cached the whole input and output of GetCasePathName. By caching the calls to FindFirstFileW instead, many redundant expensive FindFirstFileW calls can be avoided.

For example, if we call GetActualCaseForPathCached for the paths C:\A\B\C, C:\A\B\D and C:\A\B\E (assuming that they exist), currently FindFirstFileW gets called for:

3 * C:\A + 3 * C:\A\B + 1 * C:\A\B\C + 1 * C:\A\B\D + 1 * C:\A\B\E

With the new caching FindFirstFileW only gets called for:

1 * C:\A + 1 * C:\A\B + 1 * C:\A\B\C + 1 * C:\A\B\D + 1 * C:\A\B\E

This gets even better with more calls to GetActualCaseForPathCached, which share parent directories and can be directly looked up in cache, as is the case for the majority of calls by CMake. Benchmarking the difference of caching for CMake yields the following timings:

> hyperfine.exe -w 1 -p 'del /S /Q /F build-perf' -L state before,after 'build-{state}\bin\cmake.exe -G Ninja -B build-perf -DCMAKE_BUILD_TYPE=Debug'
Benchmark 1: build-before\bin\cmake.exe -G Ninja -B build-perf -DCMAKE_BUILD_TYPE=Debug
  Time (mean ± σ):     18.195 s ±  0.126 s    [User: 0.003 s, System: 0.003 s]
  Range (min … max):   18.084 s … 18.529 s    10 runs

Benchmark 2: build-after\bin\cmake.exe -G Ninja -B build-perf -DCMAKE_BUILD_TYPE=Debug
  Time (mean ± σ):     17.336 s ±  0.174 s    [User: 0.000 s, System: 0.003 s]
  Range (min … max):   17.226 s … 17.804 s    10 runs

Summary
  'build-after\bin\cmake.exe -G Ninja -B build-perf -DCMAKE_BUILD_TYPE=Debug' ran
    1.05 ± 0.01 times faster than 'build-before\bin\cmake.exe -G Ninja -B build-perf -DCMAKE_BUILD_TYPE=Debug'

Topic-rename: SystemTools-GetCasePathName-cache

Edited by Brad King

Merge request reports