mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Alexander Lougovski <alougovs@redhat.com>
To: tycho@kernel.org
Cc: Alexander Lougovski <alougovs@redhat.com>,
	bp@alien8.de, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	pbonzini@redhat.com, thomas.lendacky@amd.com,
	vkuznets@redhat.com
Subject: Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled
Date: Tue, 28 Jul 2026 19:13:56 +0200	[thread overview]
Message-ID: <20260728171356.96405-1-alougovs@redhat.com> (raw)
In-Reply-To: <ameuTMWJUZfleIbk@tycho.pizza>

On Mon, Jul 27, 2026 at 01:23:03PM -0600, Tycho Andersen wrote:
> Can you share the code for the mmap + disk io + DB content generator?
>
> We're looking at this and would like to reproduce.

Hi Tycho,

Sure, here's everything below.

The setup is a Windows Server 2022 guest on QEMU/KVM with Driver
Verifier enabled (/standard /all, which includes Special Pool).  All
three workloads run concurrently inside the guest.

1) Memory-mapped file workload (PowerShell, runs as a scheduled task)

Two concurrent background jobs, each in an infinite loop: pick a
random system DLL, read it into a byte array, create a memory-mapped
file from it, touch pages through the view accessor, then dispose.
Every 50 iterations, GC.Collect() forces the CLR to finalize all the
disposed mappings at once, which triggers a burst of PTE teardowns in
the Windows memory manager - in theory that should put some pressure on the TLB.

--- 8< --- workload-1582.ps1 ---
$ErrorActionPreference = 'Stop'
$logFile = "C:\drivers\workload-1582-errors.log"

$files = @(
    "$env:SystemRoot\System32\ntdll.dll",
    "$env:SystemRoot\System32\kernel32.dll",
    "$env:SystemRoot\System32\user32.dll",
    "$env:SystemRoot\System32\advapi32.dll",
    "$env:SystemRoot\System32\ole32.dll",
    "$env:SystemRoot\System32\shell32.dll",
    "$env:SystemRoot\System32\comctl32.dll",
    "$env:SystemRoot\System32\msvcrt.dll"
)

$block = {
    param($files, $logFile)
    $i = 0
    while ($true) {
        $f = $files[(Get-Random -Maximum $files.Count)]
        try {
            $bytes = [System.IO.File]::ReadAllBytes($f)
            $ms = [System.IO.MemoryStream]::new($bytes)
            $mmf = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateFromFile(
                $f, [System.IO.FileMode]::Open, $null,
                0, [System.IO.MemoryMappedFiles.MemoryMappedFileAccess]::Read)
            $view = $mmf.CreateViewAccessor(0, 0,
                [System.IO.MemoryMappedFiles.MemoryMappedFileAccess]::Read)
            for ($p = 0; $p -lt [Math]::Min($view.Capacity, 65536); $p += 4096) {
                $null = $view.ReadByte($p)
            }
            $view.Dispose()
            $mmf.Dispose()
            $ms.Dispose()
        } catch {
            "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') iter=$i file=$f error=$($_.Exception.Message)" | Out-File -Append $logFile
        }
        $i++
        if ($i % 50 -eq 0) {
            try {
                [GC]::Collect()
                [GC]::WaitForPendingFinalizers()
            } catch {
                "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') iter=$i GC error=$($_.Exception.Message)" | Out-File -Append $logFile
            }
        }
    }
}

"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Workload1582 starting" | Out-File -Append $logFile

1..2 | ForEach-Object {
    Start-Job -ScriptBlock $block -ArgumentList (,$files), $logFile
}

while ($true) {
    $jobs = Get-Job
    $failed = $jobs | Where-Object { $_.State -eq 'Failed' }
    if ($failed) {
        foreach ($j in $failed) {
            "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Job $($j.Id) FAILED: $($j.ChildJobs[0].JobStateInfo.Reason)" | Out-File -Append $logFile
            Remove-Job $j -Force
            Start-Job -ScriptBlock $block -ArgumentList (,$files), $logFile
        }
    }
    Start-Sleep -Seconds 60
}
--- 8< ---

Register as a startup task:

  schtasks /create /tn Workload1582 /sc onstart /ru SYSTEM /f ^
    /tr "powershell.exe -ExecutionPolicy Bypass -File C:\workload-1582.ps1"

2) Disk I/O (DiskSpd, runs as a scheduled task)

Single-threaded, 32 outstanding I/Os, 64K block size, 50/50
read/write, 128MB file, loop forever.

--- 8< --- diskspd-loop.cmd ---
:loop
C:\drivers\diskspd.exe -d604800 -t1 -o32 -b64K -w50 -Sh -c128M C:\diskspd-io.dat
goto loop
--- 8< ---

DiskSpd binary: https://github.com/microsoft/diskspd/releases

Register:

  schtasks /create /tn DiskSpdIO /sc onstart /ru SYSTEM /f ^
    /tr "C:\drivers\diskspd-loop.cmd"

