Skip to content

Commit

Permalink
add skeleton ring perf microbenchmark (#769)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtfriesen authored Dec 18, 2024
1 parent bd48277 commit 2d2d3a9
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 1 deletion.
37 changes: 36 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,41 @@ jobs:
shell: PowerShell
run: tools\xskperfcompare.ps1 -DataFile1 baseref/artifacts/logs/xskperfsuite.csv -DataFile2 artifacts/logs/xskperfsuite.csv

ring_perf_tests:
name: Ring Perf Tests
needs: [build]
strategy:
fail-fast: false
matrix:
windows: [Prerelease]
configuration: [Release]
platform: [x64, arm64]
runs-on:
- self-hosted
- "1ES.Pool=xdp-ci-perf${{ matrix.platform != 'x64' && format('-{0}', matrix.platform) || '' }}-gh"
- "1ES.ImageOverride=WS${{ matrix.windows }}${{ matrix.platform != 'x64' && format('-{0}', matrix.platform) || '' }}"
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
sparse-checkout: |
tools
- name: Download Artifacts
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
with:
name: bin_${{ matrix.configuration }}_${{ matrix.platform }}
path: artifacts/bin
- name: Run ringperf
shell: PowerShell
run: tools/ringperf.ps1 -Config ${{ matrix.configuration }} -Platform ${{ matrix.platform }} -Verbose
- name: Upload Logs
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
if: ${{ always() }}
with:
name: logs_ringperf_win${{ matrix.windows }}_${{ matrix.configuration }}_${{ matrix.platform }}
path: artifacts/logs
if-no-files-found: ignore

downlevel_functional_tests:
name: Downlevel Functional Tests
needs: build
Expand Down Expand Up @@ -524,7 +559,7 @@ jobs:
Complete:
name: Complete
if: always()
needs: [build, build_allpackage, onebranch_build_validation, functional_tests, stress_tests, pktfuzz_tests, perf_tests, xskfwdkm_test, downlevel_functional_tests, create_artifacts]
needs: [build, build_allpackage, onebranch_build_validation, functional_tests, stress_tests, pktfuzz_tests, perf_tests, ring_perf_tests, xskfwdkm_test, downlevel_functional_tests, create_artifacts]
runs-on: ubuntu-latest
permissions: {} # No need for any permissions.
steps:
Expand Down
191 changes: 191 additions & 0 deletions test/ringperf/ringperf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//

//
// This ringperf microbenchmark measures the performance of AF_XDP/XSK shared
// single producer / single consumer rings.
//

#include <afxdp_helper.h>
#include <intsafe.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

CONST CHAR *UsageText = "Usage: ringperf";
#define REQUIRE(expr) \
if (!(expr)) { printf("("#expr") failed line %d\n", __LINE__); exit(1);}

typedef struct _RING_SHARED {
XSK_RING Ring;
XSK_RING CompRing;
UINT64 MaxIterations;
UINT32 ProdBatchSize;
UINT32 ConsBatchSize;
} RING_SHARED;

VOID
Usage(
CHAR *Error
)
{
fprintf(stderr, "Error: %s\n%s", Error, UsageText);
}

DWORD
WINAPI
ProdRoutine(
VOID *Context
)
{
RING_SHARED *RingShared = (RING_SHARED *)Context;
UINT64 Iterations = RingShared->MaxIterations;
static const UINT32 ProdBaseAddress = 0x12345678;

while (Iterations > 0) {
UINT32 ProdIndex;
UINT32 ProdAvailable;
UINT32 ConsIndex;
UINT32 ConsAvailable;

ProdAvailable =
XskRingProducerReserve(&RingShared->Ring, RingShared->ProdBatchSize, &ProdIndex);
for (UINT32 i = 0; i < ProdAvailable; i++) {
XSK_FRAME_DESCRIPTOR *Frame = XskRingGetElement(&RingShared->Ring, ProdIndex + i);

Frame->Buffer.Address.BaseAddress = ProdBaseAddress;
Frame->Buffer.Address.Offset = 2;
Frame->Buffer.Length = 3;
Frame->Buffer.Reserved = 0;
}
XskRingProducerSubmit(&RingShared->Ring, ProdAvailable);

ConsAvailable =
XskRingConsumerReserve(&RingShared->CompRing, RingShared->ProdBatchSize, &ConsIndex);
for (UINT32 i = 0; i < ConsAvailable; i++) {
UINT64 *Completion = XskRingGetElement(&RingShared->CompRing, ConsIndex + i);

REQUIRE(*Completion == ProdBaseAddress)
}
XskRingConsumerRelease(&RingShared->CompRing, ConsAvailable);

Iterations -= ConsAvailable;
}

return NO_ERROR;
}

DWORD
WINAPI
ConsRoutine(
VOID *Context
)
{
RING_SHARED *RingShared = (RING_SHARED *)Context;
UINT64 Iterations = RingShared->MaxIterations;
static const UINT32 ProdBaseAddress = 0x12345678;

while (Iterations > 0) {
UINT32 ConsIndex;
UINT32 ProdIndex;
UINT32 Available;

Available =
XskRingConsumerReserve(&RingShared->Ring, RingShared->ConsBatchSize, &ConsIndex);
Available =
XskRingProducerReserve(&RingShared->CompRing, Available, &ProdIndex);

for (UINT32 i = 0; i < Available; i++) {
XSK_FRAME_DESCRIPTOR *Frame = XskRingGetElement(&RingShared->Ring, ConsIndex + i);
UINT64 *Completion = XskRingGetElement(&RingShared->CompRing, ProdIndex + i);

*Completion = Frame->Buffer.Address.BaseAddress;
}

XskRingConsumerRelease(&RingShared->Ring, Available);
XskRingProducerSubmit(&RingShared->CompRing, Available);

Iterations -= Available;
}

return NO_ERROR;
}

#pragma warning(push)
#pragma warning(disable:4324) // structure was padded due to alignment specifier

//
// This is based on the shared rings layout provided by xsk.c.
//
typedef struct _RINGPERF_SHARED_RING {
DECLSPEC_CACHEALIGN UINT32 ProducerIndex;
DECLSPEC_CACHEALIGN UINT32 ConsumerIndex;
DECLSPEC_CACHEALIGN UINT32 Flags;
//
// Followed by power-of-two array of ring elements, starting on 8-byte alignment.
// XSK_FRAME_DESCRIPTOR[] for rx/tx, UINT64[] for fill/completion
//
} RINGPERF_SHARED_RING;

#pragma warning(pop)

static
VOID
AllocateRing(
_Out_ XSK_RING *Ring,
_In_ UINT32 ElementSize,
_In_ UINT32 ElementCount
)
{
XSK_RING_INFO RingInfo = {0};
SIZE_T RingAllocSize;

REQUIRE(SUCCEEDED(SizeTMult(ElementSize, ElementCount, &RingAllocSize)));
REQUIRE(SUCCEEDED(SizeTAdd(RingAllocSize, sizeof(RINGPERF_SHARED_RING), &RingAllocSize)));

RingInfo.Ring = _aligned_malloc(RingAllocSize, SYSTEM_CACHE_ALIGNMENT_SIZE);
RingInfo.Size = ElementCount;
RingInfo.DescriptorsOffset = sizeof(RINGPERF_SHARED_RING);
RingInfo.ConsumerIndexOffset = FIELD_OFFSET(RINGPERF_SHARED_RING, ConsumerIndex);
RingInfo.ProducerIndexOffset = FIELD_OFFSET(RINGPERF_SHARED_RING, ProducerIndex);
RingInfo.FlagsOffset = FIELD_OFFSET(RINGPERF_SHARED_RING, Flags);
RingInfo.ElementStride = ElementSize;

XskRingInitialize(Ring, &RingInfo);
}

INT
__cdecl
main(
INT ArgC,
CHAR **ArgV
)
{
INT Err = 0;
RING_SHARED RingShared = {0};
HANDLE ProdThread, ConsThread;
UINT32 ElementCount = 0x1000;

UNREFERENCED_PARAMETER(ArgC);
UNREFERENCED_PARAMETER(ArgV);

RingShared.MaxIterations = 0x100000000ui64;
RingShared.ProdBatchSize = 32;
RingShared.ConsBatchSize = 32;

AllocateRing(&RingShared.Ring, sizeof(XSK_FRAME_DESCRIPTOR), ElementCount);
AllocateRing(&RingShared.CompRing, sizeof(UINT64), ElementCount);

ProdThread = CreateThread(NULL, 0, ProdRoutine, &RingShared, 0, NULL);
REQUIRE(ProdThread != NULL);

ConsThread = CreateThread(NULL, 0, ConsRoutine, &RingShared, 0, NULL);
REQUIRE(ConsThread != NULL);

WaitForSingleObject(ConsThread, INFINITE);
WaitForSingleObject(ProdThread, INFINITE);

return Err;
}
22 changes: 22 additions & 0 deletions test/ringperf/ringperf.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="ringperf.c" />
</ItemGroup>
<PropertyGroup>
<ProjectGuid>{838975ce-9bc8-4ba8-a129-2c33791ba339}</ProjectGuid>
<TargetName>ringperf</TargetName>
<UndockedType>exe</UndockedType>
<ImportWnt>true</ImportWnt>
</PropertyGroup>
<Import Project="$(SolutionDir)src\xdp.cpp.props" />
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>
onecore.lib;
%(AdditionalDependencies)
</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(SolutionDir)src\xdp.targets" />
</Project>
23 changes: 23 additions & 0 deletions tools/ringperf.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
param (
[Parameter(Mandatory = $false)]
[ValidateSet("Debug", "Release")]
[string]$Config = "Debug",

[Parameter(Mandatory = $false)]
[ValidateSet("x64", "arm64")]
[string]$Platform = "x64"
)

Set-StrictMode -Version 'Latest'
$ErrorActionPreference = 'Stop'

# Important paths.
$RootDir = Split-Path $PSScriptRoot -Parent
. $RootDir\tools\common.ps1
$ArtifactsDir = Get-ArtifactBinPath -Config $Config -Platform $Platform

$Time = Measure-Command {
& $ArtifactsDir\test\ringperf.exe
}

Write-Output "ringperf.exe took $($Time.TotalSeconds) seconds to run."
10 changes: 10 additions & 0 deletions xdp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xdpruntime", "src\xdpruntim
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xskfwdkm", "samples\xskfwd\xskfwdkm.vcxproj", "{F722DA97-3252-42F1-92D3-215C99935607}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ringperf", "test\ringperf\ringperf.vcxproj", "{838975CE-9BC8-4BA8-A129-2C33791BA339}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Expand Down Expand Up @@ -395,6 +397,14 @@ Global
{F722DA97-3252-42F1-92D3-215C99935607}.Release|ARM64.Build.0 = Release|ARM64
{F722DA97-3252-42F1-92D3-215C99935607}.Release|x64.ActiveCfg = Release|x64
{F722DA97-3252-42F1-92D3-215C99935607}.Release|x64.Build.0 = Release|x64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Debug|ARM64.ActiveCfg = Debug|ARM64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Debug|ARM64.Build.0 = Debug|ARM64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Debug|x64.ActiveCfg = Debug|x64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Debug|x64.Build.0 = Debug|x64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Release|ARM64.ActiveCfg = Release|ARM64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Release|ARM64.Build.0 = Release|ARM64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Release|x64.ActiveCfg = Release|x64
{838975CE-9BC8-4BA8-A129-2C33791BA339}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit 2d2d3a9

Please sign in to comment.