Skip to content

Various optimisations to Markup instantiation & formatting#2008

Merged
patriksvensson merged 11 commits intospectreconsole:mainfrom
benbryant0:optimise
Feb 25, 2026
Merged

Various optimisations to Markup instantiation & formatting#2008
patriksvensson merged 11 commits intospectreconsole:mainfrom
benbryant0:optimise

Conversation

@benbryant0
Copy link
Copy Markdown
Contributor

@benbryant0 benbryant0 commented Jan 29, 2026

Somewhat related to #232

  • I have read the Contribution Guidelines
  • I have commented on the issue above and discussed the intended changes
  • A maintainer has signed off on the changes and the issue was assigned to me
  • All newly added code is adequately covered by tests
  • All existing tests are still running without errors
  • The documentation was modified to reflect the changes OR no documentation changes are required.

Changes

Added several benchmarks focused around the instantiation of the Markup type, since that's used all over the place when taking in strings. There's one overall benchmark (MarkupBenchmarks.Constructor) and every other benchmark I added is focused on a part of the logic called by the constructor at various levels. I did this mostly just to demonstrate the effects of individual changes. They're in separate commits, so feel free to just drop any benchmarks that aren't wanted.

The actual changes are also in independent commits except for the last one concerning spans in Paragraph.Append, which depends on the one before it. So again, feel free to drop any that are unwanted or that you'd want reworked heavily.

Benchmarks

Here are benchmark runs for before and after (with some minor editing to make comparison easier). I ran them for .NET Framework 4.8.1 as well since .NET standard is still supported. Just to make sure there were no unexpected negative effects.

.NET 10
Before
| Method             | Mean       | Error     | StdDev    | Gen0   | Gen1   | Allocated |
|------------------- |-----------:|----------:|----------:|-------:|-------:|----------:|
| Markup_Constructor | 3,140.0 ns | 0.0060 μs | 0.0050 μs | 1.4801 | 0.0076 |   9.07 KB |
| AnsiMarkup_Parse   | 2,339.0 ns | 0.0100 μs | 0.0089 μs | 1.0376 | 0.0038 |   6.38 KB |
After
| Method             | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Markup_Constructor | 1,057.4 ns | 3.40 ns | 3.01 ns | 0.4883 | 0.0019 |   2.99 KB |
| AnsiMarkup_Parse   |   760.3 ns | 2.01 ns | 1.79 ns | 0.3710 | 0.0010 |   2.27 KB |

Before
| Method                   | Mean       | Error    | StdDev   | Gen0   | Allocated |
|------------------------- |-----------:|---------:|---------:|-------:|----------:|
| Replace_NoEmoji          |   17.58 ns | 0.131 ns | 0.116 ns | 0.0280 |     176 B |
| Replace_NoEmoji_ButColon |   49.38 ns | 0.201 ns | 0.178 ns | 0.0459 |     288 B |
| Replace_Emoji            |   72.19 ns | 0.322 ns | 0.301 ns | 0.0471 |     296 B |
After
| Method                   | Mean       | Error     | StdDev    | Gen0   | Allocated |
|------------------------- |-----------:|----------:|----------:|-------:|----------:|
| Replace_NoEmoji          |   3.013 ns | 0.0024 ns | 0.0021 ns |      - |         - |
| Replace_NoEmoji_ButColon |   6.906 ns | 0.0018 ns | 0.0016 ns |      - |         - |
| Replace_Emoji            |  70.942 ns | 0.2063 ns | 0.1722 ns | 0.0471 |     296 B |

Before
| Method | text                 | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------- |--------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Append | Multiple lines. [31] |   649.6 ns | 3.08 ns | 2.73 ns | 0.3872 | 0.0010 |   2.38 KB |
| Append | One line....... [31] |   830.3 ns | 1.86 ns | 1.55 ns | 0.5341 | 0.0029 |   3.27 KB |
After
| Method | text                 | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------- |--------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Append | Multiple lines. [31] |   295.3 ns | 0.80 ns | 0.71 ns | 0.1373 |      - |     864 B |
| Append | One line....... [31] |   451.7 ns | 3.20 ns | 3.00 ns | 0.2089 | 0.0005 |    1312 B |
.NET Framework 4.8.1
Before
| Method             | Mean       | Error     | StdDev    | Gen0   | Gen1   | Allocated |
|------------------- |-----------:|----------:|----------:|-------:|-------:|----------:|
| Markup_Constructor | 9,269.0 ns | 0.0328 μs | 0.0274 μs | 2.4261 | 0.0153 |  14.97 KB |
| AnsiMarkup_Parse   | 7,513.0 ns | 0.0108 μs | 0.0096 μs | 1.9455 | 0.0076 |  11.96 KB |
After
| Method             | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Markup_Constructor | 2,784.1 ns | 8.68 ns | 7.70 ns | 0.5646 |      - |   3.47 KB |
| AnsiMarkup_Parse   | 1,886.2 ns | 5.86 ns | 5.48 ns | 0.4330 |      - |   2.66 KB |

Before
| Method                   | Mean       | Error    | StdDev   | Gen0   | Allocated |
|------------------------- |-----------:|---------:|---------:|-------:|----------:|
| Replace_NoEmoji          |   38.21 ns | 0.197 ns | 0.175 ns | 0.0166 |     104 B |
| Replace_NoEmoji_ButColon |  133.24 ns | 0.685 ns | 0.607 ns | 0.0637 |     401 B |
| Replace_Emoji            |  221.65 ns | 0.224 ns | 0.199 ns | 0.0637 |     401 B |
After
| Method                   | Mean       | Error     | StdDev    | Gen0   | Allocated |
|------------------------- |-----------:|----------:|----------:|-------:|----------:|
| Replace_NoEmoji          |  17.674 ns | 0.1646 ns | 0.1539 ns |      - |         - |
| Replace_NoEmoji_ButColon |  22.404 ns | 0.0473 ns | 0.0443 ns |      - |         - |
| Replace_Emoji            | 210.119 ns | 0.4512 ns | 0.3768 ns | 0.0637 |     401 B |

Before
| Method | text                 | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------- |--------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Append | Multiple lines. [31] | 1,414.8 ns | 2.16 ns | 1.81 ns | 0.4463 | 0.0019 |   2.74 KB |
| Append | One line....... [31] | 1,780.9 ns | 5.19 ns | 4.60 ns | 0.5779 | 0.0019 |   3.56 KB |
After
| Method | text                 | Mean       | Error   | StdDev  | Gen0   | Gen1   | Allocated |
|------- |--------------------- |-----------:|--------:|--------:|-------:|-------:|----------:|
| Append | Multiple lines. [31] |   849.1 ns | 2.41 ns | 2.14 ns | 0.1535 |      - |     971 B |
| Append | One line....... [31] | 1,111.4 ns | 1.35 ns | 1.13 ns | 0.2270 |      - |    1436 B |

Please upvote 👍 this pull request if you are interested in it.

@benbryant0
Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree

@patriksvensson
Copy link
Copy Markdown
Contributor

Sorry for not getting back to you sooner about this PR. The results are very promising, but the PR needs to be rebased against upstream and have the merge conflicts resolved. I can do this for you, but it will take a couple of days since I'm away on vacation.

@benbryant0
Copy link
Copy Markdown
Contributor Author

No problem, thanks for taking a look at it. I just held off on rebasing due to instructions in the contribution guidelines, so I'll get on that now.

@patriksvensson patriksvensson merged commit c82f755 into spectreconsole:main Feb 25, 2026
3 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