private void DoMetrics(LinuxEvent linuxEvent)
        {
            KeyValuePair <LinuxThreadState, LinuxEvent> sampleInfo;

            if (EndingStates.TryGetValue(linuxEvent.ThreadID, out sampleInfo))
            {
                linuxEvent.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
            }

            // This is check for completed scheduler events, ones that start with prev_comm and have
            //   corresponding next_comm.
            if (linuxEvent.Kind == EventKind.Scheduler)
            {
                SchedulerEvent schedEvent = (SchedulerEvent)linuxEvent;
                if (EndingStates.ContainsKey(schedEvent.Switch.PreviousThreadID) &&
                    EndingStates[schedEvent.Switch.PreviousThreadID].Key == LinuxThreadState.CPU_TIME) // Blocking
                {
                    sampleInfo = EndingStates[schedEvent.Switch.PreviousThreadID];

                    EndingStates[schedEvent.Switch.PreviousThreadID] =
                        new KeyValuePair <LinuxThreadState, LinuxEvent>(LinuxThreadState.BLOCKED_TIME, linuxEvent);

                    linuxEvent.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
                }

                if (EndingStates.TryGetValue(schedEvent.Switch.NextThreadID, out sampleInfo) &&
                    sampleInfo.Key == LinuxThreadState.BLOCKED_TIME) // Unblocking
                {
                    EndingStates[schedEvent.Switch.NextThreadID] =
                        new KeyValuePair <LinuxThreadState, LinuxEvent>(LinuxThreadState.CPU_TIME, linuxEvent);

                    // sampleInfo.Value.Period = linuxEvent.Time - sampleInfo.Value.Time;
                    AddThreadPeriod(linuxEvent.ThreadID, sampleInfo.Value.TimeMSec, linuxEvent.TimeMSec);
                }
            }
            else if (linuxEvent.Kind == EventKind.Cpu)
            {
                int threadid;
                if (EndingCpuUsage.TryGetValue(linuxEvent.CpuNumber, out threadid) && threadid != linuxEvent.ThreadID) // Unblocking
                {
                    if (EndingStates.TryGetValue(threadid, out sampleInfo))
                    {
                        EndingStates[threadid] =
                            new KeyValuePair <LinuxThreadState, LinuxEvent>(LinuxThreadState.CPU_TIME, linuxEvent);
                        sampleInfo.Value.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
                        AddThreadPeriod(linuxEvent.ThreadID, sampleInfo.Value.TimeMSec, linuxEvent.TimeMSec);
                    }
                }
            }

            EndingCpuUsage[linuxEvent.CpuNumber] = linuxEvent.ThreadID;
        }
        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();
                source.MoveNext(); // Move past the "/"

                // Thread ID
                int 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;
                }

                // 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');
                    }

                    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
                    {
                        linuxEvent = new CpuEvent(processCommand, tid, pid, time, timeProp, cpu, eventName, eventDetails, frames);
                    }

                    yield return(linuxEvent);
                }
            }
        }
        private void DoMetrics(LinuxEvent linuxEvent)
        {
            KeyValuePair <LinuxThreadState, LinuxEvent> sampleInfo;

            // This is check for completed scheduler events, ones that start with prev_comm and have
            //   corresponding next_comm.
            if (linuxEvent.Kind == EventKind.Scheduler)
            {
                SchedulerEvent schedEvent = (SchedulerEvent)linuxEvent;
                if (EndingStates.ContainsKey(schedEvent.Switch.PreviousThreadID) &&
                    EndingStates[schedEvent.Switch.PreviousThreadID].Key == LinuxThreadState.CPU_TIME) // Blocking
                {
                    // PreviousThreadID is now blocking.  linuxEvent contains its blocking stack, so save it here.
                    // When it unblocks (becomes NextThreadID below, we'll log a sample for it.)
                    EndingStates[schedEvent.Switch.PreviousThreadID] =
                        new KeyValuePair <LinuxThreadState, LinuxEvent>(LinuxThreadState.BLOCKED_TIME, linuxEvent);
                }

                if (EndingStates.TryGetValue(schedEvent.Switch.NextThreadID, out sampleInfo) &&
                    sampleInfo.Key == LinuxThreadState.BLOCKED_TIME) // Unblocking
                {
                    sampleInfo.Value.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
                    AddThreadPeriod(sampleInfo.Value.ThreadID, sampleInfo.Value.TimeMSec, linuxEvent.TimeMSec);
                    StackSource.AddSample(StackSource.CreateSampleFor(sampleInfo.Value, this));

                    EndingStates[schedEvent.Switch.NextThreadID] =
                        new KeyValuePair <LinuxThreadState, LinuxEvent>(LinuxThreadState.CPU_TIME, linuxEvent);
                }
            }
            else if (linuxEvent.Kind == EventKind.ThreadExit)
            {
                ThreadExitEvent exitEvent = (ThreadExitEvent)linuxEvent;
                if (EndingStates.TryGetValue(exitEvent.Exit.ThreadID, out sampleInfo))
                {
                    if (sampleInfo.Key == LinuxThreadState.BLOCKED_TIME) // Blocked on exit
                    {
                        sampleInfo.Value.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
                        AddThreadPeriod(sampleInfo.Value.ThreadID, sampleInfo.Value.TimeMSec, linuxEvent.TimeMSec);
                        StackSource.AddSample(StackSource.CreateSampleFor(sampleInfo.Value, this));
                    }
                    else // Unblocked on exit
                    {
                        linuxEvent.Period = linuxEvent.TimeMSec - sampleInfo.Value.TimeMSec;
                        StackSource.AddSample(StackSource.CreateSampleFor(linuxEvent, this));
                    }

                    // Remove the thread so that any events that might come after the exit are ignored.
                    EndingStates.Remove(exitEvent.Exit.ThreadID);
                }
            }
            else if (linuxEvent.Kind == EventKind.Cpu)
            {
                // Keep track of the last CPU sample for each CPU, and use its timestamp
                // to determine how much weight to give the sample.
                if (LastCpuUsage.TryGetValue(linuxEvent.CpuNumber, out LinuxEvent lastCpuEvent))
                {
                    lastCpuEvent.Period = linuxEvent.TimeMSec - lastCpuEvent.TimeMSec;
                    StackSource.AddSample(StackSource.CreateSampleFor(lastCpuEvent, this));
                }

                LastCpuUsage[linuxEvent.CpuNumber] = linuxEvent;
            }
        }