Example #1
0
            public TraceContent(List <RawEvent> events, Dictionary <ulong, string> strings,
                                int version, long frequency, HashSet <ulong> timers, Dictionary <ulong, RawEvent> stackInfo)
            {
                if (frequency == 0)
                {
                    throw new InvalidTraceException("no EvFrequency event");
                }
                Strings   = strings;
                Version   = version;
                Frequency = frequency;
                Timers    = timers;
                StackInfo = stackInfo;
                Timeline  = new Dictionary <int, List <TraceEvent> >();

                var  lastGs = new Dictionary <int, ulong>();
                long lastSeq = 0L, lastTs = 0L;
                var  lastG = 0UL;
                var  lastP = 0;

                foreach (var ev in events)
                {
                    var argCount = ev.NumberOfArgs(version);
                    var desc     = EventDescription.Of(ev.Type);
                    if (ev.Args.Length != argCount)
                    {
                        throw new InvalidTraceException(
                                  $"${desc.Name} has wrong number of args at {ev.Offset}: want {argCount}, got {ev.Args.Length}");
                    }
                    if (ev.Type == EventType.Batch)
                    {
                        lastGs[lastP] = lastG;
                        lastP         = (int)ev.Args[0];
                        lastG         = lastGs.GetValueOrDefault(lastP, 0UL);
                        if (version < 1007)
                        {
                            lastSeq = (long)ev.Args[1];
                            lastTs  = (long)ev.Args[2];
                        }
                        else
                        {
                            lastTs = (long)ev.Args[1];
                        }
                    }
                    else
                    {
                        var e = new TraceEvent(ev.Offset, ev.Type, lastP, lastG);
                        int argOffset;
                        if (version < 1007)
                        {
                            e.Seq     = lastSeq + (long)ev.Args[0];
                            e.Ts      = lastTs + (long)ev.Args[1];
                            lastSeq   = e.Seq;
                            argOffset = 2;
                        }
                        else
                        {
                            e.Ts      = lastTs + (long)ev.Args[0];
                            argOffset = 1;
                        }

                        lastTs = e.Ts;
                        for (var i = argOffset; i < argCount; i++)
                        {
                            if (i == argCount - 1 && desc.Stack)
                            {
                                e.StackId = ev.Args[i];
                            }
                            else
                            {
                                e.Args[i - argOffset] = ev.Args[i];
                            }
                        }

                        switch (ev.Type)
                        {
                        case EventType.GoStart:
                        case EventType.GoStartLocal:
                        case EventType.GoStartLabel:
                            lastG = e.Args[0];
                            e.G   = lastG;
                            if (ev.Type == EventType.GoStartLabel)
                            {
                                e.StringArgs = new[] { Strings[e.Args[2]] }
                            }
                            ;
                            break;

                        case EventType.GcStwStart:
                            e.G          = 0;
                            e.StringArgs = e.Args[0] switch
                            {
                                0 => new[] { "mark termination" },
                                1 => new[] { "sweep termination" },
                                var x => throw new InvalidTraceException($"unknown STW kind {x}")
                            };
                            break;

                        case EventType.GcStart:
                        case EventType.GcDone:
                        case EventType.GcStwDone:
                            e.G = 0;
                            break;

                        case EventType.GoEnd:
                        case EventType.GoStop:
                        case EventType.GoSched:
                        case EventType.GoPreempt:
                        case EventType.GoSleep:
                        case EventType.GoBlock:
                        case EventType.GoBlockSend:
                        case EventType.GoBlockRecv:
                        case EventType.GoBlockSelect:
                        case EventType.GoBlockSync:
                        case EventType.GoBlockCond:
                        case EventType.GoBlockNet:
                        case EventType.GoSysBlock:
                        case EventType.GoBlockGc:
                            lastG = 0;
                            break;

                        case EventType.GoSysExit:
                        case EventType.GoWaiting:
                        case EventType.GoInSyscall:
                            e.G = e.Args[0];
                            break;

                        case EventType.UserTaskCreate:
                            // e.Args 0: taskID, 1:parentID, 2:nameID
                            e.StringArgs = new[] { strings[e.Args[2]] };
                            break;

                        case EventType.UserRegion:
                            // e.Args 0: taskID, 1: mode, 2:nameID
                            e.StringArgs = new[] { strings[e.Args[2]] };
                            break;

                        case EventType.UserLog:
                            // e.Args 0: taskID, 1:keyID, 2: stackID
                            e.StringArgs = new[] { strings[e.Args[1]], ev.StringArgs ![0] };
Example #2
0
        private TraceContent ParseContent()
        {
            var events    = new List <RawEvent>();
            var strings   = new Dictionary <ulong, string>();
            var stackInfo = new Dictionary <ulong, RawEvent>();
            var version   = ParseHeader();
            var frequency = 0L;
            var timers    = new HashSet <ulong>();

            using var progress = _registry?.Start("Load trace", "Read and parse the binary trace data");

            var end = _reader.BaseStream.Length;

            while (Position < end)
            {
                if (!(progress is null))
                {
                    progress.PercentComplete = Position / (float)end;
                }
                var eventStartPosition    = Position;
                var eventTypeAndArgsCount = _reader.ReadByte();
                var type       = (EventType)(eventTypeAndArgsCount & ~(0b11 << 6));
                var argsCount  = (eventTypeAndArgsCount >> 6) + 1;
                var inlineArgs = (byte)4;
                if (version < 1007)
                {
                    argsCount++;
                    inlineArgs++;
                }

                if (type == EventType.None || EventDescription.Of(type).MinVersion > version)
                {
                    throw new InvalidTraceException("unknown type");
                }

                if (type == EventType.String)
                {
                    // String dictionary entry [ID, length, string].
                    var id = ReadVal();
                    if (id == 0)
                    {
                        throw new InvalidTraceException($"{Position} has invalid id 0");
                    }
                    if (strings.ContainsKey(id))
                    {
                        throw new InvalidTraceException($"{Position} has duplicate id {id}");
                    }
                    var value = ReadStr();
                    if (value.Length == 0)
                    {
                        throw new InvalidTraceException($"{Position} has invalid length 0");
                    }
                    strings[id] = value;
                    continue;
                }

                var ev = new RawEvent(type, (int)eventStartPosition);
                if (argsCount < inlineArgs)
                {
                    ev.Args = new ulong[argsCount];
                    for (var i = 0; i < argsCount; i++)
                    {
                        ev.Args[i] = ReadVal();
                    }
                }
                else
                {
                    var evLength = ReadVal();
                    var start    = _reader.BaseStream.Position;
                    var buffer   = new List <ulong>();
                    while (evLength > (ulong)(_reader.BaseStream.Position - start))
                    {
                        var arg = ReadVal();
                        buffer.Add(arg);
                    }

                    if (evLength != (ulong)(Position - start))
                    {
                        throw new InvalidTraceException(
                                  $"event has wrong length at {Position}, want: {evLength}, got: {Position - start}");
                    }
                    ev.Args = buffer.ToArray();
                }

                if (ev.Type == EventType.UserLog)
                {
                    ev.StringArgs = new[] { ReadStr() }
                }
                ;

                switch (ev.Type)
                {
                case EventType.Frequency:
                    frequency = (long)ev.Args[0];
                    if (frequency <= 0)
                    {
                        throw new TimeOrderException();
                    }
                    break;

                case EventType.TimerGoroutine:
                    timers.Add(ev.Args[0]);
                    break;

                case EventType.Stack:
                    if (ev.Args.Length < 2)
                    {
                        throw new InvalidTraceException("Stack event should have at least 2 arguments");
                    }
                    var size = ev.Args[1];
                    if (size > 1000)
                    {
                        throw new InvalidTraceException($"Stack event bad number of frames {size}");
                    }
                    var want = version < 1007 ? 4 + 4 * size : 2 + 4 * size;
                    if (ev.Args.Length != (int)want)
                    {
                        throw new InvalidTraceException(
                                  $"Stack event has wrong number of arguments want {want} got {ev.Args.Length}");
                    }

                    stackInfo[ev.Args[0]] = ev;
                    break;

                default:
                    events.Add(ev);
                    break;
                }
            }

            return(new TraceContent(events, strings, version, frequency, timers, stackInfo));
        }