Gperf-simple.c revision 3be31f5dcb65ec1a37de234f127f7e69c9352a92
1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2003-2004 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be 14included in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23 24#include <memory.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <unistd.h> 28 29#include <time.h> 30 31#include <libunwind.h> 32 33#include <sys/resource.h> 34 35#define panic(args...) \ 36 do { fprintf (stderr, args); exit (-1); } while (0) 37 38long dummy; 39 40static long iterations = 10000; 41static int maxlevel = 100; 42 43#define KB 1024 44#define MB (1024*1024) 45 46static char big[64*MB]; /* should be >> max. cache size */ 47 48static inline double 49gettime (void) 50{ 51 struct timespec ts; 52 53 clock_gettime(CLOCK_REALTIME, &ts); 54 return ts.tv_sec + 1e-9*ts.tv_nsec; 55} 56 57static int 58measure_unwind (int maxlevel, double *step) 59{ 60 double stop, start; 61 unw_cursor_t cursor; 62 unw_context_t uc; 63 int ret, level = 0; 64 65 unw_getcontext (&uc); 66 if (unw_init_local (&cursor, &uc) < 0) 67 panic ("unw_init_local() failed\n"); 68 69 start = gettime (); 70 71 do 72 { 73 ret = unw_step (&cursor); 74 if (ret < 0) 75 panic ("unw_step() failed\n"); 76 ++level; 77 } 78 while (ret > 0); 79 80 stop = gettime (); 81 82 if (level <= maxlevel) 83 panic ("Unwound only %d levels, expected at least %d levels", 84 level, maxlevel); 85 86 *step = (stop - start) / (double) level; 87 return 0; 88} 89 90static int 91f1 (int level, int maxlevel, double *step) 92{ 93 if (level == maxlevel) 94 return measure_unwind (maxlevel, step); 95 else 96 /* defeat last-call/sibcall optimization */ 97 return f1 (level + 1, maxlevel, step) + level; 98} 99 100static void 101doit (const char *label) 102{ 103 double step, min_step, first_step, sum_step; 104 int i; 105 106 sum_step = first_step = 0.0; 107 min_step = 1e99; 108 for (i = 0; i < iterations; ++i) 109 { 110 f1 (0, maxlevel, &step); 111 112 sum_step += step; 113 114 if (step < min_step) 115 min_step = step; 116 117 if (i == 0) 118 first_step = step; 119 } 120 printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label, 121 1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations); 122} 123 124static long 125sum (void *buf, size_t size) 126{ 127 long s = 0; 128 char *cp = buf; 129 size_t i; 130 131 for (i = 0; i < size; i += 8) 132 s += cp[i]; 133 return s; 134} 135 136static void 137measure_init (void) 138{ 139# define N 100 140# define M 10 /* must be at least 2 to get steady-state */ 141 double stop, start, get_cold, get_warm, init_cold, init_warm, delta; 142 struct 143 { 144 unw_cursor_t c; 145 char padding[1024]; /* should be > 2 * max. cacheline size */ 146 } 147 cursor[N]; 148 struct 149 { 150 unw_context_t uc; 151 char padding[1024]; /* should be > 2 * max. cacheline size */ 152 } 153 uc[N]; 154 int i, j; 155 156 /* Run each test M times and take the minimum to filter out noise 157 such dynamic linker resolving overhead, context-switches, 158 page-in, cache, and TLB effects. */ 159 160 get_cold = 1e99; 161 for (j = 0; j < M; ++j) 162 { 163 dummy += sum (big, sizeof (big)); /* flush the cache */ 164 for (i = 0; i < N; ++i) 165 uc[i].padding[511] = i; /* warm up the TLB */ 166 start = gettime (); 167 for (i = 0; i < N; ++i) 168 unw_getcontext (&uc[i].uc); 169 stop = gettime (); 170 delta = (stop - start) / N; 171 if (delta < get_cold) 172 get_cold = delta; 173 } 174 175 init_cold = 1e99; 176 for (j = 0; j < M; ++j) 177 { 178 dummy += sum (big, sizeof (big)); /* flush cache */ 179 for (i = 0; i < N; ++i) 180 uc[i].padding[511] = i; /* warm up the TLB */ 181 start = gettime (); 182 for (i = 0; i < N; ++i) 183 unw_init_local (&cursor[i].c, &uc[i].uc); 184 stop = gettime (); 185 delta = (stop - start) / N; 186 if (delta < init_cold) 187 init_cold = delta; 188 } 189 190 get_warm = 1e99; 191 for (j = 0; j < M; ++j) 192 { 193 start = gettime (); 194 for (i = 0; i < N; ++i) 195 unw_getcontext (&uc[0].uc); 196 stop = gettime (); 197 delta = (stop - start) / N; 198 if (delta < get_warm) 199 get_warm = delta; 200 } 201 202 init_warm = 1e99; 203 for (j = 0; j < M; ++j) 204 { 205 start = gettime (); 206 for (i = 0; i < N; ++i) 207 unw_init_local (&cursor[0].c, &uc[0].uc); 208 stop = gettime (); 209 delta = (stop - start) / N; 210 if (delta < init_warm) 211 init_warm = delta; 212 } 213 214 printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 215 1e9 * get_cold, 1e9 * get_warm); 216 printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n", 217 1e9 * init_cold, 1e9 * init_warm); 218} 219 220int 221main (int argc, char **argv) 222{ 223 struct rlimit rlim; 224 225 rlim.rlim_cur = RLIM_INFINITY; 226 rlim.rlim_max = RLIM_INFINITY; 227 setrlimit (RLIMIT_STACK, &rlim); 228 229 memset (big, 0xaa, sizeof (big)); 230 231 if (argc > 1) 232 { 233 maxlevel = atol (argv[1]); 234 if (argc > 2) 235 iterations = atol (argv[2]); 236 } 237 238 measure_init (); 239 240 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE); 241 doit ("no cache "); 242 243 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL); 244 doit ("global cache "); 245 246 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD); 247 doit ("per-thread cache"); 248 249 return 0; 250} 251