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] };
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)); }