Gperf-simple.c revision 96c62506269ed6b7de3531816e9ad4a62fb50d92
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
28#include <time.h>
29
30#include <libunwind.h>
31
32#define panic(args...)							  \
33	do { fprintf (stderr, args); exit (-1); } while (0)
34
35long dummy;
36
37static long iterations = 10000;
38static int maxlevel = 100;
39
40#define MB	(1024*1024)
41
42static char big[128*MB];
43
44static inline double
45gettime (void)
46{
47  struct timespec ts;
48
49  clock_gettime(CLOCK_REALTIME, &ts);
50  return ts.tv_sec + 1e-9*ts.tv_nsec;
51}
52
53static int
54measure_unwind (int maxlevel, double *step)
55{
56  double stop, start;
57  unw_cursor_t cursor;
58  unw_context_t uc;
59  int ret, level = 0;
60
61  unw_getcontext (&uc);
62  if (unw_init_local (&cursor, &uc) < 0)
63    panic ("unw_init_local() failed\n");
64
65  start = gettime ();
66
67  do
68    {
69      ret = unw_step (&cursor);
70      if (ret < 0)
71	panic ("unw_step() failed\n");
72      ++level;
73    }
74  while (ret > 0);
75
76  stop = gettime ();
77
78  if (level <= maxlevel)
79    panic ("Unwound only %d levels, expected at least %d levels",
80	   level, maxlevel);
81
82  *step = (stop - start) / (double) level;
83  return 0;
84}
85
86static int
87f1 (int level, int maxlevel, double *step)
88{
89  if (level == maxlevel)
90    return measure_unwind (maxlevel, step);
91  else
92    /* defeat last-call/sibcall optimization */
93    return f1 (level + 1, maxlevel, step) + level;
94}
95
96static void
97doit (const char *label)
98{
99  double step, min_step, first_step, sum_step;
100  int i;
101
102  sum_step = first_step = 0.0;
103  min_step = 1e99;
104  for (i = 0; i < iterations; ++i)
105    {
106      f1 (0, maxlevel, &step);
107
108      sum_step += step;
109
110      if (step < min_step)
111	min_step = step;
112
113      if (i == 0)
114	first_step = step;
115    }
116  printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label,
117	  1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations);
118}
119
120static long
121sum (char *buf, size_t size)
122{
123  long s = 0;
124  size_t i;
125
126  for (i = 0; i < size; ++i)
127    s += *buf++;
128  return s;
129}
130
131static void
132measure_init (void)
133{
134# define N	1000
135  double stop, start, getcontext_cold, getcontext_warm, init_cold, init_warm;
136  unw_cursor_t cursor[N];
137  unw_context_t uc[N];
138  int i;
139
140  /* Ensure memory is paged in but not in the cache: */
141  memset (cursor, 0, sizeof (cursor));
142  memset (uc, 0, sizeof (uc));
143  dummy = sum (big, sizeof (big));
144
145  start = gettime ();
146  for (i = 0; i < N; ++i)
147    unw_getcontext (&uc[i]);
148  stop = gettime ();
149  getcontext_cold = (stop - start) / N;
150
151  start = gettime ();
152  for (i = 0; i < N; ++i)
153    unw_init_local (&cursor[i], &uc[i]);
154  stop = gettime ();
155  init_cold = (stop - start) / N;
156
157  start = gettime ();
158  for (i = 0; i < N; ++i)
159    unw_getcontext (&uc[0]);
160  stop = gettime ();
161  getcontext_warm = (stop - start) / N;
162
163  start = gettime ();
164  for (i = 0; i < N; ++i)
165    unw_init_local (&cursor[0], &uc[0]);
166  stop = gettime ();
167  init_warm = (stop - start) / N;
168
169  printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
170	  1e9 * getcontext_cold, 1e9 * getcontext_warm);
171  printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
172	  1e9 * init_cold, 1e9 * init_warm);
173}
174
175int
176main (int argc, char **argv)
177{
178  if (argc > 1)
179    {
180      maxlevel = atol (argv[1]);
181      if (argc > 2)
182	iterations = atol (argv[2]);
183    }
184
185  measure_init ();
186
187  unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
188  doit ("no cache        ");
189
190  unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL);
191  doit ("global cache    ");
192
193  unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD);
194  doit ("per-thread cache");
195
196  return 0;
197}
198