From bda0477a79f91a0baa6babe21e7b9389b2aafa00 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 19 Apr 2022 10:21:31 +0100 Subject: [PATCH] tst: fsbench: --empty-cache option --- ext/tlib/testsuite.c | 30 ++++++++++++++-- ext/tlib/testsuite.h | 17 +++++++++ tools/run-perf-tests.bat | 8 ++--- tst/fsbench/fsbench.c | 76 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 124 insertions(+), 7 deletions(-) diff --git a/ext/tlib/testsuite.c b/ext/tlib/testsuite.c index ad5d1c73..586bb5a5 100644 --- a/ext/tlib/testsuite.c +++ b/ext/tlib/testsuite.c @@ -48,25 +48,51 @@ void tlib_add_test_opt(const char *name, void (*fn)(void)) add_test_to_list(name, fn, 1, &test_tail); } +struct hook +{ + void (*fn)(const char *name, void (*fn)(void), int v); + struct hook *next; +}; +static struct hook hook_sentinel = { .next = &hook_sentinel }; +static struct hook *hook_tail = &hook_sentinel; +static void add_hook_to_list(void (*fn)(void), struct hook **tail) +{ + struct hook *hook = calloc(1, sizeof *hook); + hook->fn = fn; + hook->next = (*tail)->next; + (*tail)->next = hook; + (*tail) = hook; +} +void tlib_add_hook(void (*fn)(const char *name, void (*fn)(void), int v)) +{ + add_hook_to_list(fn, &hook_tail); +} + static FILE *tlib_out, *tlib_err; static jmp_buf test_jmp_buf, *test_jmp; static char assert_buf[256]; static void test_printf(const char *fmt, ...); static double run_test(struct test *test) { + double res; + for (struct hook *hook = hook_tail->next->next; 0 != hook->fn; hook = hook->next) + hook->fn(test->name, test->fn, +1); #if defined(_WIN64) || defined(_WIN32) #pragma comment(lib, "winmm.lib") unsigned long __stdcall timeGetTime(void); unsigned long t0 = timeGetTime(); test->fn(); unsigned long t1 = timeGetTime(); - return (t1 - t0) / 1000.0; + res = (t1 - t0) / 1000.0; #else time_t t0 = time(0); test->fn(); time_t t1 = time(0); - return difftime(t1, t0); + res = difftime(t1, t0); #endif + for (struct hook *hook = hook_tail->next->next; 0 != hook->fn; hook = hook->next) + hook->fn(test->name, test->fn, -1); + return res; } static void do_test_default(struct test *test, int testno) { diff --git a/ext/tlib/testsuite.h b/ext/tlib/testsuite.h index a0c60654..84150ce4 100644 --- a/ext/tlib/testsuite.h +++ b/ext/tlib/testsuite.h @@ -65,6 +65,23 @@ void tlib_add_test_suite(const char *name, void (*fn)(void)); void tlib_add_test(const char *name, void (*fn)(void)); void tlib_add_test_opt(const char *name, void (*fn)(void)); +/** + * Register a test hook to be run before and after every test. + * + * Test hooks are functions with prototype + * void testhook(const char *name, void (*fn)(void), int v). + * The parameter v specifies that a test is about to be executed (v is +1) + * or it was just executed (v is -1). + */ +#define TESTHOOK(fn)\ + do\ + {\ + void fn(const char *name, void (*fn)(void), int v);\ + tlib_add_hook(fn);\ + } while (0) + +void tlib_add_hook(void (*fn)(const char *name, void (*fn)(void), int v)); + /** * Printf function. * diff --git a/tools/run-perf-tests.bat b/tools/run-perf-tests.bat index fc7ca2e7..0c3409b0 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% --files=%%a file_*" + call :csv %%a "%fsbench% --empty-cache --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% --rdwr-cc=%%a rdwr_cc_*" + call :csv %%a "%fsbench% --empty-cache --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% --rdwr-nc=%%a rdwr_nc_*" + call :csv %%a "%fsbench% --empty-cache --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% --mmap=%%a mmap_*" + call :csv %%a "%fsbench% --empty-cache --mmap=%%a mmap_*" ) popd diff --git a/tst/fsbench/fsbench.c b/tst/fsbench/fsbench.c index 229b80d7..1ac04b12 100644 --- a/tst/fsbench/fsbench.c +++ b/tst/fsbench/fsbench.c @@ -23,6 +23,7 @@ #include #include +static BOOLEAN OptEmptyCache = FALSE; static ULONG OptFileCount = 1000; static ULONG OptListCount = 100; static ULONG OptRdwrFileSize = 4096 * 1024; @@ -398,6 +399,64 @@ static void mmap_tests(void) TEST(mmap_read_test); } +static void EmptyCache(const char *name, void (*fn)(void), int v) +{ + NTSYSCALLAPI NTSTATUS NTAPI + NtSetSystemInformation( + ULONG SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength); + + if (+1 == v) /* setup */ + { + /* flush the file system cache (requires SE_INCREASE_QUOTA_NAME) */ + ASSERT(SetSystemFileCacheSize((SIZE_T)-1, (SIZE_T)-1, 0)); + + /* flush/purge the standby list (requires SE_PROF_SINGLE_PROCESS_NAME) */ + ULONG Command; + Command = 3 /*MemoryFlushModifiedList*/; + ASSERT(0 == NtSetSystemInformation(80 /*SystemMemoryListInformation*/, &Command, sizeof Command)); + Command = 4 /*MemoryPurgeStandbyList*/; + ASSERT(0 == NtSetSystemInformation(80 /*SystemMemoryListInformation*/, &Command, sizeof Command)); + } + else + if (-1 == v) /* teardown */ + { + } +} +static DWORD EnablePrivilegesForEmptyCache(VOID) +{ + union + { + TOKEN_PRIVILEGES P; + UINT8 B[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)]; + } Privileges; + HANDLE Token; + + Privileges.P.PrivilegeCount = 2; + Privileges.P.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + Privileges.P.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; + + if (!LookupPrivilegeValueW(0, SE_PROF_SINGLE_PROCESS_NAME, &Privileges.P.Privileges[0].Luid) || + !LookupPrivilegeValueW(0, SE_INCREASE_QUOTA_NAME, &Privileges.P.Privileges[1].Luid)) + return GetLastError(); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token)) + return GetLastError(); + + if (!AdjustTokenPrivileges(Token, FALSE, &Privileges.P, 0, 0, 0) || + ERROR_NOT_ALL_ASSIGNED == GetLastError()) + { + CloseHandle(Token); + + return GetLastError(); + } + + CloseHandle(Token); + + return ERROR_SUCCESS; +} + #define rmarg(argv, argc, argi) \ argc--, \ memmove(argv + argi, argv + argi + 1, (argc - argi) * sizeof(char *)),\ @@ -414,7 +473,12 @@ int main(int argc, char *argv[]) const char *a = argv[argi]; if ('-' == a[0]) { - if (0 == strncmp("--files=", a, sizeof "--files=" - 1)) + if (0 == strcmp("--empty-cache", a)) + { + OptEmptyCache = TRUE; + rmarg(argv, argc, argi); + } + else if (0 == strncmp("--files=", a, sizeof "--files=" - 1)) { OptFileCount = strtoul(a + sizeof "--files=" - 1, 0, 10); rmarg(argv, argc, argi); @@ -442,6 +506,16 @@ int main(int argc, char *argv[]) } } + if (OptEmptyCache) + { + if (0 != EnablePrivilegesForEmptyCache()) + { + tlib_printf("ABORT: cannot enable privileges required for empty cache\n"); + abort(); + } + TESTHOOK(EmptyCache); + } + tlib_run_tests(argc, argv); return 0; }