Skip to content

Refactor call tree rendering responsibilities - #57

Merged
rogeralsing merged 1 commit into
mainfrom
codex/20260321-070613-69be4363
Mar 21, 2026
Merged

rogeralsing merged 1 commit into
mainfrom
codex/20260321-070613-69be4363

Conversation

@rogeralsing

Copy link
Copy Markdown
Contributor

Summary

  • extract timeline bar rendering into CallTreeTimelineBarRenderer
  • extract hotness color interpolation into ProfilerHotnessColorScale
  • extract JIT number highlighting into ProfilerJitNumberHighlighter
  • extract timeline row construction into ProfilerTimelineRowsRenderer
  • slim down ProfilerCallTreeFormatter and ProfilerCallTreeRenderer so they focus on call-tree formatting/orchestration instead of mixed helper logic
  • add a regression test for public JIT highlighting behavior

Testing

  • roslynator fix src/ProfilerCore/Asynkron.Profiler.Core.csproj
  • roslynator fix src/ProfileTool/ProfileTool.csproj
  • roslynator fix tests/Asynkron.Profiler.Tests/Asynkron.Profiler.Tests.csproj
  • quickdup -path . -ext .cs -select 0..20 -min 2 -exclude ".g.,.generated."
  • dotnet format Asynkron.Profiler.sln
  • dotnet build Asynkron.Profiler.sln
  • dotnet test Asynkron.Profiler.sln

Copilot AI review requested due to automatic review settings March 21, 2026 07:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors call-tree/timeline rendering by extracting previously inlined helper logic into focused renderer/formatter components within ProfilerCore, and adds a regression test for public JIT number highlighting behavior.

Changes:

  • Extracted timeline bar rendering to CallTreeTimelineBarRenderer and timeline row construction to ProfilerTimelineRowsRenderer.
  • Extracted hotness color interpolation into ProfilerHotnessColorScale and JIT number highlighting into ProfilerJitNumberHighlighter.
  • Slimmed down ProfilerCallTreeFormatter/ProfilerCallTreeRenderer to delegate to the new helpers; added JIT highlighting regression tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Asynkron.Profiler.Tests/ProfilerJitNumberHighlighterTests.cs Adds regression coverage for JIT decimal/hex token highlighting behavior.
src/ProfilerCore/Rendering/ProfilerTimelineRowsRenderer.cs New component to build timeline-oriented call-tree output rows.
src/ProfilerCore/Rendering/ProfilerJitNumberHighlighter.cs New helper encapsulating regex-based JIT number highlighting.
src/ProfilerCore/Rendering/ProfilerHotnessColorScale.cs New helper for hotness normalization + theme color interpolation.
src/ProfilerCore/Rendering/ProfilerCallTreeRenderer.cs Delegates timeline rendering to ProfilerTimelineRowsRenderer; updates hotspot detection helper usage.
src/ProfilerCore/Rendering/ProfilerCallTreeFormatter.cs Delegates hotness color and JIT highlighting; delegates timeline bar rendering.
src/ProfilerCore/Rendering/CallTreeTimelineBarRenderer.cs New helper containing the timeline bar drawing logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +26
public Rows Build(
CallTreeNode rootNode,
string title,
ProfilerCallTreeRenderContext context,
int timelineWidth)
{
var terminalWidth = Console.WindowWidth > 0 ? Console.WindowWidth : 160;

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Console.WindowWidth can throw (e.g., when output is redirected / no interactive terminal). Consider mirroring ProfilerCommandLineHelp.GetHelpWidth(): check Console.IsOutputRedirected and/or wrap WindowWidth access in try/catch with a reasonable fallback width, so timeline rendering can’t crash in non-interactive contexts.

Suggested change
public Rows Build(
CallTreeNode rootNode,
string title,
ProfilerCallTreeRenderContext context,
int timelineWidth)
{
var terminalWidth = Console.WindowWidth > 0 ? Console.WindowWidth : 160;
private static int GetTerminalWidth()
{
const int fallbackWidth = 160;
if (Console.IsOutputRedirected)
{
return fallbackWidth;
}
try
{
var width = Console.WindowWidth;
return width > 0 ? width : fallbackWidth;
}
catch
{
return fallbackWidth;
}
}
public Rows Build(
CallTreeNode rootNode,
string title,
ProfilerCallTreeRenderContext context,
int timelineWidth)
{
var terminalWidth = GetTerminalWidth();

Copilot uses AI. Check for mistakes.
depth: 0,
timeline);

var outputLines = new List<IRenderable> { new Markup($"[bold {_theme.AccentColor}]{title}[/]") };

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title is interpolated into a Spectre.Console Markup string without escaping. If title contains markup control characters (e.g., [/] from a file name or filter), this can break rendering or throw. Escape the title (e.g., via Markup.Escape) before embedding it in markup.

Suggested change
var outputLines = new List<IRenderable> { new Markup($"[bold {_theme.AccentColor}]{title}[/]") };
var outputLines = new List<IRenderable> { new Markup($"[bold {_theme.AccentColor}]{Markup.Escape(title)}[/]") };

Copilot uses AI. Check for mistakes.
context.UseSelfTime,
context.Traversal.MaxWidth,
context.Traversal.SiblingCutoffPercent,
CallTreeHelpers.IsRuntimeNoise);

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file has using static Asynkron.Profiler.CallTreeHelpers; but still references CallTreeHelpers.IsRuntimeNoise explicitly. Consider removing the using static or switching the call to the unqualified IsRuntimeNoise to avoid redundant style.

Suggested change
CallTreeHelpers.IsRuntimeNoise);
IsRuntimeNoise);

Copilot uses AI. Check for mistakes.
@rogeralsing
rogeralsing merged commit b834a04 into main Mar 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants