diff --git a/src/sys/driver.h b/src/sys/driver.h index f8cfd27d..905dd6f5 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -566,7 +566,7 @@ BOOLEAN FspFileNameIsPrefix( #else #define FspFileNameUpcase(D,S,U) (ASSERT(0 == (U)), RtlUpcaseUnicodeString(D,S,FALSE)) #define FspEaNameUpcase(D,S,U) (ASSERT(0 == (U)), RtlUpperString(D,S)) -#define FspFileNameCompare(N1,N2,I,U) (ASSERT(0 == (U)), RtlCompareUnicodeString(N1,N2,I)) +#define FspFileNameCompare(N1,N2,I,U) (ASSERT(0 == (U)), FspCompareUnicodeString(N1,N2,I)) #define FspFileNameIsPrefix(N1,N2,I,U) (ASSERT(0 == (U)), RtlPrefixUnicodeString(N1,N2,I)) #endif NTSTATUS FspFileNameInExpression( @@ -733,6 +733,12 @@ VOID FspIrpHookReset(PIRP Irp); PVOID FspIrpHookContext(PVOID Context); NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); +/* utility: string compare */ +LONG FspCompareUnicodeString( + PCUNICODE_STRING String1, + PCUNICODE_STRING String2, + BOOLEAN CaseInsensitive); + /* silos */ typedef struct { diff --git a/src/sys/util.c b/src/sys/util.c index 96f63363..fda82b68 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -131,6 +131,10 @@ NTSTATUS FspIrpHook(PIRP Irp, PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID Ow VOID FspIrpHookReset(PIRP Irp); PVOID FspIrpHookContext(PVOID Context); NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); +LONG FspCompareUnicodeString( + PCUNICODE_STRING String1, + PCUNICODE_STRING String2, + BOOLEAN CaseInsensitive); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspIsNtDdiVersionAvailable) @@ -174,6 +178,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); #pragma alloc_text(PAGE, FspSafeMdlDelete) #pragma alloc_text(PAGE, FspIrpHook) #pragma alloc_text(PAGE, FspIrpHookReset) +#pragma alloc_text(PAGE, FspCompareUnicodeString) #endif static const LONG Delays[] = @@ -1493,3 +1498,82 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) return Result; } + +static inline +USHORT FspUpcaseAscii(USHORT c) +{ + /* + * Bit-twiddling upper case char: + * + * - Let signbit(x) = x & 0x100 (treat bit 0x100 as "signbit"). + * - 'A' <= c && c <= 'Z' <=> s = signbit(c - 'A') ^ signbit(c - ('Z' + 1)) == 1 + * - c >= 'A' <=> c - 'A' >= 0 <=> signbit(c - 'A') = 0 + * - c <= 'Z' <=> c - ('Z' + 1) < 0 <=> signbit(c - ('Z' + 1)) = 1 + * - Bit 0x20 = 0x100 >> 3 toggles uppercase to lowercase and vice-versa. + * + * This is actually faster than `(c - 'a' <= 'z' - 'a') ? (c & ~0x20) : c`, even + * when compiled using cmov conditional moves at least on this system (i7-1065G7). + * + * See https://godbolt.org/z/ebv131Wrh + */ + USHORT s = ((c - 'a') ^ (c - ('z' + 1))) & 0x100; + return c & ~(s >> 3); +} + +#if DBG +static +LONG FspCompareUnicodeStringReal( + PCUNICODE_STRING S1, + PCUNICODE_STRING S2, + BOOLEAN CaseInsensitive) +#else +LONG FspCompareUnicodeString( + PCUNICODE_STRING S1, + PCUNICODE_STRING S2, + BOOLEAN CaseInsensitive) +#endif +{ + PAGED_CODE(); + + LONG LResult = S1->Length - S2->Length; + PWCH P1 = S1->Buffer; + PWCH P2 = S2->Buffer; + PWCH EndP1 = P1 + (0 >= LResult ? S1->Length : S2->Length) / sizeof(WCHAR); + + if (CaseInsensitive) + { + for (; EndP1 != P1; ++P1, ++P2) + { + USHORT C1 = *P1, C2 = *P2; + if (0xff80 & (C1 | C2)) + return RtlCompareUnicodeString(S1, S2, TRUE); + C1 = FspUpcaseAscii(C1); + C2 = FspUpcaseAscii(C2); + if (C1 != C2) + return C1 - C2; + } + } + else + { + for (; EndP1 != P1; ++P1, ++P2) + { + USHORT C1 = *P1, C2 = *P2; + if (C1 != C2) + return C1 - C2; + } + } + + return LResult; +} +#if DBG +LONG FspCompareUnicodeString( + PCUNICODE_STRING S1, + PCUNICODE_STRING S2, + BOOLEAN CaseInsensitive) +{ + LONG Result0 = FspCompareUnicodeStringReal(S1, S2, CaseInsensitive); + LONG Result1 = RtlCompareUnicodeString(S1, S2, CaseInsensitive); + ASSERT((0 < Result0) - (0 > Result0) == (0 < Result1) - (0 > Result1)); + return Result0; +} +#endif diff --git a/tools/run-perf-tests.bat b/tools/run-perf-tests.bat index 0c3409b0..13e5e506 100755 --- a/tools/run-perf-tests.bat +++ b/tools/run-perf-tests.bat @@ -30,25 +30,25 @@ pushd fsbench set OptFiles=1000 2000 3000 4000 5000 if X%2==Xbaseline set OptFiles=10000 for %%a in (%OptFiles%) do ( - call :csv %%a "%fsbench% --empty-cache --files=%%a file_*" + call :csv %%a "%fsbench% --empty-cache=C --files=%%a file_*" ) set OptRdwrCc=100 200 300 400 500 if X%2==Xbaseline set OptRdwrCc=1000 for %%a in (%OptRdwrCc%) do ( - call :csv %%a "%fsbench% --empty-cache --rdwr-cc=%%a rdwr_cc_*" + call :csv %%a "%fsbench% --empty-cache=C --rdwr-cc=%%a rdwr_cc_*" ) set OptRdwrNc=100 200 300 400 500 if X%2==Xbaseline set OptRdwrNc=100 for %%a in (%OptRdwrNc%) do ( - call :csv %%a "%fsbench% --empty-cache --rdwr-nc=%%a rdwr_nc_*" + call :csv %%a "%fsbench% --empty-cache=C --rdwr-nc=%%a rdwr_nc_*" ) set OptMmap=100 200 300 400 500 if X%2==Xbaseline set OptMmap=1000 for %%a in (%OptMmap%) do ( - call :csv %%a "%fsbench% --empty-cache --mmap=%%a mmap_*" + call :csv %%a "%fsbench% --empty-cache=C --mmap=%%a mmap_*" ) popd