-
Notifications
You must be signed in to change notification settings - Fork 38
Case Alias Symlinks
When deploying a Bethesda game you may notice that there are multiple Data folders and multiple copies of the same folder in the Data folder
This is done to decrease loading times. Which sounds very counter Intuitive. But we need to understand how a game like Skyrim interacts with Proton and why it's such an issue in this game
- Windows filesystems are case-insensitive; Linux filesystems are case-sensitive. Wine bridges that gap in software.
- When a game asks for a file, Wine first tries an exact-case
stat()- fast, one syscall. If the casing doesn't match what's on disk, Wine falls back to listing the entire directory and comparing every entry case-insensitively. - The Creation Engine constantly asks for paths in casings that don't match the disk:
- INI reads use lowercase data<PluginName>.ini, while the folder on disk is Data.
- Texture/terrain-LOD loads use uppercase Data\TEXTURES..., while the folder on disk is usually never all uppercase.
- Mesh (NIF) files embed asset paths that are ~99% all-lowercase.
- The engine also repeatedly asks for Data\Data, a folder that never exists and proving a name is absent costs a full directory scan too
- On Windows this costs nothing, NTFS keeps a case-insensitive index, so every one of these resolves instantly. The engine has no reason not to be sloppy about casing, and never has been
This is neither an issue with Skyrim or Proton/Wine. Skyrim was designed for an NTFS filesystem where this issue doesn't exist. Wine is doing its job correctly. The issue is modded Skyrim can have hundreds of thousands of loose files and makes wine do its thing far too much
- For each relevant directory, create symlinks named with the other casings, pointing at the real folder:
-
data>DataandDATA>Datain the game root -
textures>Textures,TEXTURES>Textures, and so on for every subfolder of Data - Now every casing the engine asks for exists on disk as a real path, so Wine's exact-case fast path hits on the first try, one
stat(), no directory scan.
The test was from pressing play in Steam to the Continue button in the game being clickable. Deploy mod was set to hardlink. Your hardware can affect loading times, so yours may be even better
Vanilla game (Only SKSE installed)
- No case alias applied - ~31 seconds
- Case alias applied - ~31 seconds
- Launching SKSE Directly (No launch Via steam) - ~20 Seconds
Most of the time here (about 10-15 seconds) is steam taking its sweet time to launch the exe. The reason there is no difference is because vanilla only loads from BSA files which are not affected by this fix.
Tested on my own modlist of ~500 mods.
- Launch from Mo2 - ~5:15 average
- No case alias applied - ~2:45 average
- Case alias applied - ~1:35 average
- Case alias and CRDW ~1:15 Average
About 4 minutes removed from the worst case scenario (launching in Mo2 on Linux) and best case scenario
Gate to Sovngarde
- No case alias applied - ~18 Minute average
- Case alias applied - ~5 Minute average
- Case alias and CRDW ~4:45 Average
The Cached Recursive Directory Walk mod on its own is fine but the case alias fix is needed to fix the long initial load times. CRDW does not fully take affect until it has created a cache. This plugin only masks the issue caused by Wine after the cache is built but does not remove it like the case alias fix does
The following data was done with my own modlist. We trace the Syscalls made by SkyrimSE.exe
| Metric | Fix OFF | Fix ON | Change |
|---|---|---|---|
| Directory entries read | 129.0M | 4.64M | −96.4% |
getdents64 (directory reads) |
656,785 | 97,503 | −85.2% |
newfstatat (file lookups) |
3,455,882 | 349,430 | −89.9% |
openat |
1,082,384 | 119,842 | −88.9% |
| Failed (ENOENT) lookups | 756,311 | 65,319 | −91.4% |
| Total syscalls captured | 5.19M | 0.57M | −89.1% |
| Raw trace size | 1,506 MB | 166 MB | −89.0% |
Where the scanning went
| Directory | Fix OFF (scans / entries) | Fix ON (scans / entries) |
|---|---|---|
Data |
324,227 / 119.9M | 7,986 / 2.05M |
| game root | 261,685 / 6.9M | 30,314 / 0.45M |
Data/SKSE/Plugins |
4,958 / 0.98M | 4,958 / 0.98M |
| distinct directories scanned | 7,179 | 4,749 |
With the fix off, two directories accounted for 98% of all directory
reading, and Data alone was re-read 324,227 times in a single launch.
The failed lookups that caused it (fix off)
| Requested | Times | Actually on disk |
|---|---|---|
data (root) |
226,149 | Data |
Data\data |
75,112 | (never exists — engine bug) |
Data\MESHES |
52,761 | Meshes |
Data\SOUND |
38,937 | Sound |
Data\TEXTURES |
35,769 | Textures |
Data\meshes |
17,895 | Meshes |
Data\GRASS |
8,069 | grass |
Data\SCRIPTS |
4,672 | Scripts |
All of these failed lookups drop to 0 with the fix. It also shows why renaming Meshes to meshes wouldn't help, the game still requests files from MESHES. Not an issue on Windows but on Proton this will still cause failed lookups, so we need to make both cases exist to remove them
- Skyrim asks for a file in the TEXTURES folder
- That folder doesn't exist because it's called Textures
- Wine does a full directory scan and looks for Textures to give to the game
- This repeats for every single file, Every time there is a case mismatch wine has to do a full directory scan
- This full directory scan is fast but not free, The time it takes adds up and really hurts with a large modlist
- This feature can be turned off in the quick configure menu
- Most Bethesda games can use this feature but Skyrim probably benefits the most. Other games don't need this
Getting started
Managing mods
- Installing a mod
- Mod Files Tab
- Updating a Mod
- Installing a collection
- Creating and uploading a collection
- Installing VNV and TTW
- Mods not working
- Profile Specific Saves
Load order and conflicts
Deploying and playing
Tools and advanced
Reference