/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General * Public License along with this program. If not, see * . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * main.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * Test Program for running performance tests against lsassd and winbind * * Authors: Kyle Stemen * */ #include "types.h" #if HAVE_STDIO_H #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_GETTIMEOFDAY #include #endif #if HAVE_DLFCN_H #include #endif #include #include "tests.h" #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #endif #ifndef HAVE_CLOCK_GETTIME /* replacement implementation for systems that lack clock_gettime support (e.g. Mac OS X) */ typedef int clockid_t; int clock_gettime(clockid_t clk_id, struct timespec *tp) { int ret; struct timeval tv; if (tp == NULL) { return EFAULT; } if (clk_id != CLOCK_REALTIME) { return EINVAL; } ret = gettimeofday(&tv, NULL); if (ret) { return ret; } tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * 1000; return 0; } #endif /* HAVE_CLOCK_GETTIME */ int64_t GetTimeDiff( const struct timespec *end, const struct timespec *start ) { int64_t endNanoSecs = (int64_t)end->tv_sec * 1000000000 + end->tv_nsec; int64_t startNanoSecs = (int64_t)start->tv_sec * 1000000000 + start->tv_nsec; return endNanoSecs - startNanoSecs; } void RunTests( PerfTest* tests, size_t testCount ) { size_t testIndex; BOOL passed; PVOID runArg; struct timespec startTime = {0}; struct timespec endTime = {0}; int result; int runNum; for (testIndex = 0; testIndex < testCount; testIndex++) { printf("Running: %s\n", tests[testIndex].description); runArg = NULL; if (tests[testIndex].setup != NULL) { passed = tests[testIndex].setup( tests[testIndex].setupArg, &runArg); if (!passed) { printf("Failed\n"); continue; } } if (tests[testIndex].run == NULL) { printf("Error: test function is null\n"); continue; } result = clock_gettime(CLOCK_REALTIME, &startTime); if (result < 0) { perror("clock_gettime"); return; } switch (tests[testIndex].type) { case TEST_TYPE_RUNS_PER_SEC: runNum = 0; do { do { passed = tests[testIndex].run( runArg); runNum++; } while (passed && runNum % 10 != 0); result = clock_gettime(CLOCK_REALTIME, &endTime); if (result < 0) { perror("clock_gettime"); return; } } while (passed && GetTimeDiff(&endTime, &startTime) < 10 * (int64_t)1000000000); if (passed) { printf("Result: %f calls per second\n", runNum / (GetTimeDiff(&endTime, &startTime) / 1000000000.0)); } else { printf("Failed\n"); } break; case TEST_TYPE_SINGLE_RUN: passed = tests[testIndex].run( runArg); result = clock_gettime(CLOCK_REALTIME, &endTime); if (result < 0) { perror("clock_gettime"); return; } if (passed) { printf("Result: %f seconds\n", (GetTimeDiff(&endTime, &startTime) / 1000000000.0)); } else { printf("Failed\n"); } break; default: printf("Unknown test type %d\n", tests[testIndex].type); return; } if (tests[testIndex].cleanup != NULL) { tests[testIndex].cleanup(runArg); } } } void RunLsassTests( void *lsassTestLib, const char *user0001 ) { PerfTest testList[] = { { "Lsass server connect and disconnects per second", TEST_TYPE_RUNS_PER_SEC, NULL, dlsym(lsassTestLib, "RunConnectDisconnect"), NULL, NULL }, { "Cached LsaFindUserById's per second for user0001 with shared connection", TEST_TYPE_RUNS_PER_SEC, dlsym(lsassTestLib, "SetupFindUserById"), dlsym(lsassTestLib, "RunFindUserById"), dlsym(lsassTestLib, "CleanupFindUserById"), (PVOID)user0001 }, { "LsaGetLogInfo's per second with shared connection (tests marshalling latency)", TEST_TYPE_RUNS_PER_SEC, dlsym(lsassTestLib, "SetupConnectLsass"), dlsym(lsassTestLib, "RunGetLogLevel"), dlsym(lsassTestLib, "CleanupConnectLsass"), (PVOID)user0001 }, }; RunTests( testList, sizeof(testList)/sizeof(testList[0])); } int main(int argc, const char *argv[]) { char user0001[256]; char groupsize1[256]; char groupsize1000[256]; char user[256]; char usergroup[256]; void *libperflsass = NULL; PerfTest testList[] = { { "Cached getpwuid's per second for user0001", TEST_TYPE_RUNS_PER_SEC, SetupGrabUid, RunGrabUid, NULL, user0001, }, { "Cached getgrgid's per second for groupsize1", TEST_TYPE_RUNS_PER_SEC, SetupGrabGid, RunGrabGid, NULL, groupsize1 }, { "Cached getgrgid's per second for groupsize1000", TEST_TYPE_RUNS_PER_SEC, SetupGrabGid, RunGrabGid, NULL, groupsize1000 }, { "Uncached 500 user lookup for user0001-user0500", TEST_TYPE_SINGLE_RUN, SetupClearCache, RunGrabUsers1_500, NULL, user }, { "Uncached 500 group lookup for usergroup0001-usergroup0500", TEST_TYPE_SINGLE_RUN, SetupClearCache, RunGrabGroups1_500, NULL, usergroup }, }; if (argc != 2 || argv[1][0] == '-') { printf("Usage: %s \n" "\n" "This program runs a series of nsswitch performance tests against winbind or \n" "lsassd.\n" "\n" "The following users should be available from the domain:\n" "\\user0001 through \\user0500\n" "\n" "The following groups should be available from the domain:\n" "\\groupsize1\n" "\\groupsize1000\n" "\\usergroup0001 through \\usergroup0500\n", argv[0]); exit(1); } snprintf(user0001, sizeof(user0001), "%s\\user0001", argv[1]); snprintf(groupsize1, sizeof(groupsize1), "%s\\groupsize1", argv[1]); snprintf(groupsize1000, sizeof(groupsize1000), "%s\\groupsize1000", argv[1]); snprintf(user, sizeof(user), "%s\\user", argv[1]); snprintf(usergroup, sizeof(groupsize1), "%s\\usergroup", argv[1]); RunTests( testList, sizeof(testList)/sizeof(testList[0])); libperflsass = dlopen("./libperflsass.so", RTLD_NOW | RTLD_LOCAL); if (libperflsass != NULL) { printf("Running lsass specific tests:\n"); RunLsassTests(libperflsass, user0001); dlclose(libperflsass); } else { printf("Unable to load libperflsass.so, so skipping lsass specific tests\n"); } return 0; }