示例#1
0
        /// <summary>
        /// Parse MIbcGroup method and return enumerable of MethodProfileData
        ///
        /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is
        ///
        /// ldtoken methodInProfileData
        /// Any series of instructions that does not include pop
        /// pop
        /// {Repeat N times for N methods described}
        ///
        /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers.
        /// </summary>
        static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method)
        {
            EcmaMethodIL ilBody = EcmaMethodIL.Create(method);

            byte[] ilBytes             = ilBody.GetILBytes();
            int    currentOffset       = 0;
            object metadataObject      = null;
            object methodNotResolvable = new object();

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    if (metadataObject == null)
                    {
                        uint token = (uint)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24));
                        try
                        {
                            metadataObject = ilBody.GetObject((int)token);
                        }
                        catch (TypeSystemException)
                        {
                            // The method being referred to may be missing. In that situation,
                            // use the methodNotResolvable sentinel to indicate that this record should be ignored
                            metadataObject = methodNotResolvable;
                        }
                    }
                    break;

                case ILOpcode.pop:
                    if (metadataObject != methodNotResolvable)
                    {
                        MethodProfileData mibcData = new MethodProfileData((MethodDesc)metadataObject, MethodProfilingDataFlags.ReadMethodCode, 0xFFFFFFFF);
                        yield return(mibcData);
                    }
                    metadataObject = null;
                    break;
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
        }
        /// <summary>
        /// Parse MIbcGroup method and return enumerable of MethodProfileData
        ///
        /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is
        ///
        /// ldtoken methodInProfileData
        /// Any series of instructions that does not include pop. Expansion data is encoded via ldstr "id"
        /// followed by a expansion specific sequence of il opcodes.
        /// pop
        /// {Repeat N times for N methods described}
        ///
        /// Extensions supported with current parser:
        ///
        /// ldstr "ExclusiveWeight"
        /// Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight
        ///
        /// ldstr "WeightedCallData"
        /// ldc.i4 <Count of methods called>
        /// Repeat <Count of methods called times>
        ///  ldtoken <Method called from this method>
        ///  ldc.i4 <Weight associated with calling the <Method called from this method>>
        ///
        /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers.
        /// </summary>
        static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method)
        {
            EcmaMethodIL             ilBody         = EcmaMethodIL.Create(method);
            MetadataLoaderForPgoData metadataLoader = new MetadataLoaderForPgoData(ilBody);

            byte[] ilBytes                       = ilBody.GetILBytes();
            int    currentOffset                 = 0;
            object methodInProgress              = null;
            object metadataNotResolvable         = new object();
            object metadataObject                = null;
            MibcGroupParseState state            = MibcGroupParseState.LookingForNextMethod;
            int    intValue                      = 0;
            int    weightedCallGraphSize         = 0;
            int    profileEntryFound             = 0;
            double exclusiveWeight               = 0;
            Dictionary <MethodDesc, int> weights = null;
            bool        processIntValue          = false;
            List <long> instrumentationDataLongs = null;

            PgoSchemaElem[] pgoSchemaData = null;

            while (currentOffset < ilBytes.Length)
            {
                ILOpcode opcode = (ILOpcode)ilBytes[currentOffset];
                if (opcode == ILOpcode.prefix1)
                {
                    opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1];
                }
                processIntValue = false;
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                {
                    uint token = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(token);
                    }
                    else
                    {
                        metadataObject = null;
                        try
                        {
                            metadataObject = ilBody.GetObject((int)token);
                        }
                        catch (TypeSystemException)
                        {
                            // The method being referred to may be missing. In that situation,
                            // use the metadataNotResolvable sentinel to indicate that this record should be ignored
                            metadataObject = metadataNotResolvable;
                        }
                        switch (state)
                        {
                        case MibcGroupParseState.ProcessingCallgraphToken:
                            state = MibcGroupParseState.ProcessingCallgraphWeight;
                            break;

                        case MibcGroupParseState.LookingForNextMethod:
                            methodInProgress = metadataObject;
                            state            = MibcGroupParseState.LookingForOptionalData;
                            break;

                        default:
                            state = MibcGroupParseState.LookingForOptionalData;
                            break;
                        }
                    }
                }
                break;

                case ILOpcode.ldc_r4:
                {
                    float fltValue = BitConverter.ToSingle(ilBytes.AsSpan(currentOffset + 1, 4));

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = fltValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }

                    break;
                }

                case ILOpcode.ldc_r8:
                {
                    double dblValue = BitConverter.ToDouble(ilBytes.AsSpan(currentOffset + 1, 8));

                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = dblValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                    break;
                }

                case ILOpcode.ldc_i4_0:
                    intValue        = 0;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_1:
                    intValue        = 1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_2:
                    intValue        = 2;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_3:
                    intValue        = 3;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_4:
                    intValue        = 4;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_5:
                    intValue        = 5;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_6:
                    intValue        = 6;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_7:
                    intValue        = 7;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_8:
                    intValue        = 8;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_m1:
                    intValue        = -1;
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4_s:
                    intValue        = (sbyte)ilBytes[currentOffset + 1];
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i4:
                    intValue        = BitConverter.ToInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    processIntValue = true;
                    break;

                case ILOpcode.ldc_i8:
                    if (state == MibcGroupParseState.ProcessingInstrumentationData)
                    {
                        instrumentationDataLongs.Add(BitConverter.ToInt64(ilBytes.AsSpan(currentOffset + 1, 8)));
                    }
                    break;

                case ILOpcode.ldstr:
                {
                    UInt32 userStringToken  = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4));
                    string optionalDataName = (string)ilBody.GetObject((int)userStringToken);
                    switch (optionalDataName)
                    {
                    case "ExclusiveWeight":
                        state = MibcGroupParseState.ProcessingExclusiveWeight;
                        break;

                    case "WeightedCallData":
                        state = MibcGroupParseState.ProcessingCallgraphCount;
                        break;

                    case "InstrumentationDataStart":
                        state = MibcGroupParseState.ProcessingInstrumentationData;
                        instrumentationDataLongs = new List <long>();
                        break;

                    case "InstrumentationDataEnd":
                        if (instrumentationDataLongs != null)
                        {
                            instrumentationDataLongs.Add(2);             // MarshalMask 2 (Type)
                            instrumentationDataLongs.Add(0);             // PgoInstrumentationKind.Done (0)
                            pgoSchemaData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(metadataLoader, instrumentationDataLongs, false).ToArray();
                        }
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        break;
                    }
                }
                break;

                case ILOpcode.pop:
                    if (methodInProgress != metadataNotResolvable)
                    {
                        profileEntryFound++;
                        if (exclusiveWeight == 0)
                        {
                            // If no exclusive weight is found assign a non zero value that assumes the order in the pgo file is significant.
                            exclusiveWeight = Math.Min(1000000.0 - profileEntryFound, 0.0) / 1000000.0;
                        }
                        MethodProfileData mibcData = new MethodProfileData((MethodDesc)methodInProgress, MethodProfilingDataFlags.ReadMethodCode, exclusiveWeight, weights, 0xFFFFFFFF, pgoSchemaData);
                        state                    = MibcGroupParseState.LookingForNextMethod;
                        exclusiveWeight          = 0;
                        weights                  = null;
                        instrumentationDataLongs = null;
                        pgoSchemaData            = null;
                        yield return(mibcData);
                    }
                    methodInProgress = null;
                    break;

                default:
                    state = MibcGroupParseState.LookingForOptionalData;
                    break;
                }

                if (processIntValue)
                {
                    switch (state)
                    {
                    case MibcGroupParseState.ProcessingExclusiveWeight:
                        exclusiveWeight = intValue;
                        state           = MibcGroupParseState.LookingForOptionalData;
                        break;

                    case MibcGroupParseState.ProcessingCallgraphCount:
                        weightedCallGraphSize = intValue;
                        weights = new Dictionary <MethodDesc, int>();
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingCallgraphWeight:
                        if (metadataObject != metadataNotResolvable)
                        {
                            weights.Add((MethodDesc)metadataObject, intValue);
                        }
                        weightedCallGraphSize--;
                        if (weightedCallGraphSize > 0)
                        {
                            state = MibcGroupParseState.ProcessingCallgraphToken;
                        }
                        else
                        {
                            state = MibcGroupParseState.LookingForOptionalData;
                        }
                        break;

                    case MibcGroupParseState.ProcessingInstrumentationData:
                        instrumentationDataLongs.Add(intValue);
                        break;

                    default:
                        state = MibcGroupParseState.LookingForOptionalData;
                        instrumentationDataLongs = null;
                        break;
                    }
                }

                // This isn't correct if there is a switch opcode, but since we won't do that, its ok
                currentOffset += opcode.GetSize();
            }
        }
示例#3
0
            public void AddProcessedMethodData(MethodProfileData processedMethodData)
            {
                MethodDesc method = processedMethodData.Method;

                // Format is
                // ldtoken method
                // variable amount of extra metadata about the method, Extension data is encoded via ldstr "id"
                // pop

                // Extensions generated by this emitter:
                //
                // ldstr "ExclusiveWeight"
                // Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight
                //
                // ldstr "WeightedCallData"
                // ldc.i4 <Count of methods called>
                // Repeat <Count of methods called times>
                //  ldtoken <Method called from this method>
                //  ldc.i4 <Weight associated with calling the <Method called from this method>>
                //
                // ldstr "InstrumentationDataStart"
                // Encoded ints and longs, using ldc.i4, and ldc.i8 instructions as well as ldtoken <type> instructions
                // ldstr "InstrumentationDataEnd" as a terminator
                try
                {
                    EntityHandle methodHandle = _emitter.GetMethodRef(method);
                    _il.OpCode(ILOpCode.Ldtoken);
                    _il.Token(methodHandle);
                    if (processedMethodData.ExclusiveWeight != 0)
                    {
                        _il.LoadString(_emitter.GetUserStringHandle("ExclusiveWeight"));
                        if (((double)(int)processedMethodData.ExclusiveWeight) == processedMethodData.ExclusiveWeight)
                        {
                            _il.LoadConstantI4((int)processedMethodData.ExclusiveWeight);
                        }
                        else
                        {
                            _il.LoadConstantR8(processedMethodData.ExclusiveWeight);
                        }
                    }
                    if ((processedMethodData.CallWeights != null) && processedMethodData.CallWeights.Count > 0)
                    {
                        _il.LoadString(_emitter.GetUserStringHandle("WeightedCallData"));
                        _il.LoadConstantI4(processedMethodData.CallWeights.Count);
                        foreach (var entry in processedMethodData.CallWeights)
                        {
                            EntityHandle calledMethod = _emitter.GetMethodRef(entry.Key);
                            _il.OpCode(ILOpCode.Ldtoken);
                            _il.Token(calledMethod);
                            _il.LoadConstantI4(entry.Value);
                        }
                    }
                    if (processedMethodData.SchemaData != null)
                    {
                        _il.LoadString(_emitter.GetUserStringHandle("InstrumentationDataStart"));
                        PgoProcessor.EncodePgoData <TypeSystemEntityOrUnknown, TypeSystemEntityOrUnknown>(processedMethodData.SchemaData, this, true);
                    }
                    _il.OpCode(ILOpCode.Pop);
                }
                catch (Exception ex)
                {
                    Program.PrintWarning($"Exception {ex} while attempting to generate method lists");
                }
            }