xref: /freebsd/crypto/krb5/src/tests/threads/profread.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* tests/threads/profread.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (C) 2009 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All rights reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert /*
28*7f2fe78bSCy Schubert  * krb5 profile data retrieval performance testing
29*7f2fe78bSCy Schubert  * initially contributed by Ken Raeburn
30*7f2fe78bSCy Schubert  */
31*7f2fe78bSCy Schubert 
32*7f2fe78bSCy Schubert #include "k5-platform.h"
33*7f2fe78bSCy Schubert #include <unistd.h>
34*7f2fe78bSCy Schubert #include <pthread.h>
35*7f2fe78bSCy Schubert #include <krb5.h>
36*7f2fe78bSCy Schubert #include <profile.h>
37*7f2fe78bSCy Schubert 
38*7f2fe78bSCy Schubert #include <sys/time.h>
39*7f2fe78bSCy Schubert #include <sys/resource.h>
40*7f2fe78bSCy Schubert 
41*7f2fe78bSCy Schubert #define N_THREADS 4
42*7f2fe78bSCy Schubert #define ITER_COUNT 40000
43*7f2fe78bSCy Schubert static int init_krb5_first = 0;
44*7f2fe78bSCy Schubert 
45*7f2fe78bSCy Schubert struct resource_info {
46*7f2fe78bSCy Schubert     struct timeval start_time, end_time;
47*7f2fe78bSCy Schubert };
48*7f2fe78bSCy Schubert struct thread_info {
49*7f2fe78bSCy Schubert     pthread_t tid;
50*7f2fe78bSCy Schubert     struct resource_info r;
51*7f2fe78bSCy Schubert     krb5_context ctx;
52*7f2fe78bSCy Schubert };
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert static char *prog;
55*7f2fe78bSCy Schubert static unsigned int n_threads = N_THREADS;
56*7f2fe78bSCy Schubert static int iter_count = ITER_COUNT;
57*7f2fe78bSCy Schubert static int do_pause;
58*7f2fe78bSCy Schubert 
59*7f2fe78bSCy Schubert static void usage (void) __attribute__((noreturn));
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert static void
usage()62*7f2fe78bSCy Schubert usage ()
63*7f2fe78bSCy Schubert {
64*7f2fe78bSCy Schubert     fprintf (stderr, "usage: %s [ options ]\n", prog);
65*7f2fe78bSCy Schubert     fprintf (stderr, "options:\n");
66*7f2fe78bSCy Schubert     fprintf (stderr, "\t-t N\tspecify number of threads (default %d)\n",
67*7f2fe78bSCy Schubert              N_THREADS);
68*7f2fe78bSCy Schubert     fprintf (stderr, "\t-i N\tset iteration count (default %d)\n",
69*7f2fe78bSCy Schubert              ITER_COUNT);
70*7f2fe78bSCy Schubert     fprintf (stderr, "\t-K\tinitialize a krb5_context for the duration\n");
71*7f2fe78bSCy Schubert     fprintf (stderr, "\t-P\tpause briefly after starting, to allow attaching dtrace/strace/etc\n");
72*7f2fe78bSCy Schubert     exit (1);
73*7f2fe78bSCy Schubert }
74*7f2fe78bSCy Schubert 
75*7f2fe78bSCy Schubert static int
numarg(char * arg)76*7f2fe78bSCy Schubert numarg (char *arg)
77*7f2fe78bSCy Schubert {
78*7f2fe78bSCy Schubert     char *end;
79*7f2fe78bSCy Schubert     long val;
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert     val = strtol (arg, &end, 10);
82*7f2fe78bSCy Schubert     if (*arg == 0 || *end != 0) {
83*7f2fe78bSCy Schubert         fprintf (stderr, "invalid numeric argument '%s'\n", arg);
84*7f2fe78bSCy Schubert         usage ();
85*7f2fe78bSCy Schubert     }
86*7f2fe78bSCy Schubert     if (val >= 1 && val <= INT_MAX)
87*7f2fe78bSCy Schubert         return val;
88*7f2fe78bSCy Schubert     fprintf (stderr, "out of range numeric value %ld (1..%d)\n",
89*7f2fe78bSCy Schubert              val, INT_MAX);
90*7f2fe78bSCy Schubert     usage ();
91*7f2fe78bSCy Schubert }
92*7f2fe78bSCy Schubert 
93*7f2fe78bSCy Schubert static char optstring[] = "t:i:KP";
94*7f2fe78bSCy Schubert 
95*7f2fe78bSCy Schubert static void
process_options(int argc,char * argv[])96*7f2fe78bSCy Schubert process_options (int argc, char *argv[])
97*7f2fe78bSCy Schubert {
98*7f2fe78bSCy Schubert     int c;
99*7f2fe78bSCy Schubert 
100*7f2fe78bSCy Schubert     prog = strrchr (argv[0], '/');
101*7f2fe78bSCy Schubert     if (prog)
102*7f2fe78bSCy Schubert         prog++;
103*7f2fe78bSCy Schubert     else
104*7f2fe78bSCy Schubert         prog = argv[0];
105*7f2fe78bSCy Schubert     while ((c = getopt (argc, argv, optstring)) != -1) {
106*7f2fe78bSCy Schubert         switch (c) {
107*7f2fe78bSCy Schubert         case '?':
108*7f2fe78bSCy Schubert         case ':':
109*7f2fe78bSCy Schubert             usage ();
110*7f2fe78bSCy Schubert             break;
111*7f2fe78bSCy Schubert 
112*7f2fe78bSCy Schubert         case 't':
113*7f2fe78bSCy Schubert             n_threads = numarg (optarg);
114*7f2fe78bSCy Schubert             if (n_threads >= SIZE_MAX / sizeof (struct thread_info)) {
115*7f2fe78bSCy Schubert                 n_threads = SIZE_MAX / sizeof (struct thread_info);
116*7f2fe78bSCy Schubert                 fprintf (stderr, "limiting n_threads to %u\n", n_threads);
117*7f2fe78bSCy Schubert             }
118*7f2fe78bSCy Schubert             break;
119*7f2fe78bSCy Schubert 
120*7f2fe78bSCy Schubert         case 'i':
121*7f2fe78bSCy Schubert             iter_count = numarg (optarg);
122*7f2fe78bSCy Schubert             break;
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert         case 'K':
125*7f2fe78bSCy Schubert             init_krb5_first = 1;
126*7f2fe78bSCy Schubert             break;
127*7f2fe78bSCy Schubert 
128*7f2fe78bSCy Schubert         case 'P':
129*7f2fe78bSCy Schubert             do_pause = 1;
130*7f2fe78bSCy Schubert             break;
131*7f2fe78bSCy Schubert         }
132*7f2fe78bSCy Schubert     }
133*7f2fe78bSCy Schubert     if (argc != optind)
134*7f2fe78bSCy Schubert         usage ();
135*7f2fe78bSCy Schubert }
136*7f2fe78bSCy Schubert 
137*7f2fe78bSCy Schubert static long double
tvsub(struct timeval t1,struct timeval t2)138*7f2fe78bSCy Schubert tvsub (struct timeval t1, struct timeval t2)
139*7f2fe78bSCy Schubert {
140*7f2fe78bSCy Schubert     /* POSIX says .tv_usec is signed.  */
141*7f2fe78bSCy Schubert     return (t1.tv_sec - t2.tv_sec
142*7f2fe78bSCy Schubert             + (long double) 1.0e-6 * (t1.tv_usec - t2.tv_usec));
143*7f2fe78bSCy Schubert }
144*7f2fe78bSCy Schubert 
145*7f2fe78bSCy Schubert static struct timeval
now(void)146*7f2fe78bSCy Schubert now (void)
147*7f2fe78bSCy Schubert {
148*7f2fe78bSCy Schubert     struct timeval tv;
149*7f2fe78bSCy Schubert     if (gettimeofday (&tv, NULL) < 0) {
150*7f2fe78bSCy Schubert         perror ("gettimeofday");
151*7f2fe78bSCy Schubert         exit (1);
152*7f2fe78bSCy Schubert     }
153*7f2fe78bSCy Schubert     return tv;
154*7f2fe78bSCy Schubert }
155*7f2fe78bSCy Schubert 
run_iterations(struct resource_info * r)156*7f2fe78bSCy Schubert static void run_iterations (struct resource_info *r)
157*7f2fe78bSCy Schubert {
158*7f2fe78bSCy Schubert     int i;
159*7f2fe78bSCy Schubert     krb5_error_code err;
160*7f2fe78bSCy Schubert     krb5_context ctx;
161*7f2fe78bSCy Schubert     profile_t prof = NULL;
162*7f2fe78bSCy Schubert 
163*7f2fe78bSCy Schubert     err = krb5_init_context(&ctx);
164*7f2fe78bSCy Schubert     if (err) {
165*7f2fe78bSCy Schubert         com_err(prog, err, "initializing krb5 context");
166*7f2fe78bSCy Schubert         exit(1);
167*7f2fe78bSCy Schubert     }
168*7f2fe78bSCy Schubert     err = krb5_get_profile(ctx, &prof);
169*7f2fe78bSCy Schubert     if (err) {
170*7f2fe78bSCy Schubert         com_err(prog, err, "fetching profile from context");
171*7f2fe78bSCy Schubert         exit(1);
172*7f2fe78bSCy Schubert     }
173*7f2fe78bSCy Schubert     r->start_time = now ();
174*7f2fe78bSCy Schubert     for (i = 0; i < iter_count; i++) {
175*7f2fe78bSCy Schubert         int ival;
176*7f2fe78bSCy Schubert         err = profile_get_integer(prof, "one", "two", "three", 42, &ival);
177*7f2fe78bSCy Schubert         if (err) {
178*7f2fe78bSCy Schubert             com_err(prog, err, "fetching value from profile");
179*7f2fe78bSCy Schubert             exit(1);
180*7f2fe78bSCy Schubert         }
181*7f2fe78bSCy Schubert     }
182*7f2fe78bSCy Schubert     r->end_time = now ();
183*7f2fe78bSCy Schubert     profile_release (prof);
184*7f2fe78bSCy Schubert     krb5_free_context(ctx);
185*7f2fe78bSCy Schubert }
186*7f2fe78bSCy Schubert 
187*7f2fe78bSCy Schubert static void *
thread_proc(void * p)188*7f2fe78bSCy Schubert thread_proc (void *p)
189*7f2fe78bSCy Schubert {
190*7f2fe78bSCy Schubert     run_iterations (p);
191*7f2fe78bSCy Schubert     return 0;
192*7f2fe78bSCy Schubert }
193*7f2fe78bSCy Schubert 
194*7f2fe78bSCy Schubert static struct thread_info *tinfo;
195*7f2fe78bSCy Schubert 
196*7f2fe78bSCy Schubert static krb5_context kctx;
197*7f2fe78bSCy Schubert static struct rusage start, finish;
198*7f2fe78bSCy Schubert static struct timeval start_time, finish_time;
199*7f2fe78bSCy Schubert 
200*7f2fe78bSCy Schubert int
main(int argc,char * argv[])201*7f2fe78bSCy Schubert main (int argc, char *argv[])
202*7f2fe78bSCy Schubert {
203*7f2fe78bSCy Schubert     long double user, sys, wallclock, total;
204*7f2fe78bSCy Schubert     unsigned int i;
205*7f2fe78bSCy Schubert 
206*7f2fe78bSCy Schubert     process_options (argc, argv);
207*7f2fe78bSCy Schubert 
208*7f2fe78bSCy Schubert     /*
209*7f2fe78bSCy Schubert      * Some places in the krb5 library cache data globally.
210*7f2fe78bSCy Schubert      * This option allows you to test the effect of that.
211*7f2fe78bSCy Schubert      */
212*7f2fe78bSCy Schubert     if (init_krb5_first && krb5_init_context (&kctx) != 0) {
213*7f2fe78bSCy Schubert         fprintf (stderr, "krb5_init_context error\n");
214*7f2fe78bSCy Schubert         exit (1);
215*7f2fe78bSCy Schubert     }
216*7f2fe78bSCy Schubert     tinfo = calloc (n_threads, sizeof (*tinfo));
217*7f2fe78bSCy Schubert     if (tinfo == NULL) {
218*7f2fe78bSCy Schubert         perror ("calloc");
219*7f2fe78bSCy Schubert         exit (1);
220*7f2fe78bSCy Schubert     }
221*7f2fe78bSCy Schubert     printf ("Threads: %d  iterations: %d\n", n_threads, iter_count);
222*7f2fe78bSCy Schubert     if (do_pause) {
223*7f2fe78bSCy Schubert         printf ("pid %lu napping...\n", (unsigned long) getpid ());
224*7f2fe78bSCy Schubert         sleep (10);
225*7f2fe78bSCy Schubert     }
226*7f2fe78bSCy Schubert     printf ("starting...\n");
227*7f2fe78bSCy Schubert     /* And *now* we start measuring the performance.  */
228*7f2fe78bSCy Schubert     if (getrusage (RUSAGE_SELF, &start) < 0) {
229*7f2fe78bSCy Schubert         perror ("getrusage");
230*7f2fe78bSCy Schubert         exit (1);
231*7f2fe78bSCy Schubert     }
232*7f2fe78bSCy Schubert     start_time = now ();
233*7f2fe78bSCy Schubert #define foreach_thread(IDXVAR) for (IDXVAR = 0; IDXVAR < n_threads; IDXVAR++)
234*7f2fe78bSCy Schubert     foreach_thread (i) {
235*7f2fe78bSCy Schubert         int err;
236*7f2fe78bSCy Schubert 
237*7f2fe78bSCy Schubert         err = pthread_create (&tinfo[i].tid, NULL, thread_proc, &tinfo[i].r);
238*7f2fe78bSCy Schubert         if (err) {
239*7f2fe78bSCy Schubert             fprintf (stderr, "pthread_create: %s\n", strerror (err));
240*7f2fe78bSCy Schubert             exit (1);
241*7f2fe78bSCy Schubert         }
242*7f2fe78bSCy Schubert     }
243*7f2fe78bSCy Schubert     foreach_thread (i) {
244*7f2fe78bSCy Schubert         int err;
245*7f2fe78bSCy Schubert         void *val;
246*7f2fe78bSCy Schubert 
247*7f2fe78bSCy Schubert         err = pthread_join (tinfo[i].tid, &val);
248*7f2fe78bSCy Schubert         if (err) {
249*7f2fe78bSCy Schubert             fprintf (stderr, "pthread_join: %s\n", strerror (err));
250*7f2fe78bSCy Schubert             exit (1);
251*7f2fe78bSCy Schubert         }
252*7f2fe78bSCy Schubert     }
253*7f2fe78bSCy Schubert     finish_time = now ();
254*7f2fe78bSCy Schubert     if (getrusage (RUSAGE_SELF, &finish) < 0) {
255*7f2fe78bSCy Schubert         perror ("getrusage");
256*7f2fe78bSCy Schubert         exit (1);
257*7f2fe78bSCy Schubert     }
258*7f2fe78bSCy Schubert     if (init_krb5_first)
259*7f2fe78bSCy Schubert         krb5_free_context (kctx);
260*7f2fe78bSCy Schubert     foreach_thread (i) {
261*7f2fe78bSCy Schubert         printf ("Thread %2d: elapsed time %Lfs\n", i,
262*7f2fe78bSCy Schubert                 tvsub (tinfo[i].r.end_time, tinfo[i].r.start_time));
263*7f2fe78bSCy Schubert     }
264*7f2fe78bSCy Schubert     wallclock = tvsub (finish_time, start_time);
265*7f2fe78bSCy Schubert     /*
266*7f2fe78bSCy Schubert      * Report on elapsed time and CPU usage.  Depending what
267*7f2fe78bSCy Schubert      * performance issue you're chasing down, different values may be
268*7f2fe78bSCy Schubert      * of particular interest, so report all the info we've got.
269*7f2fe78bSCy Schubert      */
270*7f2fe78bSCy Schubert     printf ("Overall run time with %d threads = %Lfs, %.2Lfus per iteration.\n",
271*7f2fe78bSCy Schubert             n_threads, wallclock, 1000000 * wallclock / iter_count);
272*7f2fe78bSCy Schubert     user = tvsub (finish.ru_utime, start.ru_utime);
273*7f2fe78bSCy Schubert     sys = tvsub (finish.ru_stime, start.ru_stime);
274*7f2fe78bSCy Schubert     total = user + sys;
275*7f2fe78bSCy Schubert     printf ("CPU usage:   user=%Lfs sys=%Lfs total=%Lfs.\n", user, sys, total);
276*7f2fe78bSCy Schubert     printf ("Utilization: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n",
277*7f2fe78bSCy Schubert             100 * user / wallclock,
278*7f2fe78bSCy Schubert             100 * sys / wallclock,
279*7f2fe78bSCy Schubert             100 * total / wallclock);
280*7f2fe78bSCy Schubert     printf ("Util/thread: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n",
281*7f2fe78bSCy Schubert             100 * user / wallclock / n_threads,
282*7f2fe78bSCy Schubert             100 * sys / wallclock / n_threads,
283*7f2fe78bSCy Schubert             100 * total / wallclock / n_threads);
284*7f2fe78bSCy Schubert     printf ("Total CPU use per iteration per thread: %.2Lfus\n",
285*7f2fe78bSCy Schubert             1000000 * total / n_threads / iter_count);
286*7f2fe78bSCy Schubert     return 0;
287*7f2fe78bSCy Schubert }
288