From 5b872e8cf9f5b6800512005abb310596dc9ea771 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Aug 2019 10:18:42 +0000 Subject: [PATCH] Use performance counter for less spinning Previously we had to spin for a minimum of 15ms because the tick interval is 156250 on NT. On linux, usually trips to the high performance timers are discouraged because if they don't hit the RDTSC path (due to being unstable or the like), they hit more expensive hardware. I assume that's probably the same on NT, but all of tcpip.sys and ndis.sys uses the performance counters too, so what are we going to do? Signed-off-by: Jason A. Donenfeld --- wintun.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wintun.c b/wintun.c index 9486457..1bc0769 100644 --- a/wintun.c +++ b/wintun.c @@ -406,7 +406,9 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) TUN_RING *Ring = Ctx->Device.Receive.Ring; ULONG RingCapacity = Ctx->Device.Receive.Capacity; - const ULONG SpinMax = 10000 * 20 / KeQueryTimeIncrement(); /* 20 ms */ + LARGE_INTEGER Frequency; + KeQueryPerformanceCounter(&Frequency); + ULONG64 SpinMax = Frequency.QuadPart / 1000 / 10; /* 1/10 ms */ VOID *Events[] = { &Ctx->Device.Disconnected, Ctx->Device.Receive.TailMoved }; ASSERT(RTL_NUMBER_OF(Events) <= THREAD_WAIT_OBJECTS); @@ -420,8 +422,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) ULONG RingTail = InterlockedGetU(&Ring->Tail); if (RingHead == RingTail) { - LARGE_INTEGER SpinStart; - KeQueryTickCount(&SpinStart); + LARGE_INTEGER SpinStart = KeQueryPerformanceCounter(NULL); for (;;) { RingTail = InterlockedGetU(&Ring->Tail); @@ -429,8 +430,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx) break; if (KeReadStateEvent(&Ctx->Device.Disconnected)) break; - LARGE_INTEGER SpinNow; - KeQueryTickCount(&SpinNow); + LARGE_INTEGER SpinNow = KeQueryPerformanceCounter(NULL); if ((ULONG64)SpinNow.QuadPart - (ULONG64)SpinStart.QuadPart >= SpinMax) break; ZwYieldExecution();