blob: 73207027b4a638265c1e03cdb0680707667b784e [file] [log] [blame]
Arun Sharma741a5a22011-03-24 23:47:25 -07001/* 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 <libunwind.h>
30
31#include <sys/resource.h>
32#include <sys/time.h>
33
34#define panic(args...) \
35 do { fprintf (stderr, args); exit (-1); } while (0)
36
37long dummy;
38
39static long iterations = 10000;
40static int maxlevel = 100;
41
42#define KB 1024
43#define MB (1024*1024)
44
45static char big[64*MB]; /* should be >> max. cache size */
46
47static inline double
48gettime (void)
49{
50 struct timeval tv;
51
52 gettimeofday (&tv, NULL);
53 return tv.tv_sec + 1e-6*tv.tv_usec;
54}
55
56static int __attribute__((noinline))
57measure_unwind (int maxlevel, double *step)
58{
59 double stop, start;
60 int level = 0;
61 void *buffer[128];
62
63 start = gettime ();
64 level = backtrace(buffer, 128);
65 stop = gettime ();
66
67 if (level <= maxlevel)
68 panic ("Unwound only %d levels, expected at least %d levels\n",
69 level, maxlevel);
70
71 *step = (stop - start) / (double) level;
72 return 0;
73}
74
75static int f1 (int, int, double *);
76
77static int __attribute__((noinline))
78g1 (int level, int maxlevel, double *step)
79{
80 if (level == maxlevel)
81 return measure_unwind (maxlevel, step);
82 else
83 /* defeat last-call/sibcall optimization */
84 return f1 (level + 1, maxlevel, step) + level;
85}
86
87static int __attribute__((noinline))
88f1 (int level, int maxlevel, double *step)
89{
90 if (level == maxlevel)
91 return measure_unwind (maxlevel, step);
92 else
93 /* defeat last-call/sibcall optimization */
94 return g1 (level + 1, maxlevel, step) + level;
95}
96
97static void
98doit (const char *label)
99{
100 double step, min_step, first_step, sum_step;
101 int i;
102
103 sum_step = first_step = 0.0;
104 min_step = 1e99;
105 for (i = 0; i < iterations; ++i)
106 {
107 f1 (0, maxlevel, &step);
108
109 sum_step += step;
110
111 if (step < min_step)
112 min_step = step;
113
114 if (i == 0)
115 first_step = step;
116 }
117 printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label,
118 1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations);
119}
120
121static long
122sum (void *buf, size_t size)
123{
124 long s = 0;
125 char *cp = buf;
126 size_t i;
127
128 for (i = 0; i < size; i += 8)
129 s += cp[i];
130 return s;
131}
132
133static void
134measure_init (void)
135{
136# define N 100
137# define M 10 /* must be at least 2 to get steady-state */
138 double stop, start, get_cold, get_warm, init_cold, init_warm, delta;
139 struct
140 {
141 unw_cursor_t c;
142 char padding[1024]; /* should be > 2 * max. cacheline size */
143 }
144 cursor[N];
145 struct
146 {
147 unw_context_t uc;
148 char padding[1024]; /* should be > 2 * max. cacheline size */
149 }
150 uc[N];
151 int i, j;
152
153 /* Run each test M times and take the minimum to filter out noise
154 such dynamic linker resolving overhead, context-switches,
155 page-in, cache, and TLB effects. */
156
157 get_cold = 1e99;
158 for (j = 0; j < M; ++j)
159 {
160 dummy += sum (big, sizeof (big)); /* flush the cache */
161 for (i = 0; i < N; ++i)
162 uc[i].padding[511] = i; /* warm up the TLB */
163 start = gettime ();
164 for (i = 0; i < N; ++i)
165 unw_getcontext (&uc[i].uc);
166 stop = gettime ();
167 delta = (stop - start) / N;
168 if (delta < get_cold)
169 get_cold = delta;
170 }
171
172 init_cold = 1e99;
173 for (j = 0; j < M; ++j)
174 {
175 dummy += sum (big, sizeof (big)); /* flush cache */
176 for (i = 0; i < N; ++i)
177 uc[i].padding[511] = i; /* warm up the TLB */
178 start = gettime ();
179 for (i = 0; i < N; ++i)
180 unw_init_local (&cursor[i].c, &uc[i].uc);
181 stop = gettime ();
182 delta = (stop - start) / N;
183 if (delta < init_cold)
184 init_cold = delta;
185 }
186
187 get_warm = 1e99;
188 for (j = 0; j < M; ++j)
189 {
190 start = gettime ();
191 for (i = 0; i < N; ++i)
192 unw_getcontext (&uc[0].uc);
193 stop = gettime ();
194 delta = (stop - start) / N;
195 if (delta < get_warm)
196 get_warm = delta;
197 }
198
199 init_warm = 1e99;
200 for (j = 0; j < M; ++j)
201 {
202 start = gettime ();
203 for (i = 0; i < N; ++i)
204 unw_init_local (&cursor[0].c, &uc[0].uc);
205 stop = gettime ();
206 delta = (stop - start) / N;
207 if (delta < init_warm)
208 init_warm = delta;
209 }
210
211 printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
212 1e9 * get_cold, 1e9 * get_warm);
213 printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
214 1e9 * init_cold, 1e9 * init_warm);
215}
216
217int
218main (int argc, char **argv)
219{
220 struct rlimit rlim;
221
222 rlim.rlim_cur = RLIM_INFINITY;
223 rlim.rlim_max = RLIM_INFINITY;
224 setrlimit (RLIMIT_STACK, &rlim);
225
226 memset (big, 0xaa, sizeof (big));
227
228 if (argc > 1)
229 {
230 maxlevel = atol (argv[1]);
231 if (argc > 2)
232 iterations = atol (argv[2]);
233 }
234
235 measure_init ();
236
237 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
238 doit ("no cache ");
239
240 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL);
241 doit ("global cache ");
242
243 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD);
244 doit ("per-thread cache");
245
246 return 0;
247}