xref: /freebsd/crypto/krb5/src/tests/threads/gss-perf.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* tests/threads/gss-perf.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  * GSSAPI performance testing
29*7f2fe78bSCy Schubert  * initially contributed by Ken Raeburn
30*7f2fe78bSCy Schubert  */
31*7f2fe78bSCy Schubert /*
32*7f2fe78bSCy Schubert  * Possible to-do items:
33*7f2fe78bSCy Schubert  * - init-mutual testing (process msg back from accept)
34*7f2fe78bSCy Schubert  * - wrap/unwrap testing (one init/accept per thread, loop on wrap/unwrap)
35*7f2fe78bSCy Schubert  * - wrap/unwrap MT testing (one init/accept for process) ?
36*7f2fe78bSCy Schubert  * - init+accept with replay cache
37*7f2fe78bSCy Schubert  * - default to target "host@localhostname"
38*7f2fe78bSCy Schubert  * - input ccache option?
39*7f2fe78bSCy Schubert  *
40*7f2fe78bSCy Schubert  * Also, perhaps try to simulate certain application patterns, like
41*7f2fe78bSCy Schubert  * init/accept, exchange N messages with wrap/unwrap, destroy context,
42*7f2fe78bSCy Schubert  * all in a loop in M parallel threads.
43*7f2fe78bSCy Schubert  */
44*7f2fe78bSCy Schubert 
45*7f2fe78bSCy Schubert #include <stdio.h>
46*7f2fe78bSCy Schubert #include <string.h>
47*7f2fe78bSCy Schubert #include <stdlib.h>
48*7f2fe78bSCy Schubert #include <limits.h>
49*7f2fe78bSCy Schubert #include <assert.h>
50*7f2fe78bSCy Schubert #include <unistd.h>
51*7f2fe78bSCy Schubert #include <pthread.h>
52*7f2fe78bSCy Schubert #include <krb5.h>
53*7f2fe78bSCy Schubert #include <gssapi/gssapi.h>
54*7f2fe78bSCy Schubert 
55*7f2fe78bSCy Schubert #include <sys/time.h>
56*7f2fe78bSCy Schubert #include <sys/resource.h>
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert #define N_THREADS 2
59*7f2fe78bSCy Schubert #define ITER_COUNT 10000
60*7f2fe78bSCy Schubert static int init_krb5_first = 0;
61*7f2fe78bSCy Schubert 
62*7f2fe78bSCy Schubert struct resource_info {
63*7f2fe78bSCy Schubert     struct timeval start_time, end_time;
64*7f2fe78bSCy Schubert };
65*7f2fe78bSCy Schubert struct thread_info {
66*7f2fe78bSCy Schubert     pthread_t tid;
67*7f2fe78bSCy Schubert     struct resource_info r;
68*7f2fe78bSCy Schubert };
69*7f2fe78bSCy Schubert 
70*7f2fe78bSCy Schubert static gss_name_t target;
71*7f2fe78bSCy Schubert static char *prog, *target_name;
72*7f2fe78bSCy Schubert static unsigned int n_threads = N_THREADS;
73*7f2fe78bSCy Schubert static int iter_count = ITER_COUNT;
74*7f2fe78bSCy Schubert static int do_pause, do_mutual;
75*7f2fe78bSCy Schubert static int test_init, test_accept;
76*7f2fe78bSCy Schubert 
77*7f2fe78bSCy Schubert static void usage (void) __attribute__((noreturn));
78*7f2fe78bSCy Schubert static void set_target (char *);
79*7f2fe78bSCy Schubert 
80*7f2fe78bSCy Schubert static void
usage()81*7f2fe78bSCy Schubert usage ()
82*7f2fe78bSCy Schubert {
83*7f2fe78bSCy Schubert     fprintf (stderr, "usage: %s [ options ] service-name\n", prog);
84*7f2fe78bSCy Schubert     fprintf (stderr, "  service-name\tGSSAPI host-based service name (e.g., 'host@FQDN')\n");
85*7f2fe78bSCy Schubert     fprintf (stderr, "options:\n");
86*7f2fe78bSCy Schubert     fprintf (stderr, "\t-I\ttest gss_init_sec_context\n");
87*7f2fe78bSCy Schubert     fprintf (stderr, "\t-A\ttest gss_accept_sec_context\n");
88*7f2fe78bSCy Schubert     fprintf (stderr, "\t-k K\tspecify keytab (remember FILE: or other prefix!)\n");
89*7f2fe78bSCy Schubert     fprintf (stderr, "\t-t N\tspecify number of threads (default %d)\n",
90*7f2fe78bSCy Schubert              N_THREADS);
91*7f2fe78bSCy Schubert     fprintf (stderr, "\t-i N\tset iteration count (default %d)\n",
92*7f2fe78bSCy Schubert              ITER_COUNT);
93*7f2fe78bSCy Schubert     fprintf (stderr, "\t-m\tenable mutual authentication flag (but don't do the additional calls)\n");
94*7f2fe78bSCy Schubert     fprintf (stderr, "\t-K\tinitialize a krb5_context for the duration\n");
95*7f2fe78bSCy Schubert     fprintf (stderr, "\t-P\tpause briefly after starting, to allow attaching dtrace/strace/etc\n");
96*7f2fe78bSCy Schubert     exit (1);
97*7f2fe78bSCy Schubert }
98*7f2fe78bSCy Schubert 
99*7f2fe78bSCy Schubert static int
numarg(char * arg)100*7f2fe78bSCy Schubert numarg (char *arg)
101*7f2fe78bSCy Schubert {
102*7f2fe78bSCy Schubert     char *end;
103*7f2fe78bSCy Schubert     long val;
104*7f2fe78bSCy Schubert 
105*7f2fe78bSCy Schubert     val = strtol (arg, &end, 10);
106*7f2fe78bSCy Schubert     if (*arg == 0 || *end != 0) {
107*7f2fe78bSCy Schubert         fprintf (stderr, "invalid numeric argument '%s'\n", arg);
108*7f2fe78bSCy Schubert         usage ();
109*7f2fe78bSCy Schubert     }
110*7f2fe78bSCy Schubert     if (val >= 1 && val <= INT_MAX)
111*7f2fe78bSCy Schubert         return val;
112*7f2fe78bSCy Schubert     fprintf (stderr, "out of range numeric value %ld (1..%d)\n",
113*7f2fe78bSCy Schubert              val, INT_MAX);
114*7f2fe78bSCy Schubert     usage ();
115*7f2fe78bSCy Schubert }
116*7f2fe78bSCy Schubert 
117*7f2fe78bSCy Schubert static char optstring[] = "k:t:i:KPmIA";
118*7f2fe78bSCy Schubert 
119*7f2fe78bSCy Schubert static void
process_options(int argc,char * argv[])120*7f2fe78bSCy Schubert process_options (int argc, char *argv[])
121*7f2fe78bSCy Schubert {
122*7f2fe78bSCy Schubert     int c;
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert     prog = strrchr (argv[0], '/');
125*7f2fe78bSCy Schubert     if (prog)
126*7f2fe78bSCy Schubert         prog++;
127*7f2fe78bSCy Schubert     else
128*7f2fe78bSCy Schubert         prog = argv[0];
129*7f2fe78bSCy Schubert     while ((c = getopt (argc, argv, optstring)) != -1) {
130*7f2fe78bSCy Schubert         switch (c) {
131*7f2fe78bSCy Schubert         case '?':
132*7f2fe78bSCy Schubert         case ':':
133*7f2fe78bSCy Schubert             usage ();
134*7f2fe78bSCy Schubert             break;
135*7f2fe78bSCy Schubert 
136*7f2fe78bSCy Schubert         case 'k':
137*7f2fe78bSCy Schubert             setenv ("KRB5_KTNAME", optarg, 1);
138*7f2fe78bSCy Schubert             break;
139*7f2fe78bSCy Schubert 
140*7f2fe78bSCy Schubert         case 't':
141*7f2fe78bSCy Schubert             n_threads = numarg (optarg);
142*7f2fe78bSCy Schubert             if (n_threads >= SIZE_MAX / sizeof (struct thread_info)) {
143*7f2fe78bSCy Schubert                 n_threads = SIZE_MAX / sizeof (struct thread_info);
144*7f2fe78bSCy Schubert                 fprintf (stderr, "limiting n_threads to %u\n", n_threads);
145*7f2fe78bSCy Schubert             }
146*7f2fe78bSCy Schubert             break;
147*7f2fe78bSCy Schubert 
148*7f2fe78bSCy Schubert         case 'i':
149*7f2fe78bSCy Schubert             iter_count = numarg (optarg);
150*7f2fe78bSCy Schubert             break;
151*7f2fe78bSCy Schubert 
152*7f2fe78bSCy Schubert         case 'K':
153*7f2fe78bSCy Schubert             init_krb5_first = 1;
154*7f2fe78bSCy Schubert             break;
155*7f2fe78bSCy Schubert 
156*7f2fe78bSCy Schubert         case 'P':
157*7f2fe78bSCy Schubert             do_pause = 1;
158*7f2fe78bSCy Schubert             break;
159*7f2fe78bSCy Schubert 
160*7f2fe78bSCy Schubert         case 'I':
161*7f2fe78bSCy Schubert             test_init = 1;
162*7f2fe78bSCy Schubert             break;
163*7f2fe78bSCy Schubert         case 'A':
164*7f2fe78bSCy Schubert             test_accept = 1;
165*7f2fe78bSCy Schubert             break;
166*7f2fe78bSCy Schubert         }
167*7f2fe78bSCy Schubert     }
168*7f2fe78bSCy Schubert     if (argc == optind + 1)
169*7f2fe78bSCy Schubert         set_target (argv[optind]);
170*7f2fe78bSCy Schubert     else
171*7f2fe78bSCy Schubert         usage ();
172*7f2fe78bSCy Schubert 
173*7f2fe78bSCy Schubert     if (test_init && test_accept) {
174*7f2fe78bSCy Schubert         fprintf (stderr, "-I and -A are mutually exclusive\n");
175*7f2fe78bSCy Schubert         usage ();
176*7f2fe78bSCy Schubert     }
177*7f2fe78bSCy Schubert     if (test_init == 0 && test_accept == 0)
178*7f2fe78bSCy Schubert         test_init = 1;
179*7f2fe78bSCy Schubert }
180*7f2fe78bSCy Schubert 
181*7f2fe78bSCy Schubert static void
display_a_status(const char * s_type,OM_uint32 type,OM_uint32 val)182*7f2fe78bSCy Schubert display_a_status (const char *s_type, OM_uint32 type, OM_uint32 val)
183*7f2fe78bSCy Schubert {
184*7f2fe78bSCy Schubert     OM_uint32 mctx = 0;
185*7f2fe78bSCy Schubert     OM_uint32 maj_stat, min_stat;
186*7f2fe78bSCy Schubert     gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
187*7f2fe78bSCy Schubert 
188*7f2fe78bSCy Schubert     do {
189*7f2fe78bSCy Schubert         maj_stat = gss_display_status (&min_stat,
190*7f2fe78bSCy Schubert                                        val,
191*7f2fe78bSCy Schubert                                        type,
192*7f2fe78bSCy Schubert                                        GSS_C_NO_OID,
193*7f2fe78bSCy Schubert                                        &mctx,
194*7f2fe78bSCy Schubert                                        &msg);
195*7f2fe78bSCy Schubert         if (maj_stat != GSS_S_COMPLETE) {
196*7f2fe78bSCy Schubert             fprintf (stderr,
197*7f2fe78bSCy Schubert                      "error getting display form of %s status code %#lx\n",
198*7f2fe78bSCy Schubert                      s_type, (unsigned long) val);
199*7f2fe78bSCy Schubert             exit (1);
200*7f2fe78bSCy Schubert         }
201*7f2fe78bSCy Schubert         fprintf (stderr, " %s: %.*s\n", s_type,
202*7f2fe78bSCy Schubert                  (int) msg.length, (char *) msg.value);
203*7f2fe78bSCy Schubert         gss_release_buffer (&min_stat, &msg);
204*7f2fe78bSCy Schubert     } while (mctx != 0);
205*7f2fe78bSCy Schubert }
206*7f2fe78bSCy Schubert 
207*7f2fe78bSCy Schubert static void
gss_error(const char * where,OM_uint32 maj_stat,OM_uint32 min_stat)208*7f2fe78bSCy Schubert gss_error(const char *where, OM_uint32 maj_stat, OM_uint32 min_stat)
209*7f2fe78bSCy Schubert {
210*7f2fe78bSCy Schubert     fprintf (stderr, "%s: %s:\n", prog, where);
211*7f2fe78bSCy Schubert     display_a_status ("major", GSS_C_GSS_CODE, maj_stat);
212*7f2fe78bSCy Schubert     display_a_status ("minor", GSS_C_MECH_CODE, min_stat);
213*7f2fe78bSCy Schubert     exit (1);
214*7f2fe78bSCy Schubert }
215*7f2fe78bSCy Schubert 
216*7f2fe78bSCy Schubert static void
do_accept(gss_buffer_desc * msg,int iter)217*7f2fe78bSCy Schubert do_accept (gss_buffer_desc *msg, int iter)
218*7f2fe78bSCy Schubert {
219*7f2fe78bSCy Schubert     OM_uint32 maj_stat, min_stat;
220*7f2fe78bSCy Schubert     gss_name_t client = GSS_C_NO_NAME;
221*7f2fe78bSCy Schubert     gss_buffer_desc reply = GSS_C_EMPTY_BUFFER;
222*7f2fe78bSCy Schubert     gss_OID oid = GSS_C_NO_OID;
223*7f2fe78bSCy Schubert     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
224*7f2fe78bSCy Schubert     OM_uint32 flags = do_mutual ? GSS_C_MUTUAL_FLAG : 0;
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert     reply.value = NULL;
227*7f2fe78bSCy Schubert     reply.length = 0;
228*7f2fe78bSCy Schubert     maj_stat = gss_accept_sec_context (&min_stat,
229*7f2fe78bSCy Schubert                                        &ctx,
230*7f2fe78bSCy Schubert                                        GSS_C_NO_CREDENTIAL,
231*7f2fe78bSCy Schubert                                        msg,
232*7f2fe78bSCy Schubert                                        GSS_C_NO_CHANNEL_BINDINGS,
233*7f2fe78bSCy Schubert                                        &client,
234*7f2fe78bSCy Schubert                                        &oid,
235*7f2fe78bSCy Schubert                                        &reply,
236*7f2fe78bSCy Schubert                                        &flags,
237*7f2fe78bSCy Schubert                                        NULL, /* time_rec */
238*7f2fe78bSCy Schubert                                        NULL); /* del_cred_handle */
239*7f2fe78bSCy Schubert     if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
240*7f2fe78bSCy Schubert         fprintf (stderr, "pid %lu thread %#lx failing in iteration %d\n",
241*7f2fe78bSCy Schubert                  (unsigned long) getpid (), (unsigned long) pthread_self (),
242*7f2fe78bSCy Schubert                  iter);
243*7f2fe78bSCy Schubert         gss_error ("accepting context", maj_stat, min_stat);
244*7f2fe78bSCy Schubert     }
245*7f2fe78bSCy Schubert     gss_release_buffer (&min_stat, &reply);
246*7f2fe78bSCy Schubert     if (ctx != GSS_C_NO_CONTEXT)
247*7f2fe78bSCy Schubert         gss_delete_sec_context (&min_stat, &ctx, GSS_C_NO_BUFFER);
248*7f2fe78bSCy Schubert     gss_release_name (&min_stat, &client);
249*7f2fe78bSCy Schubert }
250*7f2fe78bSCy Schubert 
251*7f2fe78bSCy Schubert static gss_buffer_desc
do_init()252*7f2fe78bSCy Schubert do_init ()
253*7f2fe78bSCy Schubert {
254*7f2fe78bSCy Schubert     OM_uint32 maj_stat, min_stat;
255*7f2fe78bSCy Schubert     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
256*7f2fe78bSCy Schubert     OM_uint32 flags = 0, ret_flags = 0;
257*7f2fe78bSCy Schubert     gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
258*7f2fe78bSCy Schubert 
259*7f2fe78bSCy Schubert     if (do_mutual)
260*7f2fe78bSCy Schubert         flags |= GSS_C_MUTUAL_FLAG;
261*7f2fe78bSCy Schubert 
262*7f2fe78bSCy Schubert     msg.value = NULL;
263*7f2fe78bSCy Schubert     msg.length = 0;
264*7f2fe78bSCy Schubert     maj_stat = gss_init_sec_context (&min_stat,
265*7f2fe78bSCy Schubert                                      GSS_C_NO_CREDENTIAL,
266*7f2fe78bSCy Schubert                                      &ctx,
267*7f2fe78bSCy Schubert                                      target,
268*7f2fe78bSCy Schubert                                      GSS_C_NO_OID,
269*7f2fe78bSCy Schubert                                      flags,
270*7f2fe78bSCy Schubert                                      0,
271*7f2fe78bSCy Schubert                                      NULL, /* no channel bindings */
272*7f2fe78bSCy Schubert                                      NULL, /* no previous token */
273*7f2fe78bSCy Schubert                                      NULL, /* ignore mech type */
274*7f2fe78bSCy Schubert                                      &msg,
275*7f2fe78bSCy Schubert                                      &ret_flags,
276*7f2fe78bSCy Schubert                                      NULL); /* time_rec */
277*7f2fe78bSCy Schubert     if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
278*7f2fe78bSCy Schubert         gss_error ("initiating", maj_stat, min_stat);
279*7f2fe78bSCy Schubert     }
280*7f2fe78bSCy Schubert     if (ctx != GSS_C_NO_CONTEXT)
281*7f2fe78bSCy Schubert         gss_delete_sec_context (&min_stat, &ctx, GSS_C_NO_BUFFER);
282*7f2fe78bSCy Schubert     return msg;
283*7f2fe78bSCy Schubert }
284*7f2fe78bSCy Schubert 
285*7f2fe78bSCy Schubert static void
set_target(char * name)286*7f2fe78bSCy Schubert set_target (char *name)
287*7f2fe78bSCy Schubert {
288*7f2fe78bSCy Schubert     OM_uint32 maj_stat, min_stat;
289*7f2fe78bSCy Schubert     gss_buffer_desc namebuf;
290*7f2fe78bSCy Schubert 
291*7f2fe78bSCy Schubert     target_name = name;
292*7f2fe78bSCy Schubert     namebuf.value = name;
293*7f2fe78bSCy Schubert     namebuf.length = strlen (name);
294*7f2fe78bSCy Schubert     maj_stat = gss_import_name (&min_stat,
295*7f2fe78bSCy Schubert                                 &namebuf,
296*7f2fe78bSCy Schubert                                 GSS_C_NT_HOSTBASED_SERVICE,
297*7f2fe78bSCy Schubert                                 &target);
298*7f2fe78bSCy Schubert     if (maj_stat != GSS_S_COMPLETE)
299*7f2fe78bSCy Schubert         gss_error ("importing target name", maj_stat, min_stat);
300*7f2fe78bSCy Schubert }
301*7f2fe78bSCy Schubert 
302*7f2fe78bSCy Schubert static long double
tvsub(struct timeval t1,struct timeval t2)303*7f2fe78bSCy Schubert tvsub (struct timeval t1, struct timeval t2)
304*7f2fe78bSCy Schubert {
305*7f2fe78bSCy Schubert     /* POSIX says .tv_usec is signed.  */
306*7f2fe78bSCy Schubert     return (t1.tv_sec - t2.tv_sec
307*7f2fe78bSCy Schubert             + (long double) 1.0e-6 * (t1.tv_usec - t2.tv_usec));
308*7f2fe78bSCy Schubert }
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert static struct timeval
now(void)311*7f2fe78bSCy Schubert now (void)
312*7f2fe78bSCy Schubert {
313*7f2fe78bSCy Schubert     struct timeval tv;
314*7f2fe78bSCy Schubert     if (gettimeofday (&tv, NULL) < 0) {
315*7f2fe78bSCy Schubert         perror ("gettimeofday");
316*7f2fe78bSCy Schubert         exit (1);
317*7f2fe78bSCy Schubert     }
318*7f2fe78bSCy Schubert     return tv;
319*7f2fe78bSCy Schubert }
320*7f2fe78bSCy Schubert 
321*7f2fe78bSCy Schubert static gss_buffer_desc init_msg;
322*7f2fe78bSCy Schubert 
run_iterations(struct resource_info * r)323*7f2fe78bSCy Schubert static void run_iterations (struct resource_info *r)
324*7f2fe78bSCy Schubert {
325*7f2fe78bSCy Schubert     int i;
326*7f2fe78bSCy Schubert     OM_uint32 min_stat;
327*7f2fe78bSCy Schubert 
328*7f2fe78bSCy Schubert     r->start_time = now ();
329*7f2fe78bSCy Schubert     for (i = 0; i < iter_count; i++) {
330*7f2fe78bSCy Schubert         if (test_init) {
331*7f2fe78bSCy Schubert             gss_buffer_desc msg = do_init ();
332*7f2fe78bSCy Schubert             gss_release_buffer (&min_stat, &msg);
333*7f2fe78bSCy Schubert         } else if (test_accept) {
334*7f2fe78bSCy Schubert             do_accept (&init_msg, i);
335*7f2fe78bSCy Schubert         } else
336*7f2fe78bSCy Schubert             assert (test_init || test_accept);
337*7f2fe78bSCy Schubert     }
338*7f2fe78bSCy Schubert     r->end_time = now ();
339*7f2fe78bSCy Schubert }
340*7f2fe78bSCy Schubert 
341*7f2fe78bSCy Schubert static void *
thread_proc(void * p)342*7f2fe78bSCy Schubert thread_proc (void *p)
343*7f2fe78bSCy Schubert {
344*7f2fe78bSCy Schubert     run_iterations (p);
345*7f2fe78bSCy Schubert     return 0;
346*7f2fe78bSCy Schubert }
347*7f2fe78bSCy Schubert 
348*7f2fe78bSCy Schubert static struct thread_info *tinfo;
349*7f2fe78bSCy Schubert 
350*7f2fe78bSCy Schubert static krb5_context kctx;
351*7f2fe78bSCy Schubert static struct rusage start, finish;
352*7f2fe78bSCy Schubert static struct timeval start_time, finish_time;
353*7f2fe78bSCy Schubert 
354*7f2fe78bSCy Schubert int
main(int argc,char * argv[])355*7f2fe78bSCy Schubert main (int argc, char *argv[])
356*7f2fe78bSCy Schubert {
357*7f2fe78bSCy Schubert     long double user, sys, wallclock, total;
358*7f2fe78bSCy Schubert     unsigned int i;
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     /* Probably should have a command-line option controlling this,
361*7f2fe78bSCy Schubert        but if a replay cache is used, we can't do just one
362*7f2fe78bSCy Schubert        init_sec_context and easily time just the accept_sec_context
363*7f2fe78bSCy Schubert        side.  */
364*7f2fe78bSCy Schubert     setenv ("KRB5RCACHETYPE", "none", 1);
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert     process_options (argc, argv);
367*7f2fe78bSCy Schubert 
368*7f2fe78bSCy Schubert     /*
369*7f2fe78bSCy Schubert      * Some places in the krb5 library cache data globally.
370*7f2fe78bSCy Schubert      * This option allows you to test the effect of that.
371*7f2fe78bSCy Schubert      */
372*7f2fe78bSCy Schubert     if (init_krb5_first && krb5_init_context (&kctx) != 0) {
373*7f2fe78bSCy Schubert         fprintf (stderr, "krb5_init_context error\n");
374*7f2fe78bSCy Schubert         exit (1);
375*7f2fe78bSCy Schubert     }
376*7f2fe78bSCy Schubert     tinfo = calloc (n_threads, sizeof (*tinfo));
377*7f2fe78bSCy Schubert     if (tinfo == NULL) {
378*7f2fe78bSCy Schubert         perror ("calloc");
379*7f2fe78bSCy Schubert         exit (1);
380*7f2fe78bSCy Schubert     }
381*7f2fe78bSCy Schubert     printf ("Test: %s  threads: %d  iterations: %d  target: %s\n",
382*7f2fe78bSCy Schubert             test_init ? "init" : "accept", n_threads, iter_count,
383*7f2fe78bSCy Schubert             target_name ? target_name : "(NONE)");
384*7f2fe78bSCy Schubert     if (do_pause) {
385*7f2fe78bSCy Schubert         printf ("pid %lu napping...\n", (unsigned long) getpid ());
386*7f2fe78bSCy Schubert         sleep (10);
387*7f2fe78bSCy Schubert     }
388*7f2fe78bSCy Schubert     /*
389*7f2fe78bSCy Schubert      * Some tests use one message and process it over and over.  Even
390*7f2fe78bSCy Schubert      * if not, this sort of "primes" things by fetching any needed
391*7f2fe78bSCy Schubert      * tickets just once.
392*7f2fe78bSCy Schubert      */
393*7f2fe78bSCy Schubert     init_msg = do_init ();
394*7f2fe78bSCy Schubert     printf ("starting...\n");
395*7f2fe78bSCy Schubert     /* And *now* we start measuring the performance.  */
396*7f2fe78bSCy Schubert     if (getrusage (RUSAGE_SELF, &start) < 0) {
397*7f2fe78bSCy Schubert         perror ("getrusage");
398*7f2fe78bSCy Schubert         exit (1);
399*7f2fe78bSCy Schubert     }
400*7f2fe78bSCy Schubert     start_time = now ();
401*7f2fe78bSCy Schubert #define foreach_thread(IDXVAR) for (IDXVAR = 0; IDXVAR < n_threads; IDXVAR++)
402*7f2fe78bSCy Schubert     foreach_thread (i) {
403*7f2fe78bSCy Schubert         int err;
404*7f2fe78bSCy Schubert 
405*7f2fe78bSCy Schubert         err = pthread_create (&tinfo[i].tid, NULL, thread_proc, &tinfo[i].r);
406*7f2fe78bSCy Schubert         if (err) {
407*7f2fe78bSCy Schubert             fprintf (stderr, "pthread_create: %s\n", strerror (err));
408*7f2fe78bSCy Schubert             exit (1);
409*7f2fe78bSCy Schubert         }
410*7f2fe78bSCy Schubert     }
411*7f2fe78bSCy Schubert     foreach_thread (i) {
412*7f2fe78bSCy Schubert         int err;
413*7f2fe78bSCy Schubert         void *val;
414*7f2fe78bSCy Schubert 
415*7f2fe78bSCy Schubert         err = pthread_join (tinfo[i].tid, &val);
416*7f2fe78bSCy Schubert         if (err) {
417*7f2fe78bSCy Schubert             fprintf (stderr, "pthread_join: %s\n", strerror (err));
418*7f2fe78bSCy Schubert             exit (1);
419*7f2fe78bSCy Schubert         }
420*7f2fe78bSCy Schubert     }
421*7f2fe78bSCy Schubert     finish_time = now ();
422*7f2fe78bSCy Schubert     if (getrusage (RUSAGE_SELF, &finish) < 0) {
423*7f2fe78bSCy Schubert         perror ("getrusage");
424*7f2fe78bSCy Schubert         exit (1);
425*7f2fe78bSCy Schubert     }
426*7f2fe78bSCy Schubert     if (init_krb5_first)
427*7f2fe78bSCy Schubert         krb5_free_context (kctx);
428*7f2fe78bSCy Schubert     foreach_thread (i) {
429*7f2fe78bSCy Schubert         printf ("Thread %2d: elapsed time %Lfs\n", i,
430*7f2fe78bSCy Schubert                 tvsub (tinfo[i].r.end_time, tinfo[i].r.start_time));
431*7f2fe78bSCy Schubert     }
432*7f2fe78bSCy Schubert     wallclock = tvsub (finish_time, start_time);
433*7f2fe78bSCy Schubert     /*
434*7f2fe78bSCy Schubert      * Report on elapsed time and CPU usage.  Depending what
435*7f2fe78bSCy Schubert      * performance issue you're chasing down, different values may be
436*7f2fe78bSCy Schubert      * of particular interest, so report all the info we've got.
437*7f2fe78bSCy Schubert      */
438*7f2fe78bSCy Schubert     printf ("Overall run time with %d threads = %Lfs, %Lfms per iteration.\n",
439*7f2fe78bSCy Schubert             n_threads, wallclock, 1000 * wallclock / iter_count);
440*7f2fe78bSCy Schubert     user = tvsub (finish.ru_utime, start.ru_utime);
441*7f2fe78bSCy Schubert     sys = tvsub (finish.ru_stime, start.ru_stime);
442*7f2fe78bSCy Schubert     total = user + sys;
443*7f2fe78bSCy Schubert     printf ("CPU usage:   user=%Lfs sys=%Lfs total=%Lfs.\n", user, sys, total);
444*7f2fe78bSCy Schubert     printf ("Utilization: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n",
445*7f2fe78bSCy Schubert             100 * user / wallclock,
446*7f2fe78bSCy Schubert             100 * sys / wallclock,
447*7f2fe78bSCy Schubert             100 * total / wallclock);
448*7f2fe78bSCy Schubert     printf ("Util/thread: user=%5.1Lf%% sys=%5.1Lf%% total=%5.1Lf%%\n",
449*7f2fe78bSCy Schubert             100 * user / wallclock / n_threads,
450*7f2fe78bSCy Schubert             100 * sys / wallclock / n_threads,
451*7f2fe78bSCy Schubert             100 * total / wallclock / n_threads);
452*7f2fe78bSCy Schubert     printf ("Total CPU use per iteration per thread: %Lfms\n",
453*7f2fe78bSCy Schubert             1000 * total / n_threads / iter_count);
454*7f2fe78bSCy Schubert     return 0;
455*7f2fe78bSCy Schubert }
456