private void Handle(ProfilerRequestType type) { var ticks = SampleTicks; var top = Top; long? factionMask = null; long? playerMask = null; long? entityMask = null; MyModContext modFilter = null; long? reportGPS = null; foreach (var arg in Context.Args) { if (arg.StartsWith("--ticks=")) { ticks = ulong.Parse(arg.Substring("--ticks=".Length)); } else if (arg.StartsWith("--top=")) { top = int.Parse(arg.Substring("--top=".Length)); } else if (arg.StartsWith("--faction=")) { var name = arg.Substring("--faction=".Length); if (!ResolveFaction(name, out var id)) { Context.Respond($"Failed to find faction {name}"); return; } factionMask = id?.FactionId ?? 0; } else if (arg.StartsWith("--player=")) { var name = arg.Substring("--player=".Length); if (!ResolveIdentity(name, out var id)) { Context.Respond($"Failed to find player {name}"); return; } playerMask = id?.IdentityId ?? 0; } else if (arg.StartsWith("--entity=")) { var id = long.Parse(arg.Substring("--entity=".Length)); var ent = MyEntities.GetEntityById(id); if (ent == null) { Context.Respond($"Failed to find entity with ID={id}"); return; } entityMask = ent.EntityId; } else if (arg == "--this") { var controlled = Context.Player?.Controller?.ControlledEntity?.Entity; if (controlled == null) { Context.Respond($"You must have a controlled entity to use the --this argument"); return; } MyCubeGrid grid; var tmp = controlled; do { grid = tmp as MyCubeGrid; if (grid != null) { break; } tmp = tmp.Parent; } while (tmp != null); if (grid == null) { Context.Respond($"You must be controlling a grid to use the --this argument"); return; } entityMask = grid.EntityId; } else if (arg == "--gps") { var controlled = Context.Player; if (controlled == null) { Context.Respond($"GPS return can only be used by players"); return; } reportGPS = controlled.IdentityId; CleanGPS(reportGPS.Value); } else if (arg.StartsWith("--mod=")) { var nam = arg.Substring("--mod=".Length); foreach (var mod in MySession.Static.Mods) { var ctx = new MyModContext(); ctx.Init(mod); if (ctx.ModId.Equals(nam, StringComparison.OrdinalIgnoreCase) || ctx.ModId.Equals(nam + ".sbm", StringComparison.OrdinalIgnoreCase) || ctx.ModName.Equals(nam, StringComparison.OrdinalIgnoreCase)) { modFilter = ctx; break; } } if (nam.Equals("base", StringComparison.OrdinalIgnoreCase) || nam.Equals("keen", StringComparison.OrdinalIgnoreCase)) { modFilter = MyModContext.BaseGame; } // ReSharper disable once InvertIf if (modFilter == null) { Context.Respond($"Failed to find mod {nam}"); return; } } } if (!ProfilerData.ChangeMask(playerMask, factionMask, entityMask, modFilter)) { Context.Respond($"Failed to change profiling mask. There can only be one."); return; } var req = new ProfilerRequest(type, ticks); var context = Context; req.OnFinished += (printByPassCount, results) => { for (var i = 0; i < Math.Min(top, results.Length); i++) { var r = results[i]; var formattedTime = FormatTime(r.MsPerTick); var hits = results[i].HitsPerTick; var hitsUnit = results[i].HitsUnit; var formattedName = string.Format(r.Name ?? "unknown", i, formattedTime, hits, hitsUnit); var formattedDesc = string.Format(r.Description ?? "", i, formattedTime, hits, hitsUnit); if (reportGPS.HasValue || !r.Position.HasValue) { context.Respond(printByPassCount ? $"{formattedName} {formattedDesc} took {hits:F1} {hitsUnit}" : $"{formattedName} {formattedDesc} took {formattedTime} ({hits:F1} {hitsUnit})"); if (!reportGPS.HasValue || !r.Position.HasValue) { continue; } var gpsDisplay = printByPassCount ? $"{hits:F1} {hitsUnit} {formattedName}" : $"{formattedTime} {formattedName}"; var gpsDesc = formattedDesc + $" {hits:F1} {hitsUnit}"; var gps = new MyGps(new MyObjectBuilder_Gps.Entry { name = gpsDisplay, DisplayName = gpsDisplay, coords = r.Position.Value, showOnHud = true, color = VRageMath.Color.Purple, description = gpsDesc, entityId = 0, isFinal = false }); MyAPIGateway.Session?.GPS.AddGps(reportGPS.Value, gps); var set = GpsForIdentity.GetOrAdd(reportGPS.Value, (x) => new HashSet <int>()); lock (set) set.Add(gps.Hash); continue; } var posData = $"{r.Position.Value.X.ToString(ProfilerRequest.DistanceFormat)},{r.Position.Value.Y.ToString(ProfilerRequest.DistanceFormat)},{r.Position.Value.Z.ToString(ProfilerRequest.DistanceFormat)}"; context.Respond( printByPassCount ? $"{formattedName} {formattedDesc} took ({hits:F1} {hitsUnit}) @ {posData}" : $"{formattedName} {formattedDesc} took {formattedTime} ({hits:F1} {hitsUnit}) @ {posData}"); } { var totalUpdates = 0d; var totalTime = 0d; string hitsUnit = null; for (var i = Math.Min(top, results.Length) + 1; i < results.Length; i++) { var r = results[i]; totalUpdates += r.HitsPerTick; totalTime += r.MsPerTick; hitsUnit = r.HitsUnit; } if (totalUpdates > 0) { context.Respond(printByPassCount ? $"Others took {totalUpdates:F1} {hitsUnit}" : $"Others took {FormatTime(totalTime)} ({totalUpdates:F1} {hitsUnit})"); } } }; var timeEstMs = ticks * MyEngineConstants.UPDATE_STEP_SIZE_IN_SECONDS * 1000f / (MyMultiplayer.Static?.ServerSimulationRatio ?? 1); context.Respond($"Profiling for {type} started, results in {ticks} ticks (about {FormatTime(timeEstMs)})"); ProfilerData.Submit(req); }
public ProfilerRequest(ProfilerRequestType type, ulong samplingTicks) { Type = type; SamplingTicks = samplingTicks; }