/// <summary> /// Given a stream with the symbols, this function parses the stream and stores the contents in the given mapper /// </summary> public void ParseSymbolFile(Stream stream, Mapper mapper) { FastStream source = new FastStream(stream); source.MoveNext(); // Prime Current. this.SkipPreamble(source); // Remove encoding stuff if it's there source.SkipWhiteSpace(); StringBuilder sb = new StringBuilder(); Func <byte, bool> untilWhiteSpace = (byte c) => { return(!char.IsWhiteSpace((char)c)); }; while (!source.EndOfStream) { source.ReadAsciiStringUpToTrue(sb, untilWhiteSpace); ulong start = ulong.Parse(sb.ToString(), System.Globalization.NumberStyles.HexNumber); sb.Clear(); source.SkipWhiteSpace(); source.ReadAsciiStringUpToTrue(sb, untilWhiteSpace); ulong size = ulong.Parse(sb.ToString(), System.Globalization.NumberStyles.HexNumber); sb.Clear(); source.SkipWhiteSpace(); source.ReadAsciiStringUpTo('\n', sb); string symbol = sb.ToString().TrimEnd(); sb.Clear(); mapper.Add(start, size, symbol); source.SkipWhiteSpace(); } }
private StackFrame ReadFrame(FastStream source) { StringBuilder sb = new StringBuilder(); // Address source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(' ', sb); string address = sb.ToString(); sb.Clear(); // Trying to get the module and symbol... source.SkipWhiteSpace(); source.ReadAsciiStringUpToLastBeforeTrue('(', sb, delegate(byte c) { if (c != '\n' && !source.EndOfStream) { return(true); } return(false); }); string assumedSymbol = sb.ToString(); sb.Clear(); source.ReadAsciiStringUpTo('\n', sb); string assumedModule = sb.ToString(); sb.Clear(); assumedModule = RemoveOuterBrackets(assumedModule.Trim()); string actualModule = assumedModule; string actualSymbol = RemoveOuterBrackets(assumedSymbol.Trim()); if (assumedModule.EndsWith(".map")) { string[] moduleSymbol = GetSymbolFromMicrosoftMap(assumedSymbol, assumedModule); actualSymbol = string.IsNullOrEmpty(moduleSymbol[1]) ? assumedModule : moduleSymbol[1]; actualModule = moduleSymbol[0]; } // Can't use Path.GetFileName Because it throws on illegal Windows characters actualModule = GetFileName(actualModule); actualSymbol = RemoveOffset(actualSymbol.Trim()); return(new StackFrame(address, actualModule, actualSymbol)); }
/// <summary> /// Given a stream that contains PerfInfo commands, parses the stream and stores data in the given dictionary. /// Key: somedll.ni.dll Value: {some guid} /// </summary> public void ParsePerfInfoFile(Stream stream, Dictionary <string, string> guids) { FastStream source = new FastStream(stream); source.MoveNext(); source.SkipWhiteSpace(); StringBuilder sb = new StringBuilder(); while (!source.EndOfStream) { source.ReadAsciiStringUpTo(';', sb); source.MoveNext(); string command = sb.ToString(); sb.Clear(); if (command == "ImageLoad") // TODO: should be a constant maybe? { source.ReadAsciiStringUpTo(';', sb); string path = sb.ToString(); sb.Clear(); source.MoveNext(); source.ReadAsciiStringUpTo(';', sb); string guid = sb.ToString().TrimEnd(); sb.Clear(); guids[GetFileName(path)] = guid; } source.SkipUpTo('\n'); source.MoveNext(); } }
// If the length returned is -1, then there's no more stream in the // master source, otherwise, buffer should be valid with the length returned // Note: This needs to be thread safe private FastStream GetNextSubStream(FastStream source) { lock (bufferLock) { if (source.EndOfStream) { return(null); } uint startLook = (uint)this.BufferSize * 3 / 4; uint length; bool isComplete; isComplete = this.TryGetCompleteBuffer(source, startLook, 1, source.MaxPeek - TruncateString.Length, out length); FastStream subStream = source.ReadSubStream((int)length, trail: (!isComplete ? TruncateString : null)); if (!isComplete) { this.FindValidStartOn(source); } source.SkipWhiteSpace(); return(subStream); } }
/// <summary> /// Tries to skip the byte order marks at the beginning of the given fast stream. /// </summary> public void SkipPreamble(FastStream source) { source.MoveNext(); // Skip Sentinal value while (Encoding.UTF8.GetPreamble().Contains(source.Current)) // Skip the BOM marks if there are any { source.MoveNext(); } source.SkipWhiteSpace(); // Make sure we start at the beginning of a sample. }
/// <summary> /// Given a stream that contains PerfInfo commands, parses the stream and stores data in the given dictionary. /// Key: somedll.ni.dll Value: {some guid} /// </summary> public void ParsePerfInfoFile(Stream stream, Dictionary <string, string> guids, Dictionary <string, ulong> baseAddresses) { FastStream source = new FastStream(stream); source.MoveNext(); source.SkipWhiteSpace(); StringBuilder sb = new StringBuilder(); while (!source.EndOfStream) { source.ReadAsciiStringUpTo(';', sb); source.MoveNext(); string command = sb.ToString(); sb.Clear(); if (command == "ImageLoad") // TODO: should be a constant maybe? { source.ReadAsciiStringUpTo(';', sb); string path = sb.ToString(); sb.Clear(); source.MoveNext(); source.ReadAsciiStringUpTo(';', sb); string guid = sb.ToString().TrimEnd(); sb.Clear(); source.MoveNext(); guids[GetFileName(path)] = guid; // Check to see if the base address has been appended to the line. if (source.Current != '\n') { sb.Clear(); source.ReadAsciiStringUpTo(';', sb); string strBaseAddr = sb.ToString().TrimEnd(); if (!string.IsNullOrEmpty(strBaseAddr)) { ulong baseAddr = ulong.Parse(strBaseAddr, System.Globalization.NumberStyles.HexNumber); baseAddresses[GetFileName(path)] = baseAddr; } } } source.SkipUpTo('\n'); source.MoveNext(); } }
private IEnumerable <LinuxEvent> NextEvent(Regex regex, FastStream source) { string line = string.Empty; while (true) { source.SkipWhiteSpace(); if (source.EndOfStream) { break; } EventKind eventKind = EventKind.Cpu; StringBuilder sb = new StringBuilder(); // Command - Stops at first number AFTER whitespace while (!this.IsNumberChar((char)source.Current)) { sb.Append(' '); source.ReadAsciiStringUpToTrue(sb, delegate(byte c) { return(!char.IsWhiteSpace((char)c)); }); source.SkipWhiteSpace(); } string comm = sb.ToString().Trim(); sb.Clear(); // Process ID int pid = source.ReadInt(); source.MoveNext(); // Move past the "/" // Thread ID int tid = source.ReadInt(); // CPU source.SkipWhiteSpace(); source.MoveNext(); // Move past the "[" int cpu = source.ReadInt(); source.MoveNext(); // Move past the "]" // Time source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(':', sb); double time = double.Parse(sb.ToString()) * 1000; // To convert to MSec sb.Clear(); source.MoveNext(); // Move past ":" // Time Property source.SkipWhiteSpace(); int timeProp = -1; if (this.IsNumberChar((char)source.Current)) { timeProp = source.ReadInt(); } // Event Name source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(':', sb); string eventName = sb.ToString(); sb.Clear(); source.MoveNext(); // Event Properties // I mark a position here because I need to check what type of event this is without screwing up the stream var markedPosition = source.MarkPosition(); source.ReadAsciiStringUpTo('\n', sb); string eventDetails = sb.ToString().Trim(); sb.Clear(); if (eventDetails.Length >= SchedulerEvent.Name.Length && eventDetails.Substring(0, SchedulerEvent.Name.Length) == SchedulerEvent.Name) { eventKind = EventKind.Scheduler; } // Now that we know the header of the trace, we can decide whether or not to skip it given our pattern if (regex != null && !regex.IsMatch(eventName)) { while (true) { source.MoveNext(); if (this.IsEndOfSample(source, source.Current, source.Peek(1))) { break; } } yield return(null); } else { LinuxEvent linuxEvent; Frame threadTimeFrame = null; // For the sake of immutability, I have to do a similar if-statement twice. I'm trying to figure out a better way // but for now this will do. ScheduleSwitch schedSwitch = null; if (eventKind == EventKind.Scheduler) { source.RestoreToMark(markedPosition); schedSwitch = this.ReadScheduleSwitch(source); source.SkipUpTo('\n'); } IEnumerable <Frame> frames = this.ReadFramesForSample(comm, pid, tid, threadTimeFrame, source); if (eventKind == EventKind.Scheduler) { linuxEvent = new SchedulerEvent(comm, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames, schedSwitch); } else { linuxEvent = new CpuEvent(comm, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames); } yield return(linuxEvent); } } }
private ScheduleSwitch ReadScheduleSwitch(FastStream source) { StringBuilder sb = new StringBuilder(); // There are two formats for ScheduleSwitch serialization: // Example1: sched:sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=rcu_sched next_pid=8 next_prio=120 // Example2: sched:sched_switch: perf_4.9:3005 [49] S ==> swapper/2:0 [120] // Skip "sched:sched_switch: " source.SkipUpTo(' '); source.SkipSpace(); // Figure out which format we have. var pos = source.MarkPosition(); // Look for 'prev_comm' (Example1) source.ReadFixedString(9, sb); string nextField = sb.ToString(); sb.Clear(); if (nextField.Equals("prev_comm")) { // This is of the format in Example1. source.SkipUpTo('='); source.MoveNext(); source.ReadAsciiStringUpTo(' ', sb); string prevComm = sb.ToString(); sb.Clear(); source.SkipUpTo('='); source.MoveNext(); int prevTid = source.ReadInt(); source.SkipUpTo('='); source.MoveNext(); int prevPrio = source.ReadInt(); source.SkipUpTo('='); source.MoveNext(); char prevState = (char)source.Current; source.MoveNext(); source.SkipUpTo('n'); // this is to bypass the ==> source.SkipUpTo('='); source.MoveNext(); source.ReadAsciiStringUpTo(' ', sb); string nextComm = sb.ToString(); sb.Clear(); source.SkipUpTo('='); source.MoveNext(); int nextTid = source.ReadInt(); source.SkipUpTo('='); source.MoveNext(); int nextPrio = source.ReadInt(); return(new ScheduleSwitch(prevComm, prevTid, prevPrio, prevState, nextComm, nextTid, nextPrio)); } else { // This is of the format in Example2. // Restore the position back so the full text can be parsed here. source.RestoreToMark(pos); source.ReadAsciiStringUpTo(':', sb); string prevComm = sb.ToString(); sb.Clear(); source.MoveNext(); int prevTid = source.ReadInt(); source.SkipUpTo('['); source.MoveNext(); int prevPrio = source.ReadInt(); source.MoveNext(); source.SkipWhiteSpace(); char prevState = (char)source.Current; source.SkipUpTo('>'); // this is to bypass the ==> source.MoveNext(); source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(':', sb); string nextComm = sb.ToString(); sb.Clear(); source.MoveNext(); int nextTid = source.ReadInt(); source.SkipUpTo('['); source.MoveNext(); int nextPrio = source.ReadInt(); return(new ScheduleSwitch(prevComm, prevTid, prevPrio, prevState, nextComm, nextTid, nextPrio)); } }
private IEnumerable <LinuxEvent> NextEvent(Regex regex, FastStream source) { string line = string.Empty; while (true) { source.SkipWhiteSpace(); if (source.EndOfStream) { break; } EventKind eventKind = EventKind.Cpu; StringBuilder sb = new StringBuilder(); // Fetch Command (processName) - Stops when it sees the pattern \s+\d+/\d int idx = FindEndOfProcessCommand(source); if (idx < 0) { break; } source.ReadFixedString(idx, sb); source.SkipWhiteSpace(); string processCommand = sb.ToString(); sb.Clear(); // Process ID int pid = source.ReadInt(); // Detect whether or not the Thread ID is present. int tid = pid; if (source.Peek(0) == '/') { // Thread ID source.MoveNext(); // Move past the "/" tid = source.ReadInt(); } // CPU source.SkipWhiteSpace(); int cpu = -1; if (source.Peek(0) == '[') { source.MoveNext(); // Move past the "[" cpu = source.ReadInt(); source.MoveNext(); // Move past the "]" } // Time source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(':', sb); double time = double.Parse(sb.ToString(), CultureInfo.InvariantCulture) * 1000; // To convert to MSec sb.Clear(); source.MoveNext(); // Move past ":" // Time Property source.SkipWhiteSpace(); int timeProp = -1; if (IsNumberChar((char)source.Current)) { timeProp = source.ReadInt(); } // Event Name source.SkipWhiteSpace(); source.ReadAsciiStringUpTo(':', sb); string eventName = sb.ToString(); sb.Clear(); source.MoveNext(); // Event Properties // I mark a position here because I need to check what type of event this is without screwing up the stream var markedPosition = source.MarkPosition(); source.ReadAsciiStringUpTo('\n', sb); string eventDetails = sb.ToString().Trim(); sb.Clear(); if (eventDetails.Length >= SchedulerEvent.Name.Length && eventDetails.Substring(0, SchedulerEvent.Name.Length) == SchedulerEvent.Name) { eventKind = EventKind.Scheduler; } else if (eventDetails.Length > ThreadExitEvent.Name.Length && eventDetails.Substring(0, ThreadExitEvent.Name.Length) == ThreadExitEvent.Name) { eventKind = EventKind.ThreadExit; } // Now that we know the header of the trace, we can decide whether or not to skip it given our pattern if (regex != null && !regex.IsMatch(eventName)) { while (true) { source.MoveNext(); if (IsEndOfSample(source, source.Current, source.Peek(1))) { break; } } yield return(null); } else { LinuxEvent linuxEvent; Frame threadTimeFrame = null; // For the sake of immutability, I have to do a similar if-statement twice. I'm trying to figure out a better way // but for now this will do. ScheduleSwitch schedSwitch = null; if (eventKind == EventKind.Scheduler) { source.RestoreToMark(markedPosition); schedSwitch = ReadScheduleSwitch(source); source.SkipUpTo('\n'); } ThreadExit exit = null; if (eventKind == EventKind.ThreadExit) { source.RestoreToMark(markedPosition); exit = ReadExit(source); source.SkipUpTo('\n'); } IEnumerable <Frame> frames = ReadFramesForSample(processCommand, pid, tid, threadTimeFrame, source); if (eventKind == EventKind.Scheduler) { linuxEvent = new SchedulerEvent(processCommand, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames, schedSwitch); } else if (eventKind == EventKind.ThreadExit) { linuxEvent = new ThreadExitEvent(processCommand, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames, exit); } else { linuxEvent = new CpuEvent(processCommand, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames); } yield return(linuxEvent); } } }