From: Ken Raeburn Date: Mon, 28 Dec 2009 00:21:16 +0000 (+0000) Subject: Performance testing programs for krb5_init_context and profile data fetch X-Git-Tag: krb5-1.8-alpha1~58 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=780b10fb74f2c2acf8bc86bf8d503a8adaf2a07f;p=krb5.git Performance testing programs for krb5_init_context and profile data fetch git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23523 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/tests/threads/Makefile.in b/src/tests/threads/Makefile.in index 1b291e1fe..139972a2e 100644 --- a/src/tests/threads/Makefile.in +++ b/src/tests/threads/Makefile.in @@ -7,6 +7,8 @@ RUN_SETUP = @KRB5_RUN_ENV@ SRCS=$(srcdir)/t_rcache.c \ $(srcdir)/gss-perf.c \ + $(srcdir)/init_ctx.c \ + $(srcdir)/profread.c \ $(srcdir)/prof1.c all:: @@ -23,9 +25,15 @@ prof1: prof1.o $(KRB5_BASE_DEPLIBS) prof1.o: prof1.c -gss-perf: gss-perf.o +gss-perf: gss-perf.o $(KRB5_BASE_DEPLIBS) $(GSS_DEPLIBS) $(CC_LINK) $(PTHREAD_CFLAGS) -o gss-perf gss-perf.o $(GSS_LIBS) $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS) +init_ctx: init_ctx.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) $(PTHREAD_CFLAGS) -o init_ctx init_ctx.o $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS) + +profread: profread.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) $(PTHREAD_CFLAGS) -o profread profread.o $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS) + check-unix:: run-t_rcache install:: diff --git a/src/tests/threads/init_ctx.c b/src/tests/threads/init_ctx.c new file mode 100644 index 000000000..208104deb --- /dev/null +++ b/src/tests/threads/init_ctx.c @@ -0,0 +1,278 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * test/threads/init_ctx.c + * + * Copyright (C) 2009 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * krb5 context creation performance testing + * initially contributed by Ken Raeburn + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* for SIZE_MAX: */ +#include "k5-platform.h" + +#include +#include + +#define N_THREADS 4 +#define ITER_COUNT 40000 +static int init_krb5_first = 0; + +struct resource_info { + struct timeval start_time, end_time; +}; +struct thread_info { + pthread_t tid; + struct resource_info r; +}; + +static char *prog; +static unsigned int n_threads = N_THREADS; +static int iter_count = ITER_COUNT; +static int do_pause; + +static void usage (void) __attribute__((noreturn)); + +static void +usage () +{ + fprintf (stderr, "usage: %s [ options ]\n", prog); + fprintf (stderr, "options:\n"); + fprintf (stderr, "\t-t N\tspecify number of threads (default %d)\n", + N_THREADS); + fprintf (stderr, "\t-i N\tset iteration count (default %d)\n", + ITER_COUNT); + fprintf (stderr, "\t-K\tinitialize a krb5_context for the duration\n"); + fprintf (stderr, "\t-P\tpause briefly after starting, to allow attaching dtrace/strace/etc\n"); + exit (1); +} + +static int +numarg (char *arg) +{ + char *end; + long val; + + val = strtol (arg, &end, 10); + if (*arg == 0 || *end != 0) { + fprintf (stderr, "invalid numeric argument '%s'\n", arg); + usage (); + } + if (val >= 1 && val <= INT_MAX) + return val; + fprintf (stderr, "out of range numeric value %ld (1..%d)\n", + val, INT_MAX); + usage (); +} + +static char optstring[] = "t:i:KP"; + +static void +process_options (int argc, char *argv[]) +{ + int c; + + prog = strrchr (argv[0], '/'); + if (prog) + prog++; + else + prog = argv[0]; + while ((c = getopt (argc, argv, optstring)) != -1) { + switch (c) { + case '?': + case ':': + usage (); + break; + + case 't': + n_threads = numarg (optarg); + if (n_threads >= SIZE_MAX / sizeof (struct thread_info)) { + n_threads = SIZE_MAX / sizeof (struct thread_info); + fprintf (stderr, "limiting n_threads to %u\n", n_threads); + } + break; + + case 'i': + iter_count = numarg (optarg); + break; + + case 'K': + init_krb5_first = 1; + break; + + case 'P': + do_pause = 1; + break; + } + } + if (argc != optind) + usage (); +} + +static long double +tvsub (struct timeval t1, struct timeval t2) +{ + /* POSIX says .tv_usec is signed. */ + return (t1.tv_sec - t2.tv_sec + + (long double) 1.0e-6 * (t1.tv_usec - t2.tv_usec)); +} + +static struct timeval +now (void) +{ + struct timeval tv; + if (gettimeofday (&tv, NULL) < 0) { + perror ("gettimeofday"); + exit (1); + } + return tv; +} + +static void run_iterations (struct resource_info *r) +{ + int i; + krb5_error_code err; + krb5_context ctx; + + r->start_time = now (); + for (i = 0; i < iter_count; i++) { + err = krb5_init_context(&ctx); + if (err) { + com_err(prog, err, "initializing krb5 context"); + exit(1); + } + krb5_free_context(ctx); + } + r->end_time = now (); +} + +static void * +thread_proc (void *p) +{ + run_iterations (p); + return 0; +} + +static struct thread_info *tinfo; + +static krb5_context kctx; +static struct rusage start, finish; +static struct timeval start_time, finish_time; + +int +main (int argc, char *argv[]) +{ + long double user, sys, wallclock, total; + unsigned int i; + + process_options (argc, argv); + + /* + * Some places in the krb5 library cache data globally. + * This option allows you to test the effect of that. + */ + if (init_krb5_first && krb5_init_context (&kctx) != 0) { + fprintf (stderr, "krb5_init_context error\n"); + exit (1); + } + tinfo = calloc (n_threads, sizeof (*tinfo)); + if (tinfo == NULL) { + perror ("calloc"); + exit (1); + } + printf ("Threads: %d iterations: %d\n", n_threads, iter_count); + if (do_pause) { + printf ("pid %lu napping...\n", (unsigned long) getpid ()); + sleep (10); + } + printf ("starting...\n"); + /* And *now* we start measuring the performance. */ + if (getrusage (RUSAGE_SELF, &start) < 0) { + perror ("getrusage"); + exit (1); + } + start_time = now (); +#define foreach_thread(IDXVAR) for (IDXVAR = 0; IDXVAR < n_threads; IDXVAR++) + foreach_thread (i) { + int err; + + err = pthread_create (&tinfo[i].tid, NULL, thread_proc, &tinfo[i].r); + if (err) { + fprintf (stderr, "pthread_create: %s\n", strerror (err)); + exit (1); + } + } + foreach_thread (i) { + int err; + void *val; + + err = pthread_join (tinfo[i].tid, &val); + if (err) { + fprintf (stderr, "pthread_join: %s\n", strerror (err)); + exit (1); + } + } + finish_time = now (); + if (getrusage (RUSAGE_SELF, &finish) < 0) { + perror ("getrusage"); + exit (1); + } + if (init_krb5_first) + krb5_free_context (kctx); + foreach_thread (i) { + printf ("Thread %2d: elapsed time %Lfs\n", i, + tvsub (tinfo[i].r.end_time, tinfo[i].r.start_time)); + } + wallclock = tvsub (finish_time, start_time); + /* + * Report on elapsed time and CPU usage. Depending what + * performance issue you're chasing down, different values may be + * of particular interest, so report all the info we've got. + */ + printf ("Overall run time with %d threads = %Lfs, %Lfms per iteration.\n", + n_threads, wallclock, 1000 * wallclock / iter_count); + user = tvsub (finish.ru_utime, start.ru_utime); + sys = tvsub (finish.ru_stime, start.ru_stime); + total = user + sys; + printf ("CPU usage: user=%Lfs sys=%Lfs total=%Lfs.\n", user, sys, total); + printf ("Utilization: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n", + 100 * user / wallclock, + 100 * sys / wallclock, + 100 * total / wallclock); + printf ("Util/thread: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n", + 100 * user / wallclock / n_threads, + 100 * sys / wallclock / n_threads, + 100 * total / wallclock / n_threads); + printf ("Total CPU use per iteration per thread: %Lfms\n", + 1000 * total / n_threads / iter_count); + return 0; +} diff --git a/src/tests/threads/profread.c b/src/tests/threads/profread.c new file mode 100644 index 000000000..ccc86a884 --- /dev/null +++ b/src/tests/threads/profread.c @@ -0,0 +1,293 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * test/threads/profread.c + * + * Copyright (C) 2009 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * krb5 profile data retrieval performance testing + * initially contributed by Ken Raeburn + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* for SIZE_MAX: */ +#include "k5-platform.h" + +#include +#include + +#define N_THREADS 4 +#define ITER_COUNT 40000 +static int init_krb5_first = 0; + +struct resource_info { + struct timeval start_time, end_time; +}; +struct thread_info { + pthread_t tid; + struct resource_info r; + krb5_context ctx; +}; + +static char *prog; +static unsigned int n_threads = N_THREADS; +static int iter_count = ITER_COUNT; +static int do_pause; + +static void usage (void) __attribute__((noreturn)); + +static void +usage () +{ + fprintf (stderr, "usage: %s [ options ]\n", prog); + fprintf (stderr, "options:\n"); + fprintf (stderr, "\t-t N\tspecify number of threads (default %d)\n", + N_THREADS); + fprintf (stderr, "\t-i N\tset iteration count (default %d)\n", + ITER_COUNT); + fprintf (stderr, "\t-K\tinitialize a krb5_context for the duration\n"); + fprintf (stderr, "\t-P\tpause briefly after starting, to allow attaching dtrace/strace/etc\n"); + exit (1); +} + +static int +numarg (char *arg) +{ + char *end; + long val; + + val = strtol (arg, &end, 10); + if (*arg == 0 || *end != 0) { + fprintf (stderr, "invalid numeric argument '%s'\n", arg); + usage (); + } + if (val >= 1 && val <= INT_MAX) + return val; + fprintf (stderr, "out of range numeric value %ld (1..%d)\n", + val, INT_MAX); + usage (); +} + +static char optstring[] = "t:i:KP"; + +static void +process_options (int argc, char *argv[]) +{ + int c; + + prog = strrchr (argv[0], '/'); + if (prog) + prog++; + else + prog = argv[0]; + while ((c = getopt (argc, argv, optstring)) != -1) { + switch (c) { + case '?': + case ':': + usage (); + break; + + case 't': + n_threads = numarg (optarg); + if (n_threads >= SIZE_MAX / sizeof (struct thread_info)) { + n_threads = SIZE_MAX / sizeof (struct thread_info); + fprintf (stderr, "limiting n_threads to %u\n", n_threads); + } + break; + + case 'i': + iter_count = numarg (optarg); + break; + + case 'K': + init_krb5_first = 1; + break; + + case 'P': + do_pause = 1; + break; + } + } + if (argc != optind) + usage (); +} + +static long double +tvsub (struct timeval t1, struct timeval t2) +{ + /* POSIX says .tv_usec is signed. */ + return (t1.tv_sec - t2.tv_sec + + (long double) 1.0e-6 * (t1.tv_usec - t2.tv_usec)); +} + +static struct timeval +now (void) +{ + struct timeval tv; + if (gettimeofday (&tv, NULL) < 0) { + perror ("gettimeofday"); + exit (1); + } + return tv; +} + +static void run_iterations (struct resource_info *r) +{ + int i; + krb5_error_code err; + krb5_context ctx; + profile_t prof = NULL; + + err = krb5_init_context(&ctx); + if (err) { + com_err(prog, err, "initializing krb5 context"); + exit(1); + } + err = krb5_get_profile(ctx, &prof); + if (err) { + com_err(prog, err, "fetching profile from context"); + exit(1); + } + r->start_time = now (); + for (i = 0; i < iter_count; i++) { + int ival; + err = profile_get_integer(prof, "one", "two", "three", 42, &ival); + if (err) { + com_err(prog, err, "fetching value from profile"); + exit(1); + } + } + r->end_time = now (); + profile_release (prof); + krb5_free_context(ctx); +} + +static void * +thread_proc (void *p) +{ + run_iterations (p); + return 0; +} + +static struct thread_info *tinfo; + +static krb5_context kctx; +static struct rusage start, finish; +static struct timeval start_time, finish_time; + +int +main (int argc, char *argv[]) +{ + long double user, sys, wallclock, total; + unsigned int i; + + process_options (argc, argv); + + /* + * Some places in the krb5 library cache data globally. + * This option allows you to test the effect of that. + */ + if (init_krb5_first && krb5_init_context (&kctx) != 0) { + fprintf (stderr, "krb5_init_context error\n"); + exit (1); + } + tinfo = calloc (n_threads, sizeof (*tinfo)); + if (tinfo == NULL) { + perror ("calloc"); + exit (1); + } + printf ("Threads: %d iterations: %d\n", n_threads, iter_count); + if (do_pause) { + printf ("pid %lu napping...\n", (unsigned long) getpid ()); + sleep (10); + } + printf ("starting...\n"); + /* And *now* we start measuring the performance. */ + if (getrusage (RUSAGE_SELF, &start) < 0) { + perror ("getrusage"); + exit (1); + } + start_time = now (); +#define foreach_thread(IDXVAR) for (IDXVAR = 0; IDXVAR < n_threads; IDXVAR++) + foreach_thread (i) { + int err; + + err = pthread_create (&tinfo[i].tid, NULL, thread_proc, &tinfo[i].r); + if (err) { + fprintf (stderr, "pthread_create: %s\n", strerror (err)); + exit (1); + } + } + foreach_thread (i) { + int err; + void *val; + + err = pthread_join (tinfo[i].tid, &val); + if (err) { + fprintf (stderr, "pthread_join: %s\n", strerror (err)); + exit (1); + } + } + finish_time = now (); + if (getrusage (RUSAGE_SELF, &finish) < 0) { + perror ("getrusage"); + exit (1); + } + if (init_krb5_first) + krb5_free_context (kctx); + foreach_thread (i) { + printf ("Thread %2d: elapsed time %Lfs\n", i, + tvsub (tinfo[i].r.end_time, tinfo[i].r.start_time)); + } + wallclock = tvsub (finish_time, start_time); + /* + * Report on elapsed time and CPU usage. Depending what + * performance issue you're chasing down, different values may be + * of particular interest, so report all the info we've got. + */ + printf ("Overall run time with %d threads = %Lfs, %Lfms per iteration.\n", + n_threads, wallclock, 1000 * wallclock / iter_count); + user = tvsub (finish.ru_utime, start.ru_utime); + sys = tvsub (finish.ru_stime, start.ru_stime); + total = user + sys; + printf ("CPU usage: user=%Lfs sys=%Lfs total=%Lfs.\n", user, sys, total); + printf ("Utilization: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n", + 100 * user / wallclock, + 100 * sys / wallclock, + 100 * total / wallclock); + printf ("Util/thread: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n", + 100 * user / wallclock / n_threads, + 100 * sys / wallclock / n_threads, + 100 * total / wallclock / n_threads); + printf ("Total CPU use per iteration per thread: %Lfms\n", + 1000 * total / n_threads / iter_count); + return 0; +}