/* 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;
}