[PR #396] Use BitVector128 in CharacterMap<T> #994

Closed
opened 2026-01-29 14:48:16 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/xoofx/markdig/pull/396

State: closed
Merged: Yes


CharacterMap<T> uses a bool[] isOpeningCharacter for quick lookup.

This PR replaces that by a custom BitVector128 that stores 128 bits is two ulong fields using a fixed size buffer.

This results in a measurable speedup:

The benchmark:

public class Program
{
    private string text = File.ReadAllText("spec.md");

    [Benchmark]
    public void TestMarkdig()
    {
        Markdown.Parse(text);
    }

    private static void Main()
    {
        BenchmarkRunner.Run<Program>();
    }
}

The results on .NET Framework:

BenchmarkDotNet=v0.10.6, OS=Windows 10.0.18363
Processor=Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), ProcessorCount=8
Frequency=10000000 Hz, Resolution=100.0000 ns, Timer=UNKNOWN
  [Host]     : Clr 4.0.30319.42000, 64bit RyuJIT-v4.8.4075.0
  DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.8.4075.0

Before:

Method Mean Error StdDev
TestMarkdig 3.363 ms 0.0209 ms 0.0196 ms

After:

Method Mean Error StdDev
TestMarkdig 3.275 ms 0.0220 ms 0.0206 ms

The results on .NET Core:

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.101
  [Host]     : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
  DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT

Before:

Method Mean Error StdDev
TestMarkdig 3.128 ms 0.0207 ms 0.0193 ms

After:

Method Mean Error StdDev
TestMarkdig 3.034 ms 0.0173 ms 0.0145 ms

Conclusion: parsing time is reduced by about 3 %.

**Original Pull Request:** https://github.com/xoofx/markdig/pull/396 **State:** closed **Merged:** Yes --- `CharacterMap<T>` uses a `bool[] isOpeningCharacter` for quick lookup. This PR replaces that by a custom `BitVector128` that stores 128 bits is two ulong fields using a fixed size buffer. This results in a measurable speedup: The benchmark: public class Program { private string text = File.ReadAllText("spec.md"); [Benchmark] public void TestMarkdig() { Markdown.Parse(text); } private static void Main() { BenchmarkRunner.Run<Program>(); } } The results on .NET Framework: BenchmarkDotNet=v0.10.6, OS=Windows 10.0.18363 Processor=Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), ProcessorCount=8 Frequency=10000000 Hz, Resolution=100.0000 ns, Timer=UNKNOWN [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.8.4075.0 DefaultJob : Clr 4.0.30319.42000, 64bit RyuJIT-v4.8.4075.0 Before: | Method | Mean | Error | StdDev | |------------ |---------:|----------:|----------:| | TestMarkdig | 3.363 ms | 0.0209 ms | 0.0196 ms | After: | Method | Mean | Error | StdDev | |------------ |---------:|----------:|----------:| | TestMarkdig | 3.275 ms | 0.0220 ms | 0.0206 ms | The results on .NET Core: BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363 Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores .NET Core SDK=3.1.101 [Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT Before: | Method | Mean | Error | StdDev | |------------ |---------:|----------:|----------:| | TestMarkdig | 3.128 ms | 0.0207 ms | 0.0193 ms | After: | Method | Mean | Error | StdDev | |------------ |---------:|----------:|----------:| | TestMarkdig | 3.034 ms | 0.0173 ms | 0.0145 ms | Conclusion: parsing time is reduced by about 3 %.
claunia added the pull-request label 2026-01-29 14:48:17 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/markdig#994