void Read(TextReader reader) { // TODO this is relatively inefficient. var regEx = new Regex(@"^\s*(\d+)\s*(\d+)\s*\[\s*(\d+)\s*\]\s*(\S*?)!?(.*)"); var stack = new GrowableArray <WTStackElem>(); WTStackElem elem = new WTStackElem(); long time = 0; for (; ;) { var line = reader.ReadLine(); if (line == null) { break; } var match = regEx.Match(line); if (match.Success) { int excInstrSoFar = int.Parse(match.Groups[1].Value); int depth = int.Parse(match.Groups[3].Value); string module = match.Groups[4].Value; string method = match.Groups[5].Value; var moduleIndex = ModuleIntern(module); var frameIndex = FrameIntern(method, moduleIndex); var parent = StackSourceCallStackIndex.Invalid; if (depth > 0) { parent = stack[depth - 1].FirstCallStackIndex; // TODO handle out of range } var callStackIndex = CallStackIntern(frameIndex, parent); int extra = stack.Count - depth; int exclInstr; if (extra > 0) { elem = stack[depth]; if (callStackIndex == elem.CallStackIndex) { exclInstr = excInstrSoFar - elem.ExclInstrSoFar; } else { exclInstr = excInstrSoFar; elem.CallStackIndex = callStackIndex; } Debug.Assert(exclInstr >= 0); stack.RemoveRange(depth, extra); } else { elem.CallStackIndex = callStackIndex; elem.FirstCallStackIndex = callStackIndex; Debug.Assert(extra == 0); exclInstr = excInstrSoFar; } elem.ExclInstrSoFar = excInstrSoFar; stack.Add(elem); time += exclInstr; var sample = new StackSourceSample(this); sample.SampleIndex = (StackSourceSampleIndex)m_samples.Count; sample.Metric = exclInstr; sample.TimeRelMSec = time - exclInstr; sample.StackIndex = elem.FirstCallStackIndex; // Break long sequences of instructions into individual samples. This // makes timeline work well. // TODO this bloats the data, not clear if this is the right tradeoff .... const int maxSize = 20; while (sample.Metric > maxSize) { var subSample = new StackSourceSample(sample); subSample.Metric = maxSize; sample.Metric -= maxSize; sample.TimeRelMSec += maxSize; m_samples.Add(subSample); sample.SampleIndex = (StackSourceSampleIndex)m_samples.Count; } m_samples.Add(sample); #if DEBUG var sampleStr = this.ToString(sample); Debug.WriteLine(sampleStr); #endif } } m_sampleTimeRelMSecLimit = time; CompletedReading(); }
void Read(TextReader reader) { // TODO this is relatively inefficient. var regEx = new Regex(@"^\s*(\d+)\s*(\d+)\s*\[\s*(\d+)\s*\]\s*(\S*?)!?(.*)"); var stack = new GrowableArray <WTStackElem>(); WTStackElem elem = new WTStackElem(); long time = 0; var sample = new StackSourceSample(this); for (; ;) { var line = reader.ReadLine(); if (line == null) { break; } var match = regEx.Match(line); if (match.Success) { // Parse the line. int excInstrSoFar = int.Parse(match.Groups[1].Value); int depth = int.Parse(match.Groups[3].Value); string module = match.Groups[4].Value; string method = match.Groups[5].Value; // Form the name for this line var moduleIndex = Interner.ModuleIntern(module); var frameIndex = Interner.FrameIntern(method, moduleIndex); // Get the parent stack for this line var parent = StackSourceCallStackIndex.Invalid; if (depth > 0) { parent = stack[depth - 1].FirstCallStackIndex; // TODO handle out of range } // Form the stack for this entry var callStackIndex = Interner.CallStackIntern(frameIndex, parent); int exclInstr; // Number of instructions executed on this line int extra = stack.Count - depth; // The number of frames we need to pop off (including me) if (extra > 0) { // We returned from one or more methods OR we have not left the current method // elem = stack[depth]; // We expect to return to the same method we were at at this depth. if (callStackIndex == elem.CallStackIndex) { exclInstr = excInstrSoFar - elem.ExclInstrSoFar; // We are continuing the function } else { // We are tail-calling to another routine. exclInstr = excInstrSoFar; elem.CallStackIndex = callStackIndex; } // Pop off all the frames we returned from Debug.Assert(exclInstr >= 0); stack.RemoveRange(depth, extra); } else { // Means we are adding a new frame (we called someone) Debug.Assert(extra == 0); // We always add only one more frame (e.g. we never go from depth 2 to 4) elem.CallStackIndex = callStackIndex; elem.FirstCallStackIndex = callStackIndex; exclInstr = excInstrSoFar; } elem.ExclInstrSoFar = excInstrSoFar; stack.Add(elem); time += exclInstr; sample.Metric = exclInstr; sample.TimeRelativeMSec = time - exclInstr; sample.StackIndex = elem.FirstCallStackIndex; AddSample(sample); } } Interner.DoneInterning(); }