Skip to content

Improve ordinal and clock notation hot paths#1732

Merged
clairernovotny merged 17 commits intomainfrom
codex/performance-hotspots-net11
Apr 21, 2026
Merged

Improve ordinal and clock notation hot paths#1732
clairernovotny merged 17 commits intomainfrom
codex/performance-hotspots-net11

Conversation

@clairernovotny
Copy link
Copy Markdown
Member

@clairernovotny clairernovotny commented Apr 18, 2026

Summary

  • avoid eager allocation/formatting in ordinal, clock-notation, transformer, metric, phrase-join, and single-part TimeSpan hot paths
  • preserve existing public API behavior with focused tests around optimized branches, culture-sensitive formatting, and boundary cases
  • address Copilot review feedback for culture-specific ordinal formatting, adjacent-hyphen normalization, and context-sensitive title casing
  • cache default ordinal number formatting by culture name to remove the large int.Ordinalize(culture) positive-number regression found in the benchmark artifacts
  • repair benchmark comparison reporting so ResultsComparer restores with an isolated NuGet config and no longer uploads a hidden build-failure fragment as a successful report
  • expand BenchmarkDotNet coverage for optimized paths and control paths:
    • metric default int small/kilo/mega plus boundary, giga, formatted fallback, and double milli cases
    • formatter first-touch/date/data-unit cases plus single-part, multi-part, zero, and words TimeSpan humanization

Benchmark Evidence

Local net10 short BenchmarkDotNet runs on Apple M2 Max after b959f088:

  • MetricNumeralBenchmarks: small 59.05 ns / 56 B, kilo 117.68 ns / 112 B, mega 113.29 ns / 112 B, boundary 149.74 ns / 128 B, giga 158.14 ns / 152 B, formatted fallback 205.21 ns / 128 B, milli 125.57 ns / 136 B
  • FormatterBenchmarks: Russian single-part TimeSpan 95.84 ns / 64 B, multi-part control 423.60 ns / 600 B, zero 161.50 ns / 80 B, words 131.71 ns / 224 B, Romanian Date 140.24 ns / 136 B, Arabic DataUnit 39.56 ns / 80 B

Short local review-fix spot checks after 58084558:

  • OrdinalBenchmarks: English ordinalize 29.93 ns / 64 B; custom-culture paths unchanged in shape for Dutch/Turkish/Greek/Finnish control cases
  • TransformersBenchmarks: title case 10 chars 201.24 ns / 696 B, 100 chars 2.424 us / 7264 B, 1000 chars 24.483 us / 73200 B

Short local ordinal regression check after 3221a0ad:

  • OrdinalBenchmarks: English 27.63 ns / 64 B, Dutch 44.51 ns / 176 B, Turkish 45.18 ns / 176 B, Greek 46.37 ns / 176 B, Finnish 44.53 ns / 176 B
  • The prior GitHub artifact for 58084558 showed Dutch/Turkish/Greek around 110-111 us; the cache change removes that regression locally.

GitHub benchmark workflow:

Tests

  • dotnet build src/Benchmarks/Benchmarks.csproj -c Release -f net10.0
  • dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter '*MetricNumeralBenchmarks*' --job short --warmupCount 1 --iterationCount 3
  • dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter '*FormatterBenchmarks*' --job short --warmupCount 1 --iterationCount 3
  • dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter '*OrdinalBenchmarks*' --job short --warmupCount 1 --iterationCount 3
  • dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter '*TransformersBenchmarks*' --job short --warmupCount 1 --iterationCount 3
  • dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net10.0 --no-restore -- --filter-class '*OrdinalizeTests' --filter-class '*TransformersTests' --filter-class '*CoverageGapTests'
  • dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net10.0 --no-restore -- --filter-class '*OrdinalizeTests' --filter-class '*DutchGenderedOrdinalTests'
  • dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net11.0 --no-restore -- --filter-class '*OrdinalizeTests' --filter-class '*DutchGenderedOrdinalTests'
  • dotnet run --project src/Benchmarks/Benchmarks.csproj -c Release -f net10.0 -- --filter '*OrdinalBenchmarks*' --job short --warmupCount 1 --iterationCount 1
  • dotnet format Humanizer.slnx --verify-no-changes --verbosity diagnostic --no-restore
  • ruby -e 'require "yaml"; YAML.load_file(".github/workflows/benchmarks-baseline-vs-current.yml"); puts "yaml ok"'
  • dotnet pack src/Humanizer/Humanizer.csproj -c Release -o artifacts/packages/ordinal-benchmark-fix
  • dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net10.0 --no-restore
  • dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net11.0 --no-restore
  • git diff --check

