/// <summary>
        /// Peeks ahead on source until we see \s+\d+/\d (that is space num/num) and returns the index to first (space)
        /// character in the pattern.  Returns -1 if not found.
        ///
        /// We need this complex regular expression because process names in linux can have spaces and numbers and slashes
        /// in them For example here is a real process name (rs:action 13 qu) or  (kworker/1:3)
        /// </summary>
        private static int FindSpaceNumSlash(FastStream source)
        {
            uint idx = 0;

startOver:
            int firstSpaceIdx = -1;
            bool seenDigit = false;

            for (; ;)
            {
                idx++;
                if (idx >= source.MaxPeek - 1)
                {
                    return(-1);
                }

                byte val = source.Peek(idx);
                if (firstSpaceIdx < 0)
                {
                    if (char.IsWhiteSpace((char)val))
                    {
                        firstSpaceIdx = (int)idx;
                    }
                    else
                    {
                        goto startOver;
                    }
                }
                else if (!seenDigit)
                {
                    if (char.IsDigit((char)val))
                    {
                        seenDigit = true;
                    }
                    else if (!char.IsWhiteSpace((char)val))
                    {
                        goto startOver;
                    }
                }
                else
                {
                    if (val == '/' && char.IsDigit((char)source.Peek(idx + 1)))
                    {
                        return(firstSpaceIdx);
                    }
                    else if (!char.IsDigit((char)val))
                    {
                        goto startOver;
                    }
                }
            }
        }
        private List <Frame> ReadFramesForSample(string command, int processID, int threadID, Frame threadTimeFrame, FastStream source)
        {
            List <Frame> frames = new List <Frame>();

            if (threadTimeFrame != null)
            {
                frames.Add(threadTimeFrame);
            }

            while (!this.IsEndOfSample(source, source.Current, source.Peek(1)))
            {
                StackFrame stackFrame = this.ReadFrame(source);
                if (this.mapper != null && (stackFrame.Module == "unknown" || stackFrame.Symbol == "unknown"))
                {
                    string[] moduleSymbol = this.mapper.ResolveSymbols(processID, stackFrame.Module, stackFrame);
                    stackFrame = new StackFrame(stackFrame.Address, moduleSymbol[0], moduleSymbol[1]);
                }
                frames.Add(stackFrame);
            }

            frames.Add(new ThreadFrame(threadID, "Thread"));
            frames.Add(new ProcessFrame(command));

            return(frames);
        }
Exemplo n.º 3
0
        public void PeekingWhileEnough()
        {
            FastStream stream = this.GetTestStream();

            SkipBOM(stream);
            Assert.Equal("2", ((char)stream.Peek(1)).ToString());
        }
        private bool TryGetCompleteBuffer(FastStream source, uint startLook, double portion, int maxLength, out uint length)
        {
            Contract.Requires(source != null, nameof(source));

            length = (uint)(startLook * portion);

            if (source.Peek(startLook) == 0)
            {
                return(true);
            }

            uint lastNewLine = length;

            for (uint i = length; i < maxLength; i++)
            {
                byte current = source.Peek(i);

                if (this.parser.IsEndOfSample(source, current, source.Peek(i + 1)))
                {
                    length = i;
                    return(true);
                }

                if (current == '\n')
                {
                    lastNewLine = length;
                }
            }

            if (portion < 0.5)
            {
                length = lastNewLine;
                return(false);
            }

            return(this.TryGetCompleteBuffer(source, startLook, portion * 0.8, maxLength, out length));
        }
        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);
                }
            }
        }
 public bool IsEndOfSample(FastStream source)
 {
     return(this.IsEndOfSample(source, source.Current, source.Peek(1)));
 }
        /// <summary>
        /// This routine should be called at the start of a line after you have skipped whitespace.
        ///
        /// Logically a line starts with PROCESS_COMMAND PID/TID [CPU] TIME:
        ///
        /// However PROCESS_COMMAND is unfortunately free form, including the fact hat it can have / or numbers in it.
        /// For example here is a real PROCESS_COMMAND examples (rs:action 13 qu) or  (kworker/1:3)
        /// Thus it gets tricky to know when the command stops and the PID/TID starts.
        ///
        /// We use the following regular expression to determine the end of the command
        ///
        ///       \s*\d+/\d        OR
        ///       ^\d+/\d          THIS PATTERN IS NEEDED BECAUSE THE PROCESS_COMMAND MAY BE EMPTY.
        ///
        /// This routine peeks forward looking for this pattern, and returns either the index to the start of it or -1 if not found.
        /// </summary>
        private static int FindEndOfProcessCommand(FastStream source)
        {
            uint idx = 0;

startOver:
            int firstSpaceIdx = -1;
            bool seenDigit = false;

            // Deal with the case where the COMMAND is empty.
            // Thus we have ANY spaces before the proceed ID Thread ID Num/Num.
            // We can deal with this case by 'jump starting the state machine state if it starts with a digit.
            if (char.IsDigit((char)source.Peek(0)))
            {
                firstSpaceIdx = 0;
                seenDigit     = true;
            }

            for (; ;)
            {
                idx++;
                if (idx >= source.MaxPeek - 1)
                {
                    return(-1);
                }

                byte val = source.Peek(idx);

                if (val == '\n')
                {
                    Debug.Assert(false, "Could not parse process command");
                    return(-1);
                }
                if (firstSpaceIdx < 0)
                {
                    if (char.IsWhiteSpace((char)val))
                    {
                        firstSpaceIdx = (int)idx;
                    }
                    else
                    {
                        goto startOver;
                    }
                }
                else if (!seenDigit)
                {
                    if (char.IsDigit((char)val))
                    {
                        seenDigit = true;
                    }
                    else if (!char.IsWhiteSpace((char)val))
                    {
                        goto startOver;
                    }
                }
                else
                {
                    if (val == '/' && char.IsDigit((char)source.Peek(idx + 1)))
                    {
                        return(firstSpaceIdx);
                    }
                    else if (!char.IsDigit((char)val))
                    {
                        goto startOver;
                    }
                }
            }
        }
Exemplo n.º 8
0
        public void PeekingWithNoBuffer()
        {
            FastStream stream = this.GetTestStream();

            Assert.Equal("1", ((char)stream.Peek(4)).ToString());
        }
Exemplo n.º 9
0
        private List <Frame> ReadFramesForSample(string command, int processID, int threadID, Frame threadTimeFrame, FastStream source)
        {
            List <Frame> frames = new List <Frame>();

            if (threadTimeFrame != null)
            {
                frames.Add(threadTimeFrame);
            }

            while (!IsEndOfSample(source, source.Current, source.Peek(1)))
            {
                StackFrame stackFrame = ReadFrame(source);
                if (mapper != null && (stackFrame.Module == "unknown" || stackFrame.Symbol == "unknown"))
                {
                    string[] moduleSymbol = mapper.ResolveSymbols(processID, stackFrame.Module, stackFrame);
                    stackFrame = new StackFrame(stackFrame.Address, moduleSymbol[0], moduleSymbol[1]);
                }
                if (stackFrame.Module.StartsWith("jitted-") && stackFrame.Module.EndsWith(".so") && stackFrame.Symbol.EndsWith(")"))
                {
                    // Jitted or R2R code.  Replace the module with the IL module name, and shorten the symbol.
                    // Example: uint8[] [System.Private.CoreLib] Internal.IO.File::ReadAllBytes(string)
                    // Example: instance uint8[] [System.Private.CoreLib] Internal.IO.File::ReadAllBytes(string)

                    // Start at the end of the string, which should be ')'.  Walk until we find the matching '('.
                    string symbol       = stackFrame.Symbol;
                    int    currentIndex = symbol.Length - 1;
                    int    endIndex     = 0;
                    int    parenDepth   = 0;
                    while (currentIndex >= endIndex)
                    {
                        char current = symbol[currentIndex];
                        if (current == ')')
                        {
                            // We know that we'll immediately increment the paren depth from 0 to 1 on the first loop iteration because
                            // the conditions on the if statement above require it.
                            parenDepth++;
                        }
                        else if (current == '(')
                        {
                            parenDepth--;
                        }

                        if (parenDepth <= 0)
                        {
                            // We found the open paren that matches the last close paren.
                            break;
                        }

                        currentIndex--;
                    }

                    // Continue walking until we find the first whitespace char.  This is the beginning of the full function name (with namespace).
                    while (currentIndex >= endIndex && symbol[currentIndex] != ' ')
                    {
                        currentIndex--;
                    }

                    // Make sure we actually hit a ' ' char.
                    if (symbol[currentIndex] != ' ')
                    {
                        goto abort;
                    }

                    // Save the symbol name.
                    string newSymbol = symbol.Substring(currentIndex + 1, (symbol.Length - currentIndex - 1));

                    // Find the beginning of the module name by looking for ']'.
                    while (currentIndex >= endIndex && symbol[currentIndex] != ']')
                    {
                        currentIndex--;
                    }

                    // Make sure we actually hit a ']' char.
                    if (symbol[currentIndex] != ']')
                    {
                        goto abort;
                    }
                    int moduleEndIndex = currentIndex;

                    // Find the matching '[' char.
                    while (currentIndex >= endIndex && symbol[currentIndex] != '[')
                    {
                        currentIndex--;
                    }

                    // Make sure we actually hit a '[' char.
                    if (symbol[currentIndex] != '[')
                    {
                        goto abort;
                    }

                    // Save the module name.
                    string newModuleName = symbol.Substring(currentIndex + 1, (moduleEndIndex - currentIndex - 1));

                    stackFrame = new StackFrame(stackFrame.Address, newModuleName, newSymbol, stackFrame.OptimizationTier);
                }
abort:
                frames.Add(stackFrame);
            }

            frames.Add(new ThreadFrame(threadID, "Thread"));
            frames.Add(new ProcessFrame(processID, command));

            return(frames);
        }
Exemplo n.º 10
0
        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);
                }
            }
        }