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

            if (this.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 (this.EndingStates.ContainsKey(schedEvent.Switch.PreviousThreadID) &&
                    this.EndingStates[schedEvent.Switch.PreviousThreadID].Key == LinuxThreadState.CPU_TIME) // Blocking
                {
                    sampleInfo = this.EndingStates[schedEvent.Switch.PreviousThreadID];

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

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

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

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

            this.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();

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