Note: dotnet test --project tests/Humanizer.Tests/Humanizer.Tests.csproj --framework net8.0 --no-restore could not run locally because this machine does not have the .NET 8 runtime installed; CI should cover it.

Copilot AI review requested due to automatic review settings April 18, 2026 23:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Optimizes Humanizer’s ordinalization and phrase-based clock-notation conversion hot paths to reduce allocations and avoid unnecessary culture/word-resolution work.

Changes:

  • Refactors int.Ordinalize(..., CultureInfo) to avoid loading CultureInfo.NumberFormat on the positive-number path and to better preserve custom negative-sign behavior for negative values.
  • Updates phrase clock-notation template expansion to lazily resolve placeholder values only when used by the selected template.
  • Adds a regression test covering custom NegativeSign handling for negative ordinalization.

Reviewed changes

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

File Description
tests/Humanizer.Tests/OrdinalizeTests.cs Adds a test ensuring custom culture negative-sign is preserved for negative ordinals.
src/Humanizer/OrdinalizeExtensions.cs Introduces a new ordinal number-string formatting path intended to reduce culture formatting overhead.
src/Humanizer/Localisation/TimeToClockNotation/PhraseClockNotationConverter.cs Lazily resolves template placeholders to avoid computing unused hour/minute/article/day-period strings.

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

Comment thread src/Humanizer/OrdinalizeExtensions.cs Outdated
Comment thread src/Humanizer/OrdinalizeExtensions.cs Outdated
Copilot AI review requested due to automatic review settings April 18, 2026 23:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


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

Copilot AI review requested due to automatic review settings April 18, 2026 23:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.


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

Comment thread src/Humanizer/OrdinalizeExtensions.cs
Copilot AI review requested due to automatic review settings April 19, 2026 00:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.


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

Comment thread src/Humanizer/Transformer/ToTitleCase.cs
Copilot AI review requested due to automatic review settings April 19, 2026 02:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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


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

Comment thread src/Humanizer/Transformer/To.cs Outdated
Comment thread src/Humanizer/OrdinalizeExtensions.cs
Comment thread .github/workflows/benchmarks-baseline-vs-current.yml Outdated
Copilot AI review requested due to automatic review settings April 19, 2026 03:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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


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

Comment thread src/Humanizer/Localisation/TimeToClockNotation/PhraseClockNotationConverter.cs Outdated
Comment thread .github/workflows/benchmarks-baseline-vs-current.yml
Comment thread src/Humanizer/Localisation/Formatters/DefaultFormatter.cs Outdated
Comment thread src/Humanizer/InflectorExtensions.cs Fixed
Comment thread src/Humanizer/StringHumanizeExtensions.cs Fixed
Copilot AI review requested due to automatic review settings April 19, 2026 22:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 41 out of 41 changed files in this pull request and generated 2 comments.


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

Comment thread src/Humanizer/ArticlePrefixSort.cs Outdated
Comment thread src/Humanizer/OrdinalizeExtensions.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 51 out of 51 changed files in this pull request and generated 1 comment.


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

Comment thread src/Humanizer/ArticlePrefixSort.cs
Copilot AI review requested due to automatic review settings April 20, 2026 22:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 59 out of 59 changed files in this pull request and generated no new comments.


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

@clairernovotny clairernovotny merged commit 4214280 into main Apr 21, 2026
20 checks passed
@clairernovotny clairernovotny deleted the codex/performance-hotspots-net11 branch April 21, 2026 00:10
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.

3 participants