Performance Characteristics
Info
All numbers were obtained on a stock clock 5900X and 3000MHZ CL16 RAM.
The Reloaded VFS is heavily optimized for performance. A lot of micro-optimisations were done to squeeze every bit out of making opening files faster...
-
All strings stored as Wide Strings.
- Windows APIs use Wide Strings under the hood, even for ANSI APIs.
- Therefore we save time by not having to widen them again.
-
Custom string Hash Function for file paths.
- With AVX and SSE implementations; aswell as unrolled
nint
as backup.
- With AVX and SSE implementations; aswell as unrolled
-
Custom Vectorized
ToUpper
for Strings.- Modified backport from .NET 8.
- Super fast for 99% of the paths that are pure ASCII.
- Non-ASCII paths use slower fallback since they can't be vectorized.
- Partial ASCII paths have the first ASCII part vectorized and rest handled in fallback.
-
Custom Dictionary (HashMap) that can query string slices (to avoid copying/realloc).
-
Uses a custom 'LookupTree'.
- Provides lookup for resolving file paths in O(3) time.
File Mapping Performance & Memory Usage
Info
This section describes how long it takes to create a file map. A file map is a structure that helps redirect original files to their new versions found in mod folders.
Whenever changes are made to mod folders, the file map needs to be rebuilt.
Info
Two types of maps exist, RedirectionTree and LookupTree.
The latter, LookupTree
is optimised for performance, but takes roughly twice as long to build as it is built from the former RedirectionTree
.
Folder Type | Directories | Total Items | RedirectionTree (Time) | RedirectionTree (Memory) | LookupTree (Time) | LookupTree (Memory) |
---|---|---|---|---|---|---|
Windows Folder | 40,796 | 170,438 | 43ms | 27MB | 32ms | 25MB |
Steam Folder (65 games) |
9,318 | 172,896 | 18ms | 12MB | 20ms | 11MB |
The performance of mapping operations mainly depends on the directory count. The table above shows the time and memory usage for building the RedirectionTree
and LookupTree
for both Windows and Steam folders. The LookupTree
memory usage should be approximately equal to the total runtime memory usage.
For a typical game (based on the median of a Steam library), building the RedirectionTree
should take around 0.017ms
and allocate 48KB
.
Creating the optimized LookupTree
takes about 0.012ms
and allocates 47KB
.
Success
In other words, you can assume remapping files is basically real-time.
Fast Append
Both LookupTree
and RedirectionTree
support 'fast append'
operations.
If a file is added to the mod folder while the game is running and isn't previously mapped, it can be added to the tree directly without a full rebuild.
However, if the currently mapped file's source mod cannot be determined, the entire tree must be rebuilt.
This process doesn't require scanning mod folders again for files when not necessary. Each folder mapping has a cache of subdirectories and files, and the same string instances are reused between the trees and cache to save memory.
File Open Overhead
File open has negligible performance difference compared to not using VFS.
In a test with opening+closing 21,000 files (+70,000 virtualized), the difference
was only ~41ms (~3%) or less than 2 microseconds per file.
// All tests done in separate processes for accuracy.
| Method | Mean | Error | StdDev | Ratio |
|--------------------------------- |--------:|---------:|---------:|------:|
| OpenAllHandles_WithVfs | 1.650 s | 0.0102 s | 0.0095 s | 1.03 |
| OpenAllHandles_WithVfs_Optimized | 1.643 s | 0.0145 s | 0.0135 s | 1.03 |
| OpenAllHandles_WithoutVfs | 1.602 s | 0.0128 s | 0.0120 s | 1.00 |
In real-world "cold-start"
scenarios (e.g. after a machine reboot), opening
these many files would take around 80 seconds, making this difference effectively
margin of error (~0%).
Built-in Benchmarks
Tip
If you're a programmer, a lot of microbenchmarks are available in the Reloaded.Universal.Redirector.Benchmarks
project; have a look!