4kb Markdown Files Benchmark

Time to build 4096 markdown files

Last built at 2026-01-25T22:20:43 running @ 2445 Mhz

build.with.powershell.fast (1.09s)
Build Script

param(
[Alias('Input')]
[string]
$InputPath = "$psScriptRoot/TestMarkdown",

[string]
$OutputPath = "$psScriptRoot/PowerShellFast"
)


$mdPipelineBuilder = [Markdig.MarkdownPipelineBuilder]::new()
$mdPipeline = [Markdig.MarkdownExtensions]::UsePipeTables($mdPipelineBuilder).Build()

foreach ($fullPath in [IO.Directory]::EnumerateFileSystemEntries($InputPath)) {
    $fileHtml = [Markdig.Markdown]::ToHtml(
        [IO.File]::ReadAllText($fullPath), $mdPipeline
    )
    
    $fileName = @($fullPath -split '[\\/]')[-1]
    
    $directoryPath = $OutputPath, ($fileName -replace '\.md$') -join '/'

    if (-not [IO.Directory]::Exists($directoryPath)) {
        $null = [IO.Directory]::CreateDirectory($directoryPath)
    }

    $fileOutputPath = $OutputPath, ($fileName -replace '\.md$'), 'index.html' -join '/'
    
    [IO.File]::WriteAllText($fileOutputPath, $fileHtml)    
}

build.with.powershell.New-Item (2.78s)
Build Script

param(
[Alias('Input')]
[string]
$InputPath = "$psScriptRoot/TestMarkdown",

[string]
$OutputPath = "$psScriptRoot/PowerShellSlowest"
)


foreach ($file in Get-ChildItem -Path $InputPath -File) {
    
    $fileHtml = (ConvertFrom-Markdown -LiteralPath $file.FullName).Html
    
    $fileName = $file.Name
        
    $fileOutputPath = 
        Join-Path $OutputPath ($fileName -replace '\.md$') | 
            Join-Path -ChildPath ('index.html')

    New-Item -ItemType File -Path $fileOutputPath -Value $fileHtml -Force    
}

build.with.powershell.ConvertFrom-Markdown (2.83s)
Build Script

param(
[Alias('Input')]
[string]
$InputPath = "$psScriptRoot/TestMarkdown",

[string]
$OutputPath = "$psScriptRoot/PowerShellConvertFromMarkdown"
)


foreach ($file in Get-ChildItem -Path $InputPath -File) {
    
    $fileHtml = (ConvertFrom-Markdown -LiteralPath $file.FullName).Html
    
    $fileName = $file.Name
    
    $directoryPath = $OutputPath, ($fileName -replace '\.md$') -join '/'

    if (-not [IO.Directory]::Exists($directoryPath)) {
        $null = [IO.Directory]::CreateDirectory($directoryPath)
    }

    $fileOutputPath = $OutputPath, ($fileName -replace '\.md$'), 'index.html' -join '/'
    
    [IO.File]::WriteAllText($fileOutputPath, $fileHtml)    
}

build.with.powershell.Foreach-Object (3.13s)
Build Script

param(
[Alias('Input')]
[string]
$InputPath = "$psScriptRoot/TestMarkdown",

[string]
$OutputPath = "$psScriptRoot/PowerShellForeachObject"
)


Get-ChildItem -Path $InputPath -File |
    Foreach-Object {
        $in = $_
        New-Item -ItemType File -Path (
            Join-Path $OutputPath ($in.Name -replace '\.md$') | 
            Join-Path -ChildPath ./index.html
        ) -Value (
            ($in | 
                ConvertFrom-Markdown | 
                Select-Object -ExpandProperty html) 
        ) -Force
    }

build.with.11ty (7.97s)
Build Script

<#
.SYNOPSIS
    Builds 4kb markdown files with 11ty
.DESCRIPTION
    Builds 4kb markdown files with 11ty.
    
#>
Push-Location $PSScriptRoot

npx @11ty/eleventy --input=./TestMarkdown/*.md --output ./11ty/

Pop-Location


build.with.powershell.markx (13.53s)
Build Script

param(
[Alias('Input')]
[string]
$InputPath = "$psScriptRoot/TestMarkdown",

[string]
$OutputPath = "$psScriptRoot/PowerShellMarkX"
)


foreach ($fullPath in [IO.Directory]::EnumerateFileSystemEntries($InputPath)) {
    $markx = markx ([IO.File]::ReadAllText($fullPath))
    
    $fileName = @($fullPath -split '[\\/]')[-1]
    
    $directoryPath = $OutputPath, ($fileName -replace '\.md$') -join '/'

    if (-not [IO.Directory]::Exists($directoryPath)) {
        $null = [IO.Directory]::CreateDirectory($directoryPath)
    }

    $fileOutputPath = $OutputPath, ($fileName -replace '\.md$'), 'index.html' -join '/'
    
    [IO.File]::WriteAllText($fileOutputPath, $markx.html)    
}

The Numbers

TechniqueTimeRelativeSpeed
build.with.powershell.fast00:00:01.08699800.08033470203371848
build.with.powershell.New-Item00:00:02.77808910.20531496844669553
build.with.powershell.ConvertFrom-Markdown00:00:02.83195240.2092957413239711
build.with.powershell.Foreach-Object00:00:03.13040380.2313528235730149
build.with.11ty00:00:07.96982370.5890106625778223
build.with.powershell.markx00:00:13.53086491
View Source

<#
.SYNOPSIS
    Builds 4kb Markdown files
.DESCRIPTION
    Builds 4kb Markdown files N different ways, in order to test performance.
.NOTES
    In the interests of fair play, any prerequisities should be installed before builds are timed.
#>
param()

Push-Location $PSScriptRoot

#region Install Prereqs
if ($env:GITHUB_WORKFLOW) {
    $null = sudo npm install -g '@11ty/eleventy'

    Install-Module MarkX -Force

    Import-Module MarkX -Global
}
#endregion Install Prereqs

#region Get Clock Speed
$cpuSpeed = 
    if ($executionContext.SessionState.PSVariable.Get('IsLinux').Value) {
        Get-Content /proc/cpuinfo -Raw -ErrorAction SilentlyContinue | 
            Select-String "(?<Unit>Mhz|MIPS)\s+\:\s+(?<Value>[\d\.]+)" | 
            Select-Object -First 1 -ExpandProperty Matches |
            ForEach-Object {
                $_.Groups["Value"].Value -as [int]
            }
    } elseif ($executionContext.SessionState.PSVariable.Get('IsMacOS').Value) {
        (sysctl -n hw.cpufrequency) / 1e6 -as [int]
    } else {
        $getCimInstance = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Get-CimInstance','Cmdlet')
        if ($getCimInstance) {
            & $getCimInstance -Class Win32_Processor |
                Select-Object -ExpandProperty MaxClockSpeed
        }
    }
#endregion

$mySelf = $MyInvocation.MyCommand.ScriptBlock

& {
    foreach ($file in Get-ChildItem -filter build.with.*.ps1) {
        $techniqueName = $file.Name -replace '\.build\.with' -replace '\.ps1$'
        $script = (Get-Command $file.FullName -CommandType ExternalScript).ScriptBlock
        $time = Measure-Command { . $file.FullName } 
        [PSCustomObject]@{
            Technique = $techniqueName
            Time = $time
            Script = $script
        }
    }
} | Tee-Object -Variable buildTimes


$buildTimes = $buildTimes | Sort-Object Time

foreach ($buildTime in $buildTimes) {
    $relativeSpeed = $buildTime.Time.TotalMilliseconds / $buildTimes[-1].Time.TotalMilliseconds
    Add-Member NoteProperty -InputObject $buildTime -Name RelativeSpeed $relativeSpeed -Force
} 

$buildTimes | ConvertTo-Html -Title BuildTimes > ./times.html

@(
    "<html>"
    "<head>"    
    "<title>4kb Markdown Files</title>"
    "<meta name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1.0' />"
    "<style>"
    "
    
    body { height: 100vh; max-width: 100vw; margin:0 } 
    
    svg { height: 5%; }
    h1,h2, h3,h4 { text-align: center; }
    .techniqueSummary { font-size: 2rem; }

    "
    "</style>"
    "</head>"
    "<body>"
    "<h1>4kb Markdown Files Benchmark</h1>"
    "<h2>Time to build 4096 markdown files</h2>"    
    "<h3>Last built at $([DateTime]::UtcNow.ToString("s")) running @ $cpuSpeed Mhz</h3>"
    "<h4><a href='https://github.com/PowerShellWeb/4kbMarkdownFiles/'><button>Github Repo</button></a></h4>"
    foreach ($buildTime in $buildTimes) {
        "<details open>"
            "<summary class='techniqueSummary'>$($buildTime.Technique) ($([Math]::Round(
                $buildTime.Time.TotalSeconds, 2
            ))s)</summary>"
            "<details>"
            "<summary>Build Script</summary>"
            "<pre><code class='langauge-PowerShell'>"
            [Web.HttpUtility]::HtmlEncode($buildTime.Script)
            "</code></pre>"
            "</details>"
            "<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%'>"
                "<rect x='0%' width='1%' height='100%'>"
                    "<animate attributeName='width' from='1%' to='$([Math]::Round($buildTime.relativeSpeed * 100, 2))%' dur='$($buildTime.Time.TotalSeconds)s' fill='freeze' />"
                "</rect>"
            "</svg>"
        "</details>"
    }
    
    "<h3>The Numbers</h3>"
    $buildTimes | 
        Select-Object Technique, Time, RelativeSpeed | 
        ConvertTo-Html -Fragment
    "<details>"
        "<summary>View Source</summary>"
        "<pre><code class='language-PowerShell'>"
        [Web.HttpUtility]::HtmlEncode("$mySelf")
        "</code></pre>"
    "</details>"
    "</body>"
    "</html>"
) > ./index.html


Pop-Location