3) SQL stress (host-side script, drives queries into the guest)

SQL Server Express 2022 runs inside the guest.  The database
(StressDB, SIMPLE recovery model) has a single table with ~1.6M rows:

  RandomData (
      ID    INT IDENTITY PRIMARY KEY,
      Col1  UNIQUEIDENTIFIER,
      Col2  NVARCHAR(100),
      Col3  NVARCHAR(100),
      Col4  NVARCHAR(100),
      Col5  DATETIME2,
      Col6  FLOAT,
      Col7  BIGINT,
      Col8  VARBINARY(200)
  )

In our setup the database is baked into the golden VM image, so we
don't have a standalone creation script.  To reproduce, seed random
data and double via INSERT...SELECT until you reach ~1.6M rows.  The
exact count doesn't matter much — it just needs to be larger than the
SQL Express buffer pool (1.4 GB) so that queries cause constant cache
misses and disk I/O.

The host runs 3 sqlcmd streams per VM, 75% writes / 25% reads:

--- 8< --- sql-stress-75w.sh ---
#!/usr/bin/env bash
SQLCMD=/opt/mssql-tools18/bin/sqlcmd

query_stream() {
    local TARGET=$1
    while true; do
        case $((RANDOM % 4)) in
            0) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col2 = REPLICATE(N'X', 90 + ABS(CHECKSUM(NEWID())) % 10), Col3 = REPLICATE(N'Y', 90 + ABS(CHECKSUM(NEWID())) % 10), Col5 = SYSDATETIME(), Col7 = ABS(CHECKSUM(NEWID())) WHERE ID BETWEEN @s AND @s + 50000" ;;
            1) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col4 = REPLICATE(N'Z', 90 + ABS(CHECKSUM(NEWID())) % 10), Col6 = RAND(CHECKSUM(NEWID())) * 1000, Col8 = CAST(REPLICATE(0x42, 100 + ABS(CHECKSUM(NEWID())) % 100) AS VARBINARY(200)) WHERE ID BETWEEN @s AND @s + 50000" ;;
            2) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col2 = REPLICATE(N'W', 90 + ABS(CHECKSUM(NEWID())) % 10), Col5 = SYSDATETIME(), Col7 = ABS(CHECKSUM(NEWID())), Col8 = CAST(REPLICATE(0x43, 150) AS VARBINARY(200)) WHERE ID BETWEEN @s AND @s + 50000; CHECKPOINT" ;;
            3) Q="SET NOCOUNT ON; DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS; CHECKPOINT; SELECT TOP 5000 ID, Col2, Col3, Col4, Col8 FROM StressDB.dbo.RandomData WITH (NOLOCK) WHERE Col7 > ABS(CHECKSUM(NEWID())) % 2000000000 ORDER BY Col5 DESC" ;;
        esac
        $SQLCMD -S "$TARGET" -U sa -P 'TestPass123!' -C -Q "$Q" -t 120 > /dev/null 2>&1
    done
}

echo "Starting 3 streams per VM (42 VMs = 126 streams)..."
echo "75% writes (cases 0,1,2): UPDATE 50K rows with wide columns + CHECKPOINT on case 2"
echo "25% reads (case 3): DROPCLEANBUFFERS + CHECKPOINT + table scan"
for N in $(seq 1 42); do
    IP="192.168.100.$((10 + N))"
    query_stream "$IP,1433" &
    query_stream "$IP,1433" &
    query_stream "$IP,1433" &
done
wait
--- 8< ---

On top of all that, Windows Defender runs a full scan of all drives
every 30 minutes via a scheduled task.

Al


  parent reply	other threads:[~2026-07-28 17:14 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23  9:44 Paolo Bonzini
2026-07-24 22:36 ` Sean Christopherson
2026-07-25 13:37   ` Paolo Bonzini
2026-07-24 23:42 ` Yosry Ahmed
2026-07-24 23:50   ` Yosry Ahmed
2026-07-25 13:32   ` Paolo Bonzini
2026-07-25 21:33     ` Yosry Ahmed
2026-09-03 21:16       ` Joris de Vries
2026-07-27 19:23 ` Tycho Andersen
2026-07-27 19:58   ` Yosry Ahmed
2026-07-29 23:41     ` Paolo Bonzini
2026-07-30  0:24       ` Yosry Ahmed
2026-07-28 17:13   ` Alexander Lougovski [this message]
2026-07-28 21:34     ` Tycho Andersen
2026-07-30 11:02       ` Alexander Lougovski
2026-07-30 16:26         ` Tycho Andersen
2026-08-01 14:53           ` Alexander Lougovski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260728171356.96405-1-alougovs@redhat.com \
    --to=alougovs@redhat.com \
    --cc=bp@alien8.de \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=thomas.lendacky@amd.com \
    --cc=tycho@kernel.org \
    --cc=vkuznets@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®