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);
        }
示例#2
0
 public ProfilerRequest(ProfilerRequestType type, ulong samplingTicks)
 {
     Type          = type;
     SamplingTicks = samplingTicks;
 }