Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
LoadTimeProfiler
Profiles mod loading times during game startup, world loading, and dedicated server boot. Creates clear per-mod reports and keeps the latest 10 runs for easy comparison.
| Date uploaded | 3 weeks ago |
| Version | 1.0.1 |
| Download link | sighsorry-LoadTimeProfiler-1.0.1.zip |
| Downloads | 58 |
| Dependency string | sighsorry-LoadTimeProfiler-1.0.1 |
This mod requires the following mods to function
denikson-BepInExPack_Valheim
BepInEx pack for Valheim. Preconfigured with the correct entry point for mods and preferred defaults for the community.
Preferred version: 5.4.2333README
LoadTimeProfiler
Profiles mod loading times during game startup, world loading, and dedicated server boot. Creates clear per-mod reports and keeps the latest 10 runs for easy comparison.
It starts before normal BepInEx plugins and writes an easy-to-read timing report for each launch. It does not change gameplay, items, worlds, or server settings.
Features
- Measures client startup from launch to the main menu.
- Measures the trip from the lobby to a playable world.
- Measures dedicated server startup until the server is ready.
- Shows how much time individual mods spend during plugin setup, including construction,
Awake,OnEnable, andStart. - Shows per-mod synchronous work during the important
ZNetScene.AwakeandObjectDB.Awakeloading stages. - Records a timeline of major Valheim loading stages, making long pauses easier to spot.
- Keeps the latest 10 reports so you can compare runs before and after changing your mod list.
- Works on clients and dedicated servers without DataForge or ServerSync.
Manual Installation
Place LoadTimeProfiler.dll directly inside:
BepInEx/patchers
Do not place it in BepInEx/plugins. A patcher needs to start before regular plugins so it can measure their loading time.
Install it separately on every client or dedicated server that you want to profile. A server installation measures the server; a client installation measures that client.
How To Use
- Start Valheim or your dedicated server normally.
- On a client, wait for the main menu and then enter a world if you also want a lobby-to-world report.
- On a dedicated server, wait until world loading is complete and the server is ready for connections.
- Open the newest report in:
BepInEx/config/LoadTimeProfiler
Each report is named with its launch date and time. Up to 10 reports are stored in this folder. When an 11th report is created, the oldest report is removed automatically.
Compare several runs before deciding that one mod is slow. Loading time can change because of disk cache, network conditions, world size, and other programs running on the computer.
Dedicated Server Behavior
Install the same LoadTimeProfiler.dll in the dedicated server's own BepInEx/patchers folder. No client installation is required to measure the server itself.
When the valheim_server process starts, LoadTimeProfiler automatically switches to dedicated server mode and creates a Server Startup report. It measures:
- BepInEx startup and plugin construction,
Awake,OnEnable, andStartwork. - Major server loading stages such as
ZNetScene.Awake,ObjectDB.Awake,ZoneSystem.Start, andDungeonDB.Start. - Synchronous per-mod Harmony callback time during
ZNetScene.AwakeandObjectDB.Awake. - Startup through world and location generation until Valheim opens the server for connections.
The report is saved on the server machine at:
BepInEx/config/LoadTimeProfiler
Server reports are not sent to connected players. Installing LoadTimeProfiler only on a client measures that client, while installing it only on the dedicated server measures the server. The server also keeps only its newest 10 reports.
Reading The Report
- Plugin construction/Awake/OnEnable shows time spent while BepInEx creates and enables each plugin.
- Plugin Start shows measured work from plugin
Startmethods. - Timeline shows the order and duration of major Valheim loading stages.
- Scoped deep attribution shows synchronous Harmony callback time assigned to mods during
ZNetScene.AwakeandObjectDB.Awake. - Unattributed time is work that cannot be safely assigned to one mod.
The slowest entries are useful investigation targets. They are not automatic proof that a mod is broken; manager mods such as Jotunn may perform work on behalf of several other mods.
Example Report
The numbers below are only an example. Your results will depend on your computer, world, server, and installed mods.
Start To Lobby
=== Start To Lobby ===
Result: completed
Total: 2 min 15.781 s
Milestone intervals:
Breakdown: lifecycle execution + remaining time until the next milestone.
0.714 s: LoadTimeProfiler.Patcher.Finish
0.106 s: LoadTimeProfiler.Patcher initialized
82.336 s: BepInEx.Chainloader.Start
32.418 s: BepInEx.Chainloader.Start complete
16.894 s (16.463 s + 0.431 s): FejdStartup.Awake
0.000 s: FejdStartup.Start
0.244 s (0.244 s + 0.000 s): FejdStartup.SetupGui
3.068 s (2.771 s + 0.297 s): FejdStartup.SetupObjectDB
BepInEx startup:
Before Chainloader.Start (includes Chainloader.Initialize): 820.046 ms
Chainloader.Start: 1 min 22.336 s
Plugin construction/Awake/OnEnable:
6.534 s: MonsterLabZ
4.629 s: MonstrumDeepNorth
4.091 s: WarfareFireAndIce
3.134 s: SouthsilArmor
2.965 s: Jewelcrafting
2.770 s: CrystalLights
2.486 s: Warfare
2.367 s: ValheimCuisine
This section helps you find mods that spend a long time being created or enabled before the main menu appears.
Lobby To World
=== Lobby To World ===
Result: completed
Total: 52.154 s
Milestone intervals:
Breakdown: lifecycle execution + remaining time until the next milestone.
0.022 s (0.001 s + 0.021 s): FejdStartup.OnWorldStart
1.468 s (0.000 s + 1.468 s): FejdStartup.TransitionToMainScene
0.233 s (0.000 s + 0.233 s): FejdStartup.LoadMainScene
0.043 s (0.043 s + 0.000 s): Game.Awake
0.009 s (0.008 s + 0.001 s): ZoneSystem.Awake
2.262 s (2.261 s + 0.001 s): ZNet.Awake
15.022 s (13.311 s + 1.711 s): ZNetScene.Awake
8.769 s (7.079 s + 1.690 s): ObjectDB.Awake
0.033 s (0.032 s + 0.001 s): Game.Start
0.438 s (0.437 s + 0.001 s): ZoneSystem.Start
3.387 s (3.387 s + 0.000 s): DungeonDB.Start
4.285 s (0.293 s + 3.992 s): ZNet.Start
16.010 s (0.301 s + 15.709 s): Game.RequestRespawn
0.167 s (0.167 s + 0.000 s): Game.SpawnPlayer
Measured lifecycle execution times (prefix -> finalizer, inclusive):
13.311 s: ZNetScene.Awake
7.079 s: ObjectDB.Awake
3.388 s: DungeonDB.Start
2.262 s: ZNet.Awake
0.437 s: ZoneSystem.Start
0.301 s: Game.RequestRespawn
0.293 s: ZNet.Start
0.167 s: Game.SpawnPlayer
Scoped deep lobby attribution:
Exclusive synchronous Harmony callback time in ObjectDB.Awake and ZNetScene.Awake.
Breakdown order: ObjectDB + ZNetScene.
Prepared callbacks: installed=4, existing=398, skipped=2, failed=0, setup=0.021 s
11.973 s (0.189 s + 11.783 s): Jotunn
4.423 s (4.418 s + 0.005 s): DataForge
0.813 s (0.813 s + 0.000 s): AdminQoL
0.534 s (0.047 s + 0.486 s): EpicMMOSystem
0.246 s (0.211 s + 0.035 s): WarfareFireAndIce
0.180 s (0.116 s + 0.064 s): Jewelcrafting
For a milestone such as 15.022 s (13.311 s + 1.711 s): ZNetScene.Awake, the first value inside the parentheses is measured execution time. The second is the remaining time before the next milestone.
The scoped attribution rows use ObjectDB + ZNetScene order. For example, DataForge used 4.418 s during ObjectDB.Awake and 0.005 s during ZNetScene.Awake in this sample.
Measurement Limits
LoadTimeProfiler safely assigns synchronous work that it can observe. Network waits, coroutine continuations, background work, vanilla work, transpiled code, and work completed before the patcher starts may remain unattributed. Work delegated through another framework may be listed under that framework instead of the mod that requested it.
CHANGELOG
Changelog
1.2.4
- Increased automatic profile-log retention from 10 to 20 reports.
- Refined the package description around faster startup, reliable world joins, and built-in profiling.
1.2.3
- Reworked the README into a shorter installation, configuration, compatibility, and report-reading guide.
- Retained both the Start To Lobby and Lobby To World report examples.
- Removed the remaining legacy-key guidance and retired internal identifier; the runtime and config schema are current-only.
1.2.2
- Added explicit manual overlap guidance to the three acceleration/protection config descriptions and the README.
- Documents which LoadTimeProfiler setting to disable when StartupAccelerator, LocalizationCache, or TimeoutLimit is installed.
- Keeps configuration authoritative: no runtime scan for these conflicting mods, automatic feature override, or additional config option was added.
1.2.1
- Simplified profile reports to measured loading and connection timings plus actionable compatibility warnings.
- Removed acceleration, localization-cache, config-write, and timeout-protection installation status, hit counters, and internal processing-time sections because they do not measure end-to-end time saved.
- Removed all legacy configuration migration and legacy-mod detection/bypass paths. Only the four current
Generalsettings are read; legacy keys are ignored.
1.2.0
- Replaced the single
General.Enabledmaster switch with independent profiling, localization-cache, config-write-coalescing, and timeout-protection settings. - Profiling can now be disabled without disabling startup acceleration or connection protection; no report files or profiling-only runtime hooks are created in that mode.
- Changed the default timeout floor from 90 to 120 seconds, made it configurable through
General.TimeoutProtectionSeconds, and uses0to disable protection while preserving longer original limits. - Added safe migration from
General.Enabledand older per-feature settings, including preservation of the previous all-disabled state. - Keeps only the minimal plugin-discovery and startup-completion hooks required by external localization caching when profiling is disabled.
1.1.13
- Removed the Jotunn localization producer adapter after its pre-
AwakeHarmony preparation was found to initializeLocalizationManagerbeforeJotunn.Main.Instanceexisted. - Keeps Jotunn localization entirely on its original path while retaining the successfully exercised vanilla CSV, canonical
LocalizationManager.Localizer, and manager-libraryLocalizeKeycaches. - Prevents the resulting Jotunn
TypeInitializationExceptioncascade into dependent mods such as VNEI, STUWard, and content registrations.
1.1.12
- Extended startup localization acceleration to repeatedly invoked, canonical
LocalizationManager.Localizer, Jotunn, and manager-libraryLocalizeKeyproducers. - Requires exact identities, method signatures, semantic fields, validated IL call flow, and actual Harmony callback registration; obfuscated AzuAntiCheat localization and stateful/side-effect variants stay on their original paths.
- Added per-adapter fail-open isolation, mutation invalidation, exception-safe startup lifetime cleanup, cache-release on lobby arrival, and adapter installation/hit diagnostics.
1.1.11
- Removed the experimental
ObjectDB.AwakeandZNetScene.AwakeHarmony wrapper batching after warm comparisons showed only a small end-to-end startup improvement. - Restored immediate Harmony wrapper rebuild semantics and removed every
PatchFunctions.UpdateWrapperhook, flush path, statistic, and report entry. - Retains the localization cache, automatic config-write coalescing, profiling, and fixed 90-second connection-timeout protection.
1.1.10
- Removed global
PatchFunctions.UpdateWrappertiming, per-target dictionaries, physical-rebuild statistics, and the startup-onlyUpdateWrapperfinalizer. - Retains exact
ObjectDB.AwakeandZNetScene.Awakebatching through a minimal prefix-only path; non-target requests now perform only fast target checks before continuing normally. - Keeps structural Harmony validation, first-rebuild materialization, exception-safe final flush, compatibility fallback, and concise exact-target flush diagnostics.
1.1.9
- Added structurally verified, Chainloader-scoped Harmony wrapper batching for only the exact parameterless
ObjectDB.AwakeandZNetScene.Awaketargets. - Added
PatchFunctions.UpdateWrapperrequest, physical rebuild, avoided rebuild, target, and final flush diagnostics to the startup report. - Keeps the first rebuild for each exact target, every other Harmony target, and every background-thread patch request on its original immediate path; adds no configuration option and removes the diagnostic hook when Chainloader finishes.
1.1.8
- Removed the exact-version AzuAntiCheat same-launch prehash integration, its background worker, and its report section.
- Restores AzuAntiCheat's original synchronous hash path while retaining normal plugin timing and the minimal 90-second AzuAntiCheat send-queue protection.
1.1.7
- Removed the observation-only FastAssetBundleLoader hash diagnostic and both of its Harmony hooks after confirming that the loader and its cache are effective independently.
- Keeps FastAssetBundleLoader behavior untouched and retains the AzuAntiCheat same-launch asynchronous prehash.
1.1.6
- Removed the 1.1.5 per-callback
FejdStartup.Awakeinstrumentation after its Harmony detours could trigger a native Mono crash immediately after BepInEx chainloader startup. - Retains the safe inclusive
FejdStartup.Awakelifecycle timing and the 1.1.5 AzuAntiCheat prehash and FastAssetBundleLoader hash diagnostics.
1.1.5
- Added an exact-version AzuAntiCheat 4.3.11 integration that starts same-launch per-plugin SHA-256 work on one below-normal background worker while BepInEx continues loading plugins.
- Revalidates file identity before consuming a prehash and uses a fresh synchronous streaming hash on any missing, changed, or failed result; no persistent digest cache is trusted.
- Added narrowly scoped per-mod Harmony callback attribution for
FejdStartup.Awake, with preparation and runtime bookkeeping cost reported separately. - Added diagnostic timing for only FastAssetBundleLoader's original-source hash inside
TryUseCachedBundle(Stream), excluding cache-output verification hashes. - Keeps all three additions behind the existing
General.Enabledmaster switch with no new configuration options.
1.1.4
- Removed the recent spawn-readiness, per-prefab ZDO,
CreateObject, zone-loading hold, Jotunn source-hint, and minimap diagnostic hooks. - Retains the coarse
Game.RequestRespawntoGame.SpawnPlayerlifecycle interval, normal/failure connection outcomes, major world-loading stages, and per-modObjectDB.Awake/ZNetScene.Awakeattribution. - Keeps completed connection report formatting deferred until after
SpawnPlayerreturns.
1.1.3
- Added
Game.UpdateRespawnandFindSpawnPointactivation fallbacks so Unity string-based respawn invocation cannot leave spawn-readiness diagnostics empty. - Added final-target 3x3 ZDO attribution by prefab, including final known counts, a separate transient peak-missing backlog table with sampled first/last/clear observations, approximate inclusive
CreateObjecttime, and registered-instance outcomes. - Adds best-effort Jotunn source metadata or clearly labeled component-presence hints without enabling Jotunn's startup-costly global
ModQuerycollection. - Added bounded
SetLoadingInZone/UnsetLoadingInZonediagnostics, split into center-zone direct blockers and 3x3 instance-order candidates clipped to the final spawn attempt's relevant time windows, with the ordering start broadened to cover active-area sampling delay. - Keeps the new diagnostics observation-only and behind the existing single master switch, with no new configuration options.
- Separately reports measured in-path diagnostic work and defers post-endpoint connection-report assembly through BepInEx's persistent main-thread queue until after
SpawnPlayerreturns, with a generation guard against mixing a newer session's detail.
1.1.2
- Added observation-only spawn-readiness diagnostics for the interval between
_RequestRespawnactivation andSpawnPlayer, plus connection-wide minimap call timing. - Separately reports the built-in logout/custom-spawn gate, target-zone readiness, active-area readiness, and
IsAreaReadycompletion. - Samples known 3x3 spawn-sector ZDO totals and uninstantiated valid objects periodically at no more than 1 Hz, plus a terminal readiness sample, without changing loading behavior.
- Reports minimap cache hits, misses, and inclusive
GenerateWorldMapcall time relative to respawn activation so map regeneration can be distinguished from spawn-area loading. - Keeps the diagnostics always on with the existing master switch, buffers samples in memory without per-sample disk writes, and reports a lower bound for measured diagnostic work.
1.1.1
- Replaced the per-feature settings with one
General.Enabledmaster switch and automatically removes the retired settings from existing config files. - Replaced exhaustive connection compatibility analysis with a minimal fixed 90-second floor for vanilla ZRpc, Jotunn, and known ServerSync/AzuAntiCheat send queues.
- Preserves timeout values already longer than 90 seconds and leaves fragment-cache lifetimes unchanged.
- Removed experimental Harmony wrapper rebuild batching and connection-time fragment patching.
- Added event-based connection outcomes that separately report normal connection time, first failure-decision time, and return-to-lobby/error-display time without per-frame polling.
- Starts connection timing only after
TransitionToMainSceneaccepts the transition, and distinguishes a benign lobby return from ServerSync/AzuAntiCheat failures that set their terminal status afterGame.Logout.
1.1.0
- Added safe localization CSV acceleration that replays captured
AddWordsequences into Valheim's existing translation dictionary and keeps other mods' prefix/postfix callbacks active. - Added Chainloader-scoped automatic config-save coalescing without changing a plugin's
SaveOnConfigSetpolicy or delaying explicitSave()calls. - Added opt-in Harmony wrapper rebuild batching. It remains disabled by default because mods that use a patch immediately after installing it can be incompatible.
- Added a structurally verified connection-stability layer for vanilla
ZRpc, JotunnCustomRPC, embedded/standalone ServerSync copies, and obfuscated AzuAntiCheat queue waits. - Extended compatible fragment receive-cache lifetimes together with queue timeouts to reduce the risk of the original 60-second cache expiring during a slow fragmented transfer.
- Added acceleration and stability diagnostics to both Start To Lobby and Lobby To World reports.
- Added decompiled compatibility references and a detailed integration analysis for Jotunn 2.29.2, AzuAntiCheat 4.3.11, and the supplied ServerSync build.
1.0.1
- Fixed dedicated-server joins not preparing deep lobby attribution, so client-side per-mod
ObjectDB.AwakeandZNetScene.Awaketimings are now recorded when connecting to a dedicated server. - Generalized the active lifecycle callback blocklist so attribution can be prepared safely from both
JoinServerand localOnWorldStartpaths. - Updated the Thunderstore package icon.
1.0.0
- Initial public release of LoadTimeProfiler.
- Supports client loading and dedicated server startup profiling.