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