Skip to content

Namespace update - #40

Open
buttheadbob wants to merge 5 commits into
TorchAPI:masterfrom
buttheadbob:master
Open

Namespace update#40
buttheadbob wants to merge 5 commits into
TorchAPI:masterfrom
buttheadbob:master

Conversation

@buttheadbob

Copy link
Copy Markdown

Removed the following:

  • using Sandbox.Game.Entities.Cube;
  • using Sandbox.Game.Entities.EnvironmentItems;

Compiled. Server runs. !profile sim returns sim data. That was the extent of testing.

Removed the following:
- using Sandbox.Game.Entities.Cube;
- using Sandbox.Game.Entities.EnvironmentItems;
Compiled. Server runs. !profile sim returns sim data. That was the extent of testing.
BUG FIXES:
FastConcurrentQueue: Delete entire file (132 lines). Replaced with
System.Collections.Concurrent.ConcurrentQueue<ProfilerResult> in
ProfilerResultQueue. The custom FastConcurrentQueue/QueuePair/
NullableArrayList implementation had unsynchronized Expand() in
NullableArrayList causing two threads to share a single non-thread-safe
Queue<T> instance, leading to Array.Copy failures and crashes under
heavy concurrent profiling load.
StringIndexer: Add lock around List<string> _mapping access.
IndexOf() and StringAt() can be called concurrently from multiple
threads via CustomProfiling.Profile() at runtime, corrupting the
internal list state.
ProfilerResultQueue consumer loop:
- Remove racy _profilers.Count == 0 early-exit (non-atomic check
allowed results to be silently dropped or accumulate unbounded)
- Wrap consumer body in try/catch with retry (1s backoff, logs
warning) to prevent silent consumer death causing unbounded
memory growth
- Only sleep when queue is empty (batch-drain, no forced 100ms
batching penalty)
- Drop Alternate() call (ConcurrentQueue handles concurrent
read/write natively)
FEATURES:
!profile diagnose command:
- Runs 7 profilers simultaneously: GameLoopProfiler, GridProfiler,
BlockTypeProfiler, PlayerProfiler, FactionProfiler, PhysicsProfiler,
SessionComponentsProfiler
- Tiered output: frame breakdown with percentages, top grids/block
types/players/factions, physics clusters with per-grid drill-down,
top session components
- Discord-native formatting: bold headers, '>' block quotes,
'—' separators, compact single-line frame breakdown; no code blocks
- In-game chat format: compact line-by-line with abbreviated labels
- Physics cluster drill-down queries HkWorld entities on game thread
to identify top grids within each cluster
- Player/faction grid counts computed on game thread for Discord output
BUILD:
csproj: Add packaging targets (matching Advanced PB Limiter pattern)
- Copy manifest.xml to output directory (PreserveNewest)
- Zip output (DLL, PDB, manifest.xml) to Build/Profiler.zip
- Uses PowerShell Compress-Archive for standard zip format (compatible
with Torch PluginManager)
- Remove unused packages.config reference
MISC:
ProfilerCommands: Use C#8 'using var' declarations in existing commands
- PlayerProfiler: Fix "Collection was modified" InvalidOperationException
by copying grid.BigOwners with .ToList() before enumeration. The game
thread can mutate BigOwners while the profiler worker thread iterates.
- BaseProfiler: Capture _endFrameCount and _endTime at MarkEnd() time
and freeze them, so GetResult() reports the snapshot at end-marker
rather than at GetResult() call time (results were leaking extra
frames/time between MarkEnd and GetResult).
- MyPhysics_StepWorlds: Add volatile to _simulatesParallel field to
prevent stale reads from JIT/CPU optimizations when accessed across
threads.
- ProfilerCommands: Add 150ms extra delay after profiling period to
allow the queue of profiler results to drain before MarkEnd() is
called. Prevents results from being missed at the tail end.
- Build packaging updated.
…ugin consumption
Extract the Diagnose() profiling logic into a standalone static API
(ProfilerApi.RunDiagnoseAsync) that returns structured POCOs instead of
formatted text. This enables external plugins (e.g. Orion) to invoke
comprehensive diagnostics programmatically and receive serializable data.
New files:
- DiagnoseResult.cs: POCOs for all result categories (GridEntry,
BlockTypeEntry, PlayerEntry, FactionEntry, ClusterEntry, SessionEntry).
Primitive types only, no game object references, fully serializable.
- ProfilerApi.cs: Static RunDiagnoseAsync(seconds, topCount) that mirrors
the exact profiler lifecycle of ProfilerCommands.Diagnose() -- same 7
profilers, same ProfilerResultQueue.Profile() registration, same
MarkStart/Delay/MarkEnd/GetResult cycle.
Key design decisions:
- FrameCategories returned as Dictionary<string,double> with named keys
(Update, Physics, Network, Replication, Session, GPS, ParallelWait, Lock)
- topCount governs all entity lists including clusters; nested grids per
cluster hardcoded at 3
- Player/faction grid counts always computed (not gated by discordDisplay)
- TotalFrameCount kept as ulong to match internal profiler type
- ProfilerCommands.Diagnose() left untouched to avoid risk to existing command
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@buttheadbob