public static void ToHtml()

in src/PerfView/JitStats.cs [17:375]


        public static void ToHtml(TextWriter writer, TraceProcess stats, TraceLoadedDotNetRuntime runtime, string fileName)
        {
            JITStatsEx statsEx = JITStatsEx.Create(runtime);

            var usersGuideFile = ClrStatsUsersGuide.WriteUsersGuide(fileName);
            bool hasInliningEvents = runtime.JIT.Stats().InliningSuccesses.Count > 0 || runtime.JIT.Stats().InliningFailures.Count > 0;

            writer.WriteLine("<H3><A Name=\"Stats_{0}\"><font color=\"blue\">JIT Stats for for Process {1,5}: {2}</font><A></H3>", stats.ProcessID, stats.ProcessID, stats.Name);
            writer.WriteLine("<UL>");
            {
                if (!string.IsNullOrEmpty(stats.CommandLine))
                {
                    writer.WriteLine("<LI>CommandLine: {0}</LI>", stats.CommandLine);
                }

                writer.WriteLine("<LI>Process CPU Time: {0:n0} msec</LI>", stats.CPUMSec);
                writer.WriteLine("<LI>Guidance on JIT data:");
                writer.WriteLine("<UL>");
                {
                    writer.WriteLine("<LI> <A HREF=\"{0}#UnderstandingJITPerf\">JIT Perf Users Guide</A></LI>", usersGuideFile);

                    if (runtime.JIT.Stats().BackgroundJitThread != 0 || runtime.JIT.Stats().BackgroundJitAbortedAtMSec != 0)
                    {
                        writer.WriteLine("<LI>Background JIT compilation (System.Runtime.ProfileOptimize) in use - <A HREF=\"{0}#UnderstandingBackgroundJIT\">Guide</A></LI>", usersGuideFile);
                        writer.WriteLine(" <UL>");

                        if (runtime.JIT.Stats().RecordedModules.Count == 0)
                        {
                            writer.WriteLine(" <LI><font color=\"red\">This trace is missing some background JIT events, which could result in incorrect information in the background JIT blocking reason column.</font></LI>");
                            writer.WriteLine(" <LI><font color=\"red\">Re-collect the trace enabling \"Background JIT\" events on the collection menu to fix this.</font></LI>");
                        }

                        if (runtime.JIT.Stats().BackgroundJitAbortedAtMSec != 0)
                        {
                            writer.WriteLine("  <LI><font color=\"red\">WARNING: Background JIT aborted at {0:n3} Msec</font></LI>", runtime.JIT.Stats().BackgroundJitAbortedAtMSec);
                            writer.WriteLine("  <LI>The last assembly before the abort was '{0}' loaded {1} at {2:n3}</LI>",
                                runtime.JIT.Stats().LastAssemblyLoadNameBeforeAbort, runtime.JIT.Stats().LastAssemblyLoadBeforeAbortSuccessful ? "successfully" : "unsuccessfully",
                                runtime.JIT.Stats().LastAssemblyLoadBeforeAbortMSec);
                        }

                        writer.WriteLine(" </UL>");
                    }
                    else if (runtime.JIT.Stats().BackgroundJitThread == 0)
                    {
                        if (runtime.JIT.Stats().BackgroundJITEventsOn)
                        {
                            writer.WriteLine("<LI>Background JIT compilation (System.Runtime.ProfileOptimize) not in use - <A HREF=\"{0}#UnderstandingBackgroundJIT\">Guide</A></LI>", usersGuideFile);
                            writer.WriteLine("<UL><LI>If there is a lot of JIT time enabling this may improve startup performance</LI></UL>");
                        }
                        else
                        {
                            writer.WriteLine("<LI>Background JIT compilation (System.Runtime.ProfileOptimize) events are not being collected - <A HREF=\"{0}#UnderstandingBackgroundJIT\">Guide</A></LI>", usersGuideFile);
                            writer.WriteLine("<UL><LI>If you are interested in seeing them enable the 'Background JIT' checkbox in the 'Advanced' section of the collection dialog when collecting the data.</LI></UL>");
                        }
                    }

                    if (!runtime.IsTieredCompilationEnabled)
                    {
                        writer.WriteLine("<LI>Tiered compilation not in use - <A HREF=\"{0}#UnderstandingTieredCompilation\">Guide</A></LI>", usersGuideFile);
                        writer.WriteLine("<UL><LI>On .Net Core, enabling this may improve application performance</LI></UL>");
                    }
                    else
                    {
                        writer.WriteLine("<LI>Tiered compilation in use - <A HREF=\"{0}#UnderstandingTieredCompilation\">Guide</A></LI>", usersGuideFile);
                    }
                }
                writer.WriteLine("</UL>");
                writer.WriteLine("</LI>");

                writer.WriteLine("<LI>Raw data:");
                writer.WriteLine("<UL>");
                {
                    writer.WriteLine("<LI>Individual JIT Events <A HREF=\"#Events_{0}\">Html</A> | <A HREF=\"command:excel/{0}\">Excel</A></LI>", stats.ProcessID);
                    if (hasInliningEvents)
                    {
                        writer.WriteLine("<LI>Inlining Decisions <A HREF=\"#Inlining_{0}\">Html</A> | <A HREF=\"command:excelInlining/{0}\">Excel</A></LI>", stats.ProcessID);
                    }
                    else
                    {
                        writer.WriteLine("<LI><I>No JIT Inlining data available.  Consider enabling the JITInlining option.</I></LI>");
                    }

                    if (runtime.JIT.Stats().BackgroundJitThread != 0 || runtime.JIT.Stats().BackgroundJitAbortedAtMSec != 0)
                    {
                        writer.WriteLine("<LI>Background Jit Diagnostics <A HREF=\"command:excelBackgroundDiag/{0}\">Excel</A></LI>", stats.ProcessID);
                    }
                }
                writer.WriteLine("</UL>");
                writer.WriteLine("</LI>");


                //
                // Summary table by trigger
                //

                writer.WriteLine("<LI> Summary of jitting time by trigger:");

                writer.WriteLine("<Center>");
                writer.WriteLine("<Table Border=\"1\">");
                writer.WriteLine("<TR>" +
                    "<TH Title=\"The reason why the JIT was invoked.\">Jitting Trigger</TH>" +
                    "<TH Title=\"The number of times the JIT was invoked\">Num Compilations</TH>" +
                    "<TH Title=\"The % of all compilations that triggered by this trigger\">% of total jitted compilations</TH>" +
                    "<TH Title=\"The total time used by all compilations with the given trigger\">Jit Time msec</TH>" +
                    "<TH Title=\"The total time used by all compilations with the given trigger as a % of total CPU time used for the process\">Jit Time (% of total process CPU)</TH>" +
                    "</TR>");
                writer.WriteLine(FormatThreadingModelTableRow("TOTAL", runtime.JIT.Stats().Count, runtime.JIT.Stats().TotalCpuTimeMSec, stats, runtime));
                writer.WriteLine(FormatThreadingModelTableRow(CompilationThreadKind.Foreground, runtime.JIT.Stats().CountForeground, runtime.JIT.Stats().TotalForegroundCpuTimeMSec, stats, runtime));
                writer.WriteLine(FormatThreadingModelTableRow(CompilationThreadKind.MulticoreJitBackground, runtime.JIT.Stats().CountBackgroundMultiCoreJit, runtime.JIT.Stats().TotalBackgroundMultiCoreJitCpuTimeMSec, stats, runtime));
                writer.WriteLine(FormatThreadingModelTableRow(CompilationThreadKind.TieredCompilationBackground, runtime.JIT.Stats().CountBackgroundTieredCompilation, runtime.JIT.Stats().TotalBackgroundTieredCompilationCpuTimeMSec, stats, runtime));

                writer.WriteLine("</Table>");
                writer.WriteLine("</Center>");
                writer.WriteLine("</LI>");

                //
                // Module table
                //

                // Sort the module list by Jit Time;
                List<string> moduleNames = new List<string>(statsEx.TotalModuleStats.Keys);
                moduleNames.Sort(delegate (string x, string y)
                {
                    double diff = statsEx.TotalModuleStats[y].TotalCpuTimeMSec - statsEx.TotalModuleStats[x].TotalCpuTimeMSec;
                    if (diff > 0)
                    {
                        return 1;
                    }
                    else if (diff < 0)
                    {
                        return -1;
                    }

                    return 0;
                });


                writer.WriteLine("<LI> Summary of jitting time by module:</P>");
                writer.WriteLine("<Center>");
                writer.WriteLine("<Table Border=\"1\">");
                writer.Write("<TR>" +
                    "<TH Title=\"The name of the module\">Name</TH>" +
                    "<TH Title=\"The total CPU time spent jitting for all methods in this module\">JitTime<BR/>msec</TH>" +
                    "<TH Title=\"The number of times the JIT was invoked for methods in this module\">Num Compilations</TH>" +
                    "<TH Title=\"The total amount of IL processed by the JIT for all methods in this module\">IL Size</TH>" +
                    "<TH Title=\"The total amount of native code produced by the JIT for all methods in this module\">Native Size</TH>" +
                    "<TH Title=\"Time spent jitting synchronously to produce code for methods that were just invoked. These compilations often consume time at startup.\">" + GetLongNameForThreadClassification(CompilationThreadKind.Foreground) + "<BR/>msec</TH>" +
                    "<TH Title=\"Time spent jitting asynchronously to produce code for methods the runtime speculates will be invoked in the future.\">" + GetLongNameForThreadClassification(CompilationThreadKind.MulticoreJitBackground) + "<BR/>msec</TH>" +
                    "<TH Title=\"Time spent jitting asynchronously to produce code for methods that is more optimized than their initial code.\">" + GetLongNameForThreadClassification(CompilationThreadKind.TieredCompilationBackground) + "<BR/>msec</TH>");

                if (runtime.JIT.Stats().IsJitAllocSizePresent)
                {
                    writer.Write("<TH Title=\"The total amount of heap memory requested for the code produced by the JIT for all methods in this module.  \">JIT Hotcode request size</TH>");
                    writer.Write("<TH Title=\"The total amount of heap memory requested for the read-only data of code produced by the JIT for all methods in this module.  \">JIT RO-data request size</TH>");
                    writer.Write("<TH Title=\"The total amount of heap memory allocated for the code produced by the JIT for all methods in this module. \">Allocated size for JIT code</TH>");
                }

                writer.WriteLine("</TR>");

                string moduleTableRow = "<TR>" +
                    "<TD Align=\"Left\">{0}</TD>" +
                    "<TD Align=\"Center\">{1:n1}</TD>" +
                    "<TD Align=\"Center\">{2:n0}</TD>" +
                    "<TD Align=\"Center\">{3:n0}</TD>" +
                    "<TD Align=\"Center\">{4:n0}</TD>" +
                    "<TD Align=\"Center\">{5:n1}</TD>" +
                    "<TD Align=\"Center\">{6:n1}</TD>" +
                    "<TD Align=\"Center\">{7:n1}</TD>";
                
                writer.Write(moduleTableRow,
                    "TOTAL",
                    runtime.JIT.Stats().TotalCpuTimeMSec,
                    runtime.JIT.Stats().Count,
                    runtime.JIT.Stats().TotalILSize,
                    runtime.JIT.Stats().TotalNativeSize,
                    runtime.JIT.Stats().TotalForegroundCpuTimeMSec,
                    runtime.JIT.Stats().TotalBackgroundMultiCoreJitCpuTimeMSec,
                    runtime.JIT.Stats().TotalBackgroundTieredCompilationCpuTimeMSec);

                string allocSizeColumns = "";
                if (runtime.JIT.Stats().IsJitAllocSizePresent)
                {
                    allocSizeColumns +=
                       "<TD Align=\"Center\">{0:n0}</TD>" +
                       "<TD Align=\"Center\">{1:n0}</TD>" +
                       "<TD Align=\"Center\">{2:n0}</TD>";

                    writer.Write(allocSizeColumns,
                        runtime.JIT.Stats().TotalHotCodeAllocSize,
                        runtime.JIT.Stats().TotalRODataAllocSize,
                        runtime.JIT.Stats().TotalAllocSizeForJitCode);
                }
                writer.WriteLine();

                foreach (string moduleName in moduleNames)
                {
                    JITStats info = statsEx.TotalModuleStats[moduleName];
                    writer.Write(moduleTableRow,
                        moduleName.Length == 0 ? "&lt;UNKNOWN&gt;" : moduleName,
                        info.TotalCpuTimeMSec,
                        info.Count,
                        info.TotalILSize,
                        info.TotalNativeSize,
                        info.TotalForegroundCpuTimeMSec,
                        info.TotalBackgroundMultiCoreJitCpuTimeMSec,
                        info.TotalBackgroundTieredCompilationCpuTimeMSec);

                    if (runtime.JIT.Stats().IsJitAllocSizePresent)
                    {
                        writer.Write(allocSizeColumns,
                            info.TotalHotCodeAllocSize,
                            info.TotalRODataAllocSize,
                            info.TotalAllocSizeForJitCode);
                    }

                    writer.WriteLine("</TR>");

                }
                writer.WriteLine("</Table>");
                writer.WriteLine("</Center>");
                writer.WriteLine("</LI>");

            }
            writer.WriteLine("</UL>");

            bool backgroundJitEnabled = runtime.JIT.Stats().BackgroundJitThread != 0;

            writer.WriteLine("<HR/>");
            writer.WriteLine("<H4><A Name=\"Events_{0}\">Individual JIT Events for Process {1,5}: {2}<A></H4>", stats.ProcessID, stats.ProcessID, stats.Name);

            // We limit the number of JIT events we ut on the page because it makes the user exerience really bad (browsers crash)
            const int maxEvents = 1000;
            if (runtime.JIT.Methods.Count >= maxEvents)
            {
                writer.WriteLine("<p><Font color=\"red\">Warning: Truncating JIT events to " + maxEvents + ".  <A HREF=\"command:excel/{0}\">View in excel</A> to look all of them.</font></p>", stats.ProcessID);
            }

            bool showOptimizationTiers = ShouldShowOptimizationTiers(runtime);
            writer.WriteLine("<Center>");
            writer.WriteLine("<Table Border=\"1\">");
            writer.Write(
                "<TR>" +
                "<TH>Start<BR/>(msec)</TH>" +
                "<TH>Jit Time<BR/>(msec)</TH>" +
                "<TH>IL<BR/>Size</TH>" +
                "<TH>Native<BR/>Size</TH>");

            if (runtime.JIT.Stats().IsJitAllocSizePresent)
            {
                writer.Write(
                    "<TH>JIT Hotcode<BR/>request size</TH>" +
                    "<TH>JIT RO-data<BR/>request size</TH>" +
                    "<TH>Allocated size<BR/>for JIT code</TH>" +
                    "<TH>JIT Allocation<BR/>Flags</TH>"
                    );
            }

            if (showOptimizationTiers)
            {
                writer.Write("<TH Title=\"The optimization tier at which the method was jitted.\">Optimization<BR/>Tier</TH>");
            }
            writer.Write(
                "<TH>Method Name</TH>" +
                "<TH Title=\"Is Jit compilation occurring in the background for Multicore JIT (MC), in the background for tiered compilation (TC), or in the foreground on first execution of a method (FG).\">Trigger</TH>" +
                "<TH>Module</TH>");
            if (backgroundJitEnabled)
            {
                writer.Write(
                    "<TH Title=\"How far ahead of the method usage was relative to the background JIT operation.\">Distance Ahead</TH>" +
                    "<TH Title=\"Why the method was not JITTed in the background.\">Background JIT Blocking Reason</TH>");
            }
            writer.WriteLine("</TR>");
            int eventCount = 0;
            foreach (TraceJittedMethod _event in runtime.JIT.Methods)
            {
                writer.Write(
                    "<TR>" +
                    "<TD Align=\"Center\">{0:n3}</TD>" +
                    "<TD Align=\"Center\">{1:n1}</TD>" +
                    "<TD Align=\"Center\">{2:n0}</TD>" +
                    "<TD Align=\"Center\">{3:n0}</TD>",
                    _event.StartTimeMSec,
                    _event.CompileCpuTimeMSec,
                    _event.ILSize,
                    _event.NativeSize);

                if (_event.IsJitAllocSizePresent)
                {
                    writer.Write(
                        "<TD Align=\"Center\">{0}</TD>" +
                        "<TD Align=\"Center\">{1}</TD>" +
                        "<TD Align=\"Center\">{2}</TD>" +
                        "<TD Align=\"Center\">{3}</TD>",
                        _event.JitHotCodeRequestSize,
                        _event.JitRODataRequestSize,
                        _event.AllocatedSizeForJitCode,
                        _event.JitAllocFlag
                        );
                }

                if (showOptimizationTiers)
                {
                    writer.Write(
                        "<TD Align=\"Center\">{0}</TD>",
                        _event.OptimizationTier == OptimizationTier.Unknown ? string.Empty : _event.OptimizationTier.ToString());
                }
                writer.Write(
                    "<TD Align=Left>{0}</TD>" +
                    "<TD Align=\"Center\">{1}</TD>" +
                    "<TD Align=\"Center\">{2}</TD>",
                    _event.MethodName ?? "&nbsp;",
                    GetShortNameForThreadClassification(_event.CompilationThreadKind),
                    _event.ModuleILPath.Length != 0 ? Path.GetFileName(_event.ModuleILPath) : "&lt;UNKNOWN&gt;");
                if (backgroundJitEnabled)
                {
                    writer.Write(
                        "<TD Align=\"Center\">{0:n3}</TD>" +
                        "<TD Align=\"Left\">{1}</TD>",
                        _event.DistanceAhead,
                        _event.CompilationThreadKind == CompilationThreadKind.MulticoreJitBackground ? "Not blocked" : _event.BlockedReason);
                }
                writer.WriteLine("</TR>");
                eventCount++;
                if (eventCount >= maxEvents)
                {
                    break;
                }
            }
            writer.WriteLine("</Table>");
            writer.WriteLine("</Center>");

            if (hasInliningEvents)
            {
                writer.WriteLine("<HR/>");
                writer.WriteLine("<A Name=\"Inlining_{0}\">", stats.ProcessID);
                writer.WriteLine("<H4>Successful Inlinings for Process {0,5}: {1}<A></H4>", stats.ProcessID, stats.Name);
                writer.WriteLine("<Center>");
                writer.WriteLine("<Table Border=\"1\">");
                writer.Write("<TR><TH>Method Begin Compiled</TH><TH>Inliner</TH><TH>Inlinee</TH></TR>");
                foreach (InliningSuccessResult success in runtime.JIT.Stats().InliningSuccesses)
                {
                    writer.Write("<TR><TD>{0}</TD><TD>{1}</TD><TD>{2}</TD></TR>", success.MethodBeingCompiled, success.Inliner, success.Inlinee);
                }
                writer.WriteLine("</Table>");
                writer.WriteLine("</Center>");
                writer.WriteLine("<H4>Failed Inlinings for Process {0,5}: {1}<A></H4>", stats.ProcessID, stats.Name);
                writer.WriteLine("<Center>");
                writer.WriteLine("<Table Border=\"1\">");
                writer.Write("<TR><TH>Method Begin Compiled</TH><TH>Inliner</TH><TH>Inlinee</TH><TH>Failure Reason</TH></TR>");
                foreach (InliningFailureResult failure in runtime.JIT.Stats().InliningFailures)
                {
                    writer.Write("<TR><TD>{0}</TD><TD>{1}</TD><TD>{2}</TD><TD>{3}</TD></TR>", failure.MethodBeingCompiled, failure.Inliner, failure.Inlinee, failure.Reason);
                }
                writer.WriteLine("</Table>");
                writer.WriteLine("</Center>");
            }

            writer.WriteLine("<HR/><HR/><BR/><BR/>");
        }