Skip to content

Commit 3caae95

Browse files
authored
Loading optimizations (#269)
Various loading performance focused changes, part of the general loading re-implementation : - Added performance metrics logging upon reaching the main menu - Added (almost) entirely custom MU model parser, roughly 3 times the throughput of the stock parser (~300 MB/s on my machine). Will only really benefit to people having fast NVME drives with good random read performance. - KSPCF now maintains dictionaries of loaded models and texture assets by their url/name, and patch the stock `GameDatabase.GetModel*` / `GameDatabase.GetTexture*` method to use them instead of doing a linear search. This was especially bad with models, as the method would compare the requested string to the `GameObject.name` property for every model in the database. Unfortunately, we have no way to know if additional assets are loaded by custom means, so we have to fallback to a linear search when the requested texture isn't known and we can't assume that a texture that isn't found at some point won't be found in the future, so in cases where a not loaded / absent texture is queried, there is no performance improvement. Overall, this benefit to many scenarios, during initial loading for model parsing and part compilation, and more marginally for scenes switches [when various initialization paths are re-acquiring a texture reference](https://github.com/search?q=GameDatabase.Instance.GetTexture+OR+GameDatabase.Instance.GetModel+language%3AC%23&type=code). Other changes, also loading related : - As a part of the `MinorPerfTweaks` patch, patched the `FlightGlobals.fetch` property to not fallback to a `FindObjectOfType()` call when the `FlightGlobals._fetch` field is null, which is always the case during loading. In a stock + BDB test case, this alone was about 10% of the total loading time, 7+ seconds. The call doesn't seem necessary as `FlightGlobals._fetch` is set/unset from `FlightGlobals.Awake()` / `FlightGlobals.OnDestroy()`. I guess there are some very edge cases where a (just about to be destroyed) instance could be acquired by a call to `FindObjectOfType()`, but in any case I would qualify such behavior as a bug. On a side note, the same issue is present with `PhysicsGlobals`, but I haven't been able to detect any benefits in patching that one. - New patch `PartParsingPerf` - Slightly faster part icon generation. Part icon GameObject generation is done by cloning the part prefab and basically removing everything on it. The operation represent roughly 35% of the part compilation time, a good two thirds of that being in instantiating the copy of prefab, and running all the associated code (part / modules KSPField scaffolding and Awake() code), only to immediately destroy everything. Unfortunately, this can't really be avoided due to the need to run `PartModule.OnIconCreate()` and in some case, some model-manipulation code in Awake(). - Faster `Part` fields parsing, by creating a dictionary of IL-emitted parser delegates instead of the very generic reflection based stock approach. Overall, these changes can provide a quite significant boost to loading time, mainly to part compilation and model loading. On a hot boot (config/model/texture loading not throughput limited by I/O), total time from exe launch to main menu for a stock + BDB install is now around 35 seconds on my 5800X3D.
1 parent 6d58c6c commit 3caae95

File tree

11 files changed

+2453
-110
lines changed

11 files changed

+2453
-110
lines changed

GameData/KSPCommunityFixes/Settings.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ KSP_COMMUNITY_FIXES
459459
// but this helps a bit in other cases as well.
460460
FloatingOriginPerf = true
461461
462+
PartParsingPerf = true
463+
462464
// ##########################
463465
// Modding
464466
// ##########################

KSPCommunityFixes/BasePatch.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ internal class TranspileInDebugAttribute : Attribute
4343
{
4444
}
4545

46+
/// <summary>
47+
/// When applied to a class derived from <see cref="BasePatch"/>, the patch won't be automatically applied.<para/>
48+
/// To apply the patch, call <see cref="BasePatch.Patch"/>. Note that if that call happens before ModuleManager
49+
/// has patched the configs (ie, before part compilation), <see cref="BasePatch.IgnoreConfig"/> must be overriden
50+
/// to return <see langword="true"/>, or the patch won't be applied.
51+
/// </summary>
52+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
53+
internal class ManualPatchAttribute : Attribute
54+
{
55+
}
56+
4657
public abstract class BasePatch
4758
{
4859
public static readonly string pluginData = "PluginData";
@@ -64,7 +75,7 @@ public static void Patch(Type patchType)
6475

6576
if (!patch.IgnoreConfig && !KSPCommunityFixes.enabledPatches.Contains(patchType.Name))
6677
{
67-
Debug.Log($"[KSPCommunityFixes] Patch {patchType.Name} not applied (disabled in Settings.cfg)");
78+
Debug.Log($"[KSPCommunityFixes] Patch {patchType.Name} not applied (not enabled in Settings.cfg)");
6879
return;
6980
}
7081

KSPCommunityFixes/KSPCommunityFixes.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class KSPCommunityFixes : MonoBehaviour
1414

1515
public static string LOC_KSPCF_Title = "KSP Community Fixes";
1616

17-
1817
public static Harmony Harmony { get; private set; }
1918

2019
public static HashSet<string> enabledPatches = new HashSet<string>();
@@ -50,6 +49,14 @@ public static Version KspVersion
5049
}
5150
}
5251

52+
static KSPCommunityFixes()
53+
{
54+
Harmony = new Harmony("KSPCommunityFixes");
55+
#if DEBUG
56+
Harmony.DEBUG = true;
57+
#endif
58+
}
59+
5360
public static T GetPatchInstance<T>() where T : BasePatch
5461
{
5562
if (!patchInstances.TryGetValue(typeof(T), out BasePatch instance))
@@ -72,11 +79,6 @@ void Start()
7279
DontDestroyOnLoad(this);
7380
}
7481

75-
Harmony = new Harmony("KSPCommunityFixes");
76-
77-
#if DEBUG
78-
Harmony.DEBUG = true;
79-
#endif
8082
LocalizationUtils.GenerateLocTemplateIfRequested();
8183
LocalizationUtils.ParseLocalization();
8284

@@ -113,10 +115,9 @@ public void MMPostLoadCallback()
113115
List<Type> patchesTypes = new List<Type>();
114116
foreach (Type type in Assembly.GetAssembly(basePatchType).GetTypes())
115117
{
116-
if (!type.IsAbstract && type.IsSubclassOf(basePatchType))
118+
if (!type.IsAbstract && type.IsSubclassOf(basePatchType) && type.GetCustomAttribute<ManualPatchAttribute>() == null)
117119
{
118120
patchesTypes.Add(type);
119-
120121
}
121122
}
122123

KSPCommunityFixes/KSPCommunityFixes.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="..\packages\Krafs.Publicizer.2.2.1\build\Krafs.Publicizer.props" Condition="Exists('..\packages\Krafs.Publicizer.2.2.1\build\Krafs.Publicizer.props')" />
44
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -155,13 +155,16 @@
155155
<Compile Include="Library\LocalizationUtils.cs" />
156156
<Compile Include="Library\Numerics.cs" />
157157
<Compile Include="Library\ObjectPool.cs" />
158+
<Compile Include="Library\MuParser.cs" />
159+
<Compile Include="Library\ShaderHelpers.cs" />
158160
<Compile Include="Modding\KSPFieldEnumDesc.cs" />
159161
<Compile Include="Modding\ModUpgradePipeline.cs" />
160162
<Compile Include="Performance\ForceSyncSceneSwitch.cs" />
161163
<Compile Include="Performance\AsteroidAndCometDrillCache.cs" />
162164
<Compile Include="BugFixes\DoubleCurvePreserveTangents.cs" />
163165
<Compile Include="BugFixes\RestoreMaxPhysicsDT.cs" />
164166
<Compile Include="Performance\FloatingOriginPerf.cs" />
167+
<Compile Include="Performance\GameDatabasePerf.cs" />
165168
<Compile Include="Performance\PartSystemsFastUpdate.cs" />
166169
<Compile Include="Performance\CollisionEnhancerFastUpdate.cs" />
167170
<Compile Include="Performance\CollisionManagerFastUpdate.cs" />
@@ -173,6 +176,7 @@
173176
<Compile Include="Performance\FasterPartFindTransform.cs" />
174177
<Compile Include="Performance\FastLoader.cs" />
175178
<Compile Include="Performance\FlightIntegratorPerf.cs" />
179+
<Compile Include="Performance\PartParsingPerf.cs" />
176180
<Compile Include="Performance\IMGUIOptimization.cs" />
177181
<Compile Include="Performance\LocalizerPerf.cs" />
178182
<Compile Include="Performance\LowerMinPhysicsDTPerFrame.cs" />
@@ -254,6 +258,7 @@
254258
<ItemGroup>
255259
<None Include="packages.config" />
256260
</ItemGroup>
261+
<ItemGroup />
257262
<!--Project-specfic configuration-->
258263
<PropertyGroup>
259264
<RepoRootPath>$(SolutionDir)</RepoRootPath>

0 commit comments

Comments
 (0)