Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel Information Objects and adapted Kernel Loaders #104

Closed
m4rs-mt opened this issue May 11, 2020 · 0 comments · Fixed by #155
Closed

Kernel Information Objects and adapted Kernel Loaders #104

m4rs-mt opened this issue May 11, 2020 · 0 comments · Fixed by #155
Assignees
Labels
difficulty:beginner A beginner task feature A new feature (or feature request)
Milestone

Comments

@m4rs-mt
Copy link
Owner

m4rs-mt commented May 11, 2020

Some kernel loaders (LoadAutoGroupedXXXKernel) provide additional information about the "optimal" number of threads per group and/or the number of groups to achieve maximum occupancy on a certain device. However, this functionality is not available for all overloads. Furthermore, there have been requests (like #76) to get additional information about the number of functions, the amount of stack memory or the maximum call depth of all functions in a final compile unit (CompiledKernel instance - similar to the output of ptxas -v filename). This feature might require an extension of the CompiledKernel class to store additional information about the functions compiled. A sample implementation of such an extension is shown below (can be nested types of the class CompiledKernel)

        /// <summary>
        /// Contains information about functions.
        /// </summary>
        public readonly struct FunctionInfo
        {
            #region Instance

            /// <summary>
            /// Constructs a new function information object.
            /// </summary>
            public FunctionInfo(
                string name,
                MethodBase method,
                int localMemorySize,
                int maxCallDepth)
            {
                if (localMemorySize < 0)
                    throw new ArgumentOutOfRangeException(nameof(localMemorySize));
                if (maxCallDepth < 0)
                    throw new ArgumentOutOfRangeException(nameof(maxCallDepth));

                Name = name ?? throw new ArgumentNullException(nameof(name));
                Method = method;
                LocalMemorySize = localMemorySize;
                MaxCallDepth = maxCallDepth;
            }

            #endregion

            #region Properties

            /// <summary>
            /// The name of the compiled function inside the kernel.
            /// </summary>
            public string Name { get; }

            /// <summary>
            /// Returns the managed method reference (if any).
            /// </summary>
            public MethodBase Method { get; }

            /// <summary>
            /// Returns the local memory size in bytes.
            /// </summary>
            public int LocalMemorySize { get; }

            /// <summary>
            /// Returns the estimated maximum call depth.
            /// </summary>
            public int MaxCallDepth { get; }

            #endregion
        }

        /// <summary>
        /// Provides detailed information about compiled kernels.
        /// </summary>
        public class CompiledKernelInfo
        {
            #region Instance

            /// <summary>
            /// Constructs a new kernel information object.
            /// </summary>
            /// <param name="sharedAllocations">All shared allocations.</param>
            /// <param name="functions">
            /// An array containing detailed function information.
            /// </param>
            public KernelInfo(
                in AllocaKindInformation sharedAllocations,
                ImmutableArray<FunctionInfo> functions)
            {
                SharedAllocations = sharedAllocations;
                Functions = functions;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Returns detailed information about all shared allocations.
            /// </summary>
            /// <remarks>
            /// This information will be populated if the flag
            /// <see cref="ContextFlags.EnableKernelInformation"/> is set.
            /// </remarks>
            public AllocaKindInformation SharedAllocations { get; }

            /// <summary>
            /// Returns information about all functions in the compiled kernel.
            /// </summary>
            /// <remarks>
            /// This array will be populated if the flag
            /// <see cref="ContextFlags.EnableKernelInformation"/> is set.
            /// </remarks>
            public ImmutableArray<FunctionInfo> Functions { get; }

            #endregion

            #region Methods

            /// <summary>
            /// Dumps kernel information to the standard console output.
            /// </summary>
            public void Dump() => Dump(Console.Out);

            /// <summary>
            /// Dumps kernel information to the given text writer.
            /// </summary>
            /// <param name="writer">The text writer.</param>
            public virtual void Dump(TextWriter writer)
            {
                if (writer == null)
                    throw new ArgumentNullException(nameof(writer));

                // Shared memory
                if (SharedAllocations.TotalSize > 0)
                {
                    writer.WriteLine("Shared Memory:");
                    writer.Write("\tTotal Size: ");
                    writer.Write(SharedAllocations.TotalSize);
                    writer.WriteLine(" bytes");

                    foreach (var alloc in SharedAllocations)
                    {
                        writer.Write("\t");
                        writer.Write(alloc.ElementType.ToString());
                        writer.Write('[');
                        writer.Write(alloc.ArraySize);
                        writer.Write("] ");
                        writer.Write(alloc.TotalSize);
                        writer.WriteLine(" bytes");
                    }
                }

                // Information about methods, calls and local memory sizes
                if (!Functions.IsDefaultOrEmpty)
                {
                    writer.WriteLine("Functions:");
                    for (int i = 0, e = Functions.Length; i < e; ++i)
                    {
                        ref readonly var functionRef = ref Functions.ItemRef(i);
                        var methodName = functionRef.Method?.Name ?? functionRef.Name;
                        writer.Write('\t');
                        writer.WriteLine(methodName);

                        writer.Write("\t\tLocal Memory: ");
                        writer.WriteLine(functionRef.LocalMemorySize);
                        writer.WriteLine(" bytes");

                        writer.Write("\t\tMax Call Depth:");
                        writer.WriteLine(functionRef.MaxCallDepth);
                    }
                }
            }

            #endregion
        }

A link to the existing functionality in the scope of the CompiledKernel class might look like this:

        /// <summary>
        /// Returns information about all functions in the compiled kernel.
        /// </summary>
        /// <remarks>
        /// This instance will be available when the
        /// <see cref="ContextFlags.EnableKernelInformation"/> is set.
        /// </remarks>
        public CompiledKernelInfo Info { get; }

The code above assumes that a ContextFlag named EnableKernelInformation is present to avoid unnecessary object creation if detailed information is not required:

         /// <summary>
        /// Enables detailed kernel information about all compiled kernel functions.
        /// </summary>
        EnableKernelInformation = 1 << 3,

All kernel loaders should be extended with additional overloads to "return" custom KernelInfo instances. A sample implementation of this class might look like:

    /// <summary>
    /// Provides detailed information about compiled kernels.
    /// </summary>
    public sealed class KernelInfo : CompiledKernel.KernelInfo
    {
        #region Static

        /// <summary>
        /// 
        /// </summary>
        /// <param name="info">The underlying kernel info (if any).</param>
        /// <param name="minGroupSize">The minimum group size (if known).</param>
        /// <param name="minGridSize">The minimum grid size (if known).</param>
        /// <returns></returns>
        public static KernelInfo CreateFrom(
            CompiledKernel.KernelInfo info,
            int? minGroupSize,
            int? minGridSize) =>
            info is null
            ? null
            : new KernelInfo(
                minGroupSize,
                minGridSize,
                info.SharedAllocations,
                info.Functions);

        #endregion

        #region Instance

        /// <summary>
        /// Constructs a new kernel information object.
        /// </summary>
        /// <param name="minGroupSize">The minimum group size (if known).</param>
        /// <param name="minGridSize">The minimum grid size (if known).</param>
        public KernelInfo(int? minGroupSize, int? minGridSize)
            : this(
                  minGroupSize,
                  minGridSize,
                  new AllocaKindInformation(
                      ImmutableArray<AllocaInformation>.Empty,
                      0),
                  ImmutableArray<CompiledKernel.FunctionInfo>.Empty)
        { }

        /// <summary>
        /// Constructs a new kernel information object.
        /// </summary>
        /// <param name="minGroupSize">The minimum group size (if known).</param>
        /// <param name="minGridSize">The minimum grid size (if known).</param>
        /// <param name="sharedAllocations">All shared allocations.</param>
        /// <param name="functions">
        /// An array containing detailed function information.
        /// </param>
        public KernelInfo(
            int? minGroupSize,
            int? minGridSize,
            in AllocaKindInformation sharedAllocations,
            ImmutableArray<CompiledKernel.FunctionInfo> functions)
            : base(sharedAllocations, functions)
        {
            MinGroupSize = minGroupSize;
            MinGridSize = minGridSize;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Returns the estimated group size to gain maximum occupancy on this device.
        /// </summary>
        public int? MinGroupSize { get; }

        /// <summary>
        /// Returns the minimum grid size to gain maximum occupancy on this device.
        /// </summary>
        public int? MinGridSize { get; }

        #endregion

        #region Methods

        /// <summary>
        /// Dumps kernel information to the given text writer.
        /// </summary>
        /// <param name="writer">The text writer.</param>
        public override void Dump(TextWriter writer)
        {
            base.Dump(writer);

            // Group and grid dimensions
            if (MinGroupSize.HasValue)
            {
                writer.Write(nameof(MinGroupSize));
                writer.Write(' ');
                writer.WriteLine(MinGroupSize);
            }
            if (MinGridSize.HasValue)
            {
                writer.Write(nameof(MinGridSize));
                writer.Write(' ');
                writer.WriteLine(MinGridSize);
            }
        }

        #endregion
    }
@m4rs-mt m4rs-mt added difficulty:beginner A beginner task feature A new feature (or feature request) labels May 11, 2020
@m4rs-mt m4rs-mt added this to the v0.8.1 milestone May 12, 2020
@m4rs-mt m4rs-mt linked a pull request Jun 15, 2020 that will close this issue
@m4rs-mt m4rs-mt self-assigned this Jun 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty:beginner A beginner task feature A new feature (or feature request)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant