private void ReadFile()

in src/PerfView/memory/ClrProfilerParser.cs [226:852]


        private void ReadFile(FastStream stream)
        {
            StringBuilder sb = new StringBuilder();
            List<Address> addressList = new List<Address>();
            int lineNum = 1;
            int gcNumber = 0;

            stream.MoveNext();
            for (; ; )
            {
                // Check whether we've been asked to abort this parsing early
                if (abort)
                {
                    return;
                }

                byte c = stream.Current;
                stream.MoveNext();
                // Because the stats are highly skewed, and if-then-else tree is better than a switch.  
                if (c == '\r')
                {
                    // Do nothing 
                }
                else if (c == '\n')
                {
                    lineNum++;
                    if (lineNum % 4096 == 0)                 // Every 4K events allow Thread.Interrupt.  
                    {
                        System.Threading.Thread.Sleep(0);
                    }
                }
                else if (c == 'c')
                {
                    // Call was made
                    if (Call == null)
                    {
                        goto SKIP_LINE;
                    }

                    uint threadId = stream.ReadUInt();
                    uint fileStackId = stream.ReadUInt();
                    if (!stream.EndOfStream)
                    {
                        ProfilerStackTraceID stackId = GetStackIdForFileId(fileStackId);
                        Call(stackId, threadId);
                    }
                }
                else if (c == '!')
                {
                    // Allocation was made
                    if (Allocation == null)
                    {
                        goto SKIP_LINE;
                    }

                    uint threadId = stream.ReadUInt();
                    Address address = (Address)stream.ReadULong();
                    uint fileStackId = stream.ReadUInt();
                    ProfilerAllocID allocId = GetAllocIdForFileId(fileStackId);
                    if (!stream.EndOfStream)
                    {
                        Allocation(allocId, address, threadId);
                    }
                }
                else if (c == 'n')
                {
                    // Announce a stack
                    uint fileStackId = stream.ReadUInt();
                    uint flag = stream.ReadUInt();
                    uint hadTypeId = (flag & 2);
                    uint tailCount = flag >> 2;

                    uint hasTypeId = (flag & 1);
                    ProfilerTypeID typeId = 0;
                    uint size = 0;
                    if (hasTypeId != 0)
                    {
                        typeId = (ProfilerTypeID)stream.ReadUInt();
                        size = stream.ReadUInt();
                    }
                    uint fileTailStackId = 0;
                    if (tailCount > 0)
                    {
                        fileTailStackId = stream.ReadUInt();
                    }

                    if (!stream.EndOfStream)
                    {
                        // The rest of the line are a series of function Ids (going from closest to top of stack
                        // to closest to execution.  
                        ProfilerStackTraceID stackId = GetStackIdForFileId(fileTailStackId);
                        if (tailCount > 0)
                        {
                            stackId = GetTopOfStack(stackId, tailCount);
                        }

                        for (; ; )
                        {
                            ProfilerMethodID methodId = (ProfilerMethodID)stream.ReadUInt();
                            if ((uint)methodId == 0xFFFFFFFF)
                            {
                                break;
                            }

                            // TODO decide how to fix this. 
                            // Debug.Assert(methodIds[(int)methodId].name != null);

                            uint newStackId = stackIdLimit++;
                            stackIds = ArrayUtilities<StackInfo>.InsureCapacity(stackIds, newStackId);
                            stackIds[newStackId].methodId = methodId;
                            stackIds[newStackId].stackId = stackId;

                            stackId = (ProfilerStackTraceID)newStackId;
                            if (methodIds[(int)methodId] != null)
                            {
                                VerboseDebug("Frame stackId=S" + newStackId + " name=" + methodIds[(int)methodId].name);
                            }
                        }
                        if (hasTypeId != 0)
                        {
                            uint allocId = allocIdLimit++;
                            allocIds = ArrayUtilities<AllocInfo>.InsureCapacity(allocIds, allocId);
                            allocIds[allocId].Set(typeId, size, stackId);

                            if (methodIds[(int)stackIds[(int)stackId].methodId] != null)    // TODO 
                            {
                                VerboseDebug("FileAlloc s" + fileStackId + " maps to allocId=" + allocId +
                                    " type=" + typeIds[(int)typeId].name + " size=" + size + " stackId=" + stackId +
                                    ((stackId == 0) ? "" : " (" + methodIds[(int)stackIds[(int)stackId].methodId].name + ")"));
                            }

                            fileIdStackInfoId = ArrayUtilities<uint>.InsureCapacity(fileIdStackInfoId, fileStackId);
                            fileIdStackInfoId[fileStackId] = SetAllocId(allocId);
                        }
                        else
                        {
                            if (methodIds[(int)stackIds[(int)stackId].methodId] != null)    // TODO 
                            {
                                VerboseDebug("FileStack s" + fileStackId + " maps to stackId=" + stackId +
                                    ((stackId == 0) ? "" : " (" + methodIds[(int)stackIds[(int)stackId].methodId].name + ")"));
                            }

                            fileIdStackInfoId = ArrayUtilities<uint>.InsureCapacity(fileIdStackInfoId, fileStackId);
                            fileIdStackInfoId[fileStackId] = SetStackId(stackId);
                        }
                    }
                }
                else if (c == 'f')
                {
                    // Announce a function (used in stacks)
                    ProfilerMethodID methodId = (ProfilerMethodID)stream.ReadUInt();
                    stream.SkipSpace();
                    sb.Length = 0;
                    // name may contain spaces if they are in angle brackets.
                    // Example: <Module>::std_less<unsigned void>.()
                    // The name may be truncated at 255 chars by profilerOBJ.dll
                    int angleBracketsScope = 0;
                    c = stream.Current;
                    while (c > ' ' || angleBracketsScope != 0 && sb.Length < 255)
                    {
                        if (c == '<')
                        {
                            angleBracketsScope++;
                        }

                        sb.Append((char)c);
                        c = stream.ReadByte();

                        if (c == '>' && angleBracketsScope > 0)
                        {
                            angleBracketsScope--;
                        }
                    }
                    string name = sb.ToString();
                    stream.SkipSpace();
                    sb.Length = 0;
                    c = stream.Current;
                    while (c > '\r')
                    {
                        sb.Append((char)c);
                        if (c == ')')
                        {
                            c = stream.ReadByte();
                            break;
                        }
                        c = stream.ReadByte();
                    }
                    string signature = sb.ToString();
                    Address address = (Address)stream.ReadULong();
                    uint size = stream.ReadUInt();
                    ProfilerMethodID moduleId = (ProfilerMethodID)stream.ReadUInt();
                    uint fileFirstStackId = stream.ReadUInt();
                    if (!stream.EndOfStream)
                    {
                        ProfilerModule module = null;
                        if (methodId == 0)      // Hack for first method, it does not have a module ID or a stack
                        {
                            moduleId = 0;
                            fileFirstStackId = 0;
                            module = new ProfilerModule(0, "UnknownModule", 0, 0);
                        }
                        else
                        {
                            module = moduleIds[(int)moduleId];
                        }

                        ProfilerStackTraceID firstStackId = GetStackIdForFileId(fileFirstStackId);
                        VerboseDebug("Method " + methodId + "  name=" + name + " sig=" + signature +
                            " moduleId=" + moduleId + " size=" + size + " stack=S" + firstStackId);
                        methodIds = ArrayUtilities<ProfilerMethod>.InsureCapacity(methodIds, (uint)methodId);
                        methodIds[(int)methodId] = new ProfilerMethod(methodId, name, signature, address, size, module, firstStackId);
                        if ((uint)methodId >= methodIdLimit)
                        {
                            methodIdLimit = (uint)methodId + 1;
                        }
                    }
                }
                else if (c == 't')
                {
                    // Announce a nodeId
                    ProfilerTypeID typeId = (ProfilerTypeID)stream.ReadUInt();
                    bool isFinalizable = (stream.ReadInt() == 1);
                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo('\r', sb);
                    string name = sb.ToString();
                    if (!stream.EndOfStream)
                    {
                        VerboseDebug("Type " + typeId + " name=" + name + " isFinalizable=" + isFinalizable);
                        CreateType(typeId, name, isFinalizable);
                    }
                }
                else if (c == 'h')
                {
                    // A handle was created 
                    if (CreateHandle == null)
                    {
                        goto SKIP_LINE;
                    }

                    uint threadId = stream.ReadUInt();
                    Address handle = (Address)stream.ReadULong();
                    Address objectInHandle = (Address)stream.ReadULong();
                    uint fileStackId = stream.ReadUInt();
                    if (!stream.EndOfStream && CreateHandle != null)
                    {
                        ProfilerStackTraceID stackId = GetStackIdForFileId(fileStackId);
                        CreateHandle(handle, objectInHandle, stackId, threadId);
                    }
                }
                else if (c == 'i')
                {
                    // Time has gone by (do this every msec to 10 msec 
                    if (Tick == null)
                    {
                        goto SKIP_LINE;
                    }

                    int millisecondsSinceStart = stream.ReadInt();
                    if (!stream.EndOfStream)
                    {
                        Tick(millisecondsSinceStart);
                    }
                }
                else if (c == 'j')
                {
                    // Destroy a handle
                    if (DestroyHandle == null)
                    {
                        goto SKIP_LINE;
                    }

                    uint threadId = stream.ReadUInt();
                    Address handle = (Address)stream.ReadULong();
                    uint fileStackId = stream.ReadUInt();
                    if (!stream.EndOfStream)
                    {
                        ProfilerStackTraceID stackId = GetStackIdForFileId(fileStackId);
                        DestroyHandle(handle, stackId, threadId);
                    }
                }
                else if (c == 'l')
                {
                    // Finalizer called 
                    if (Finalizer == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address objectAddress = (Address)stream.ReadULong();
                    bool isCritical = (stream.ReadInt() == 1);
                    if (!stream.EndOfStream)
                    {
                        Finalizer(objectAddress, isCritical);
                    }
                }
                else if (c == 'b')
                {
                    // GC boundary (first args indicates if it is start or end)
                    if (GCStart == null && GCEnd == null)
                    {
                        goto SKIP_LINE;
                    }

                    bool gcStart = (stream.ReadInt() == 1);
                    bool induced = (stream.ReadInt() == 1);
                    int condemnedGeneration = stream.ReadInt();

                    if (gcStart)
                    {
                        gcNumber++;
                    }

                    List<ProfilerGCSegment> gcMemoryRanges = new List<ProfilerGCSegment>(5);
                    for (; ; )
                    {
                        ProfilerGCSegment range = new ProfilerGCSegment((Address)stream.ReadULong(), stream.ReadUInt(), stream.ReadUInt(), stream.ReadInt());
                        if (range.rangeGeneration < 0)
                        {
                            break;
                        }

                        gcMemoryRanges.Add(range);
                    }
                    if (!stream.EndOfStream)
                    {
                        if (gcStart && GCStart != null)
                        {
                            GCStart(gcNumber, induced, condemnedGeneration, gcMemoryRanges);
                        }

                        if (!gcStart && GCEnd != null)
                        {
                            GCEnd(gcNumber, induced, condemnedGeneration, gcMemoryRanges);
                        }
                    }
                }
                else if (c == 'g')
                {
                    // Generation count
                    int gen0Count = stream.ReadInt();
                    int gen1Count = stream.ReadInt();
                    int gen2Count = stream.ReadInt();
                }
                else if (c == 'r')
                {
                    // Heap roots (for heap dump)
                    if (HeapDump == null && ObjectDescription == null)
                    {
                        goto SKIP_LINE;
                    }

                    addressList.Clear();
                    for (; ; )
                    {
                        Address root = (Address)stream.ReadULong();
                        if (root == BadAddress)
                        {
                            break;
                        }

                        addressList.Add(root);
                    }
                    if (!stream.EndOfStream && HeapDump != null)
                    {
                        HeapDump(addressList);
                    }
                }
                else if (c == 'o')
                {
                    // Object in heap (heap dump)
                    if (ObjectDescription == null && HeapDump == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address objectAddress = (Address)stream.ReadULong();
                    ProfilerTypeID typeId = (ProfilerTypeID)stream.ReadUInt();
                    uint size = stream.ReadUInt();

                    addressList.Clear();
                    for (; ; )
                    {
                        Address reference = (Address)stream.ReadULong();
                        if (reference == BadAddress)
                        {
                            break;
                        }

                        addressList.Add(reference);
                    }
                    if (!stream.EndOfStream)
                    {
                        ObjectDescription(objectAddress, typeId, size, addressList);
                    }
                }
                else if (c == 'u')
                {
                    // Object relocation 
                    if (ObjectRangeRelocation == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address oldBase = (Address)stream.ReadULong();
                    Address newBase = (Address)stream.ReadULong();
                    uint size = stream.ReadUInt();

                    if (!stream.EndOfStream)
                    {
                        ObjectRangeRelocation(oldBase, newBase, size);
                    }
                }
                else if (c == 'v')
                {
                    // Object live range 
                    if (ObjectRangeLive == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address startAddress = (Address)stream.ReadULong();
                    uint size = stream.ReadUInt();
                    if (!stream.EndOfStream)
                    {
                        ObjectRangeLive(startAddress, size);
                    }
                }
                else if (c == 'm')
                {
                    // Module load
                    uint moduleId = stream.ReadUInt();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(" 0x", sb);
                    string name = sb.ToString();
                    Address address = (Address)stream.ReadULong();
                    uint fileFirstStackId = stream.ReadUInt();
                    if (!stream.EndOfStream)
                    {
                        ProfilerStackTraceID firstStackId = GetStackIdForFileId(fileFirstStackId);
                        VerboseDebug("Module " + moduleId + " Addr=" + address + " stack=S" + firstStackId + " name=" + name);
                        ProfilerModule newModule = CreateModule((ProfilerModuleID)moduleId, name, address, firstStackId);
                        ModuleLoad?.Invoke(newModule);
                    }
                }
                else if (c == 'y')
                {
                    // Assembly load
                    if (AssemblyLoad == null)
                    {
                        goto SKIP_LINE;
                    }

                    uint threadId = stream.ReadUInt();
                    Address assemblyAddress = (Address)stream.ReadULong();
                    sb.Length = 0;
                    stream.SkipSpace();
                    stream.ReadAsciiStringUpTo('\r', sb);
                    string assemblyName = sb.ToString();

                    if (!stream.EndOfStream && AssemblyLoad != null)
                    {
                        AssemblyLoad(assemblyName, assemblyAddress, threadId);
                    }
                }
                else if (c == 'e')
                {
                    // GC root (handle) (heap dump)
                    if (GCRoot == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address objectAddress = (Address)stream.ReadULong();
                    GcRootKind rootKind = (GcRootKind)stream.ReadInt();
                    GcRootFlags rootFlags = (GcRootFlags)stream.ReadInt();
                    Address rootID = (Address)stream.ReadULong();

                    if (!stream.EndOfStream && GCRoot != null)
                    {
                        GCRoot(objectAddress, rootKind, rootFlags, rootID);
                    }
                }
                else if (c == 's')      // NEW! static variable root.   
                {
                    if (StaticVar == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address objectAddress = (Address)stream.ReadULong();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string fieldName = sb.ToString();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string typeName = sb.ToString();

                    var threadId = stream.ReadUInt();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string appDomainName = sb.ToString();


                    // Find the typeId for this type name, and when you find it, call the callback.  
                    // Use the TypesNeedingModule dictionary to avoid searching most of the list
                    var typeIds = GetTypesNeedingModule(typeName, true);
                    foreach (var typeId in typeIds)
                    {
                        var type = GetTypeById(typeId);
                        if (type.name == typeName)
                        {
                            StaticVar(objectAddress, fieldName, typeId, threadId, appDomainName);
                            break;
                        }
                    }
                }
                else if (c == 'L')      // NEW! local variable root.   
                {
                    if (LocalVar == null)
                    {
                        goto SKIP_LINE;
                    }

                    Address objectAddress = (Address)stream.ReadULong();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string localName = sb.ToString();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string methodName = sb.ToString();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string typeName = sb.ToString();

                    var threadId = stream.ReadUInt();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string appDomainName = sb.ToString();

                    // Find the typeId for this type name, and when you find it, call the callback.  
                    // Use the TypesNeedingModule dictionary to avoid searching most of the list
                    var typeIds = GetTypesNeedingModule(typeName, true);
                    foreach (var typeId in typeIds)
                    {
                        var type = GetTypeById(typeId);
                        if (type.name == typeName)
                        {
                            LocalVar(objectAddress, localName, methodName, typeId, threadId, appDomainName);
                            break;
                        }
                    }
                }
                else if (c == 'M')      // NEW! module information for types
                {
                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo(' ', sb);
                    string typeName = sb.ToString();

                    stream.SkipSpace();
                    sb.Length = 0;
                    stream.ReadAsciiStringUpTo('\r', sb);
                    string moduleName = sb.ToString();

                    // Only add module names to type names that we already care about. 
                    var typeIds = GetTypesNeedingModule(typeName, false);
                    if (typeIds != null)
                    {
                        var moduleId = GetModuleIdForName(moduleName);
                        foreach (var typeId in typeIds)
                        {
                            GetTypeById(typeId).ModuleId = moduleId;
                        }
                    }
                }
                else if (c == 'z')
                {
                    // User event
                    if (UserEvent == null)
                    {
                        goto SKIP_LINE;
                    }

                    sb.Length = 0;
                    stream.SkipSpace();
                    stream.ReadAsciiStringUpTo('\r', sb);
                    string comment = sb.ToString();
                    if (!stream.EndOfStream && UserEvent != null)
                    {
                        UserEvent(comment);
                    }
                }
                else
                {
                    // We matched none of the expected chars
                    if (stream.EndOfStream)
                    {
                        break;
                    }

                    Debug.WriteLine("Warning unknown CLRProfiler entry line '" + (char)c + "' on line " + lineNum);
                    goto SKIP_LINE;
                }

                continue;
                SKIP_LINE:
                stream.SkipUpTo('\r');
            }

            moduleNameToId = null;
            typesNeedingModule = null;
        }