File: Compiler\ProfileData.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.ReadyToRun\ILCompiler.ReadyToRun.csproj (ILCompiler.ReadyToRun)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using ILCompiler.IBC;

using Internal.Pgo;
using Internal.TypeSystem;

namespace ILCompiler
{
    [Flags]
    public enum MethodProfilingDataFlags
    {
        // Important: update toolbox\ibcmerge\ibcmerge.cs if you change these
        ReadMethodCode = 0,  // 0x00001  // Also means the method was executed
        ReadMethodDesc = 1,  // 0x00002
        RunOnceMethod = 2,  // 0x00004
        RunNeverMethod = 3,  // 0x00008
                             //  MethodStoredDataAccess        = 4,  // 0x00010  // obsolete
        WriteMethodDesc = 5,  // 0x00020
                              //  ReadFCallHash                 = 6,  // 0x00040  // obsolete
        ReadGCInfo = 7,  // 0x00080
        CommonReadGCInfo = 8,  // 0x00100
                               //  ReadMethodDefRidMap           = 9,  // 0x00200  // obsolete
        ReadCerMethodList = 10, // 0x00400
        ReadMethodPrecode = 11, // 0x00800
        WriteMethodPrecode = 12, // 0x01000
        ExcludeHotMethodCode = 13, // 0x02000  // Hot method should be excluded from the ReadyToRun image
        ExcludeColdMethodCode = 14, // 0x04000  // Cold method should be excluded from the ReadyToRun image
        DisableInlining = 15, // 0x08000  // Disable inlining of this method in optimized AOT native code
    }

    public class MethodProfileData
    {
        public MethodProfileData(MethodDesc method, MethodProfilingDataFlags flags, double exclusiveWeight, Dictionary<MethodDesc, int> callWeights, uint scenarioMask, PgoSchemaElem[] schemaData)
        {
#pragma warning disable CA1507 // Use nameof to express symbol names
            Method = method ?? throw new ArgumentNullException("method");
#pragma warning restore CA1507 // Use nameof to express symbol names
            Flags = flags;
            ScenarioMask = scenarioMask;
            ExclusiveWeight = exclusiveWeight;
            CallWeights = callWeights;
            SchemaData = schemaData;
        }

        public readonly MethodDesc Method;
        public readonly MethodProfilingDataFlags Flags;
        public readonly uint ScenarioMask;
        public readonly double ExclusiveWeight;
        public readonly Dictionary<MethodDesc, int> CallWeights;
        public readonly PgoSchemaElem[] SchemaData;
    }

    public abstract class ProfileData
    {
        public abstract MibcConfig Config { get; }
        public abstract bool PartialNGen { get; }
        public abstract MethodProfileData GetMethodProfileData(MethodDesc m);
        public abstract IEnumerable<MethodProfileData> GetAllMethodProfileData();
        public abstract byte[] GetMethodBlockCount(MethodDesc m);

        public static void MergeProfileData(Dictionary<MethodDesc, MethodProfileData> mergedProfileData, ProfileData profileData)
        {
            PgoSchemaElem[][] schemaElemMergerArray = new PgoSchemaElem[2][];

            foreach (MethodProfileData data in profileData.GetAllMethodProfileData())
            {
                MethodProfileData dataToMerge;
                if (mergedProfileData.TryGetValue(data.Method, out dataToMerge))
                {
                    var mergedCallWeights = data.CallWeights;
                    if (mergedCallWeights == null)
                    {
                        mergedCallWeights = dataToMerge.CallWeights;
                    }
                    else if (dataToMerge.CallWeights != null)
                    {
                        mergedCallWeights = new Dictionary<MethodDesc, int>(data.CallWeights);
                        foreach (var entry in dataToMerge.CallWeights)
                        {
                            if (mergedCallWeights.TryGetValue(entry.Key, out var initialWeight))
                            {
                                mergedCallWeights[entry.Key] = initialWeight + entry.Value;
                            }
                            else
                            {
                                mergedCallWeights[entry.Key] = entry.Value;
                            }
                        }
                    }

                    PgoSchemaElem[] mergedSchemaData;
                    if (data.SchemaData == null)
                    {
                        mergedSchemaData = dataToMerge.SchemaData;
                    }
                    else if (dataToMerge.SchemaData == null)
                    {
                        mergedSchemaData = data.SchemaData;
                    }
                    else
                    {
                        // Actually merge
                        schemaElemMergerArray[0] = dataToMerge.SchemaData;
                        schemaElemMergerArray[1] = data.SchemaData;
                        mergedSchemaData = PgoProcessor.Merge<TypeSystemEntityOrUnknown, TypeSystemEntityOrUnknown>(schemaElemMergerArray);
                    }
                    mergedProfileData[data.Method] = new MethodProfileData(data.Method, dataToMerge.Flags | data.Flags, data.ExclusiveWeight + dataToMerge.ExclusiveWeight, mergedCallWeights, dataToMerge.ScenarioMask | data.ScenarioMask, mergedSchemaData);
                }
                else
                {
                    mergedProfileData.Add(data.Method, data);
                }
            }
        }
    }

    public class EmptyProfileData : ProfileData
    {
        private static readonly EmptyProfileData s_singleton = new EmptyProfileData();

        private EmptyProfileData()
        {
        }

        public override MibcConfig Config { get; } = new();

        public override bool PartialNGen => false;

        public static EmptyProfileData Singleton => s_singleton;

        public override MethodProfileData GetMethodProfileData(MethodDesc m)
        {
            return null;
        }

        public override IEnumerable<MethodProfileData> GetAllMethodProfileData()
        {
            return Array.Empty<MethodProfileData>();
        }

        public override byte[] GetMethodBlockCount(MethodDesc m)
        {
            return null;
        }
    }
}