blob: 7c2cc99666a86a3e475426acae4105031557cbda [file] [log] [blame]
mostang.com!davidme1da7182004-01-21 06:36:35 +00001/* 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
mostang.com!davidm96c62502004-03-27 09:25:58 +000024#include <memory.h>
mostang.com!davidm12876ef2003-09-24 05:02:14 +000025#include <stdio.h>
26#include <stdlib.h>
hp.com!davidm3be31f52004-03-30 22:57:06 +000027#include <unistd.h>
mostang.com!davidm12876ef2003-09-24 05:02:14 +000028
mostang.com!davidm12876ef2003-09-24 05:02:14 +000029#include <libunwind.h>
30
hp.com!davidm3be31f52004-03-30 22:57:06 +000031#include <sys/resource.h>
mostang.com!davidm50c2be02004-03-31 07:29:27 +000032#include <sys/time.h>
hp.com!davidm3be31f52004-03-30 22:57:06 +000033
mostang.com!davidm12876ef2003-09-24 05:02:14 +000034#define panic(args...) \
35 do { fprintf (stderr, args); exit (-1); } while (0)
36
mostang.com!davidm96c62502004-03-27 09:25:58 +000037long dummy;
38
mostang.com!davidmc7fdc722004-03-20 09:54:28 +000039static long iterations = 10000;
hp.com!davidm5e446b22003-11-27 06:52:54 +000040static int maxlevel = 100;
41
hp.com!davidm3be31f52004-03-30 22:57:06 +000042#define KB 1024
mostang.com!davidm96c62502004-03-27 09:25:58 +000043#define MB (1024*1024)
44
hp.com!davidm3be31f52004-03-30 22:57:06 +000045static char big[64*MB]; /* should be >> max. cache size */
mostang.com!davidm96c62502004-03-27 09:25:58 +000046
mostang.com!davidm12876ef2003-09-24 05:02:14 +000047static inline double
48gettime (void)
49{
mostang.com!davidme3eae742004-03-31 01:53:04 +000050 struct timeval tv;
mostang.com!davidm12876ef2003-09-24 05:02:14 +000051
mostang.com!davidme3eae742004-03-31 01:53:04 +000052 gettimeofday (&tv, NULL);
53 return tv.tv_sec + 1e-6*tv.tv_usec;
mostang.com!davidm12876ef2003-09-24 05:02:14 +000054}
55
56static int
mostang.com!davidm96c62502004-03-27 09:25:58 +000057measure_unwind (int maxlevel, double *step)
mostang.com!davidm12876ef2003-09-24 05:02:14 +000058{
mostang.com!davidm96c62502004-03-27 09:25:58 +000059 double stop, start;
mostang.com!davidm12876ef2003-09-24 05:02:14 +000060 unw_cursor_t cursor;
61 unw_context_t uc;
62 int ret, level = 0;
63
mostang.com!davidm12876ef2003-09-24 05:02:14 +000064 unw_getcontext (&uc);
65 if (unw_init_local (&cursor, &uc) < 0)
66 panic ("unw_init_local() failed\n");
67
mostang.com!davidm96c62502004-03-27 09:25:58 +000068 start = gettime ();
mostang.com!davidm12876ef2003-09-24 05:02:14 +000069
70 do
71 {
72 ret = unw_step (&cursor);
73 if (ret < 0)
74 panic ("unw_step() failed\n");
75 ++level;
76 }
77 while (ret > 0);
78
79 stop = gettime ();
80
81 if (level <= maxlevel)
82 panic ("Unwound only %d levels, expected at least %d levels",
83 level, maxlevel);
84
mostang.com!davidm96c62502004-03-27 09:25:58 +000085 *step = (stop - start) / (double) level;
hp.com!davidm29f2f892003-09-25 05:29:14 +000086 return 0;
mostang.com!davidm12876ef2003-09-24 05:02:14 +000087}
88
89static int
mostang.com!davidm96c62502004-03-27 09:25:58 +000090f1 (int level, int maxlevel, double *step)
mostang.com!davidm12876ef2003-09-24 05:02:14 +000091{
92 if (level == maxlevel)
mostang.com!davidm96c62502004-03-27 09:25:58 +000093 return measure_unwind (maxlevel, step);
mostang.com!davidm12876ef2003-09-24 05:02:14 +000094 else
95 /* defeat last-call/sibcall optimization */
mostang.com!davidm96c62502004-03-27 09:25:58 +000096 return f1 (level + 1, maxlevel, step) + level;
hp.com!davidm5e446b22003-11-27 06:52:54 +000097}
98
99static void
100doit (const char *label)
101{
mostang.com!davidm96c62502004-03-27 09:25:58 +0000102 double step, min_step, first_step, sum_step;
hp.com!davidm5e446b22003-11-27 06:52:54 +0000103 int i;
104
mostang.com!davidm96c62502004-03-27 09:25:58 +0000105 sum_step = first_step = 0.0;
106 min_step = 1e99;
mostang.com!davidmc7fdc722004-03-20 09:54:28 +0000107 for (i = 0; i < iterations; ++i)
hp.com!davidm5e446b22003-11-27 06:52:54 +0000108 {
mostang.com!davidm96c62502004-03-27 09:25:58 +0000109 f1 (0, maxlevel, &step);
hp.com!davidm5e446b22003-11-27 06:52:54 +0000110
hp.com!davidm5e446b22003-11-27 06:52:54 +0000111 sum_step += step;
112
hp.com!davidm5e446b22003-11-27 06:52:54 +0000113 if (step < min_step)
114 min_step = step;
115
116 if (i == 0)
mostang.com!davidm96c62502004-03-27 09:25:58 +0000117 first_step = step;
hp.com!davidm5e446b22003-11-27 06:52:54 +0000118 }
mostang.com!davidm96c62502004-03-27 09:25:58 +0000119 printf ("%s: unw_step : 1st=%9.3f min=%9.3f avg=%9.3f nsec\n", label,
mostang.com!davidmc7fdc722004-03-20 09:54:28 +0000120 1e9*first_step, 1e9*min_step, 1e9*sum_step/iterations);
mostang.com!davidm12876ef2003-09-24 05:02:14 +0000121}
122
mostang.com!davidm96c62502004-03-27 09:25:58 +0000123static long
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000124sum (void *buf, size_t size)
mostang.com!davidm96c62502004-03-27 09:25:58 +0000125{
126 long s = 0;
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000127 char *cp = buf;
mostang.com!davidm96c62502004-03-27 09:25:58 +0000128 size_t i;
129
hp.com!davidm3be31f52004-03-30 22:57:06 +0000130 for (i = 0; i < size; i += 8)
131 s += cp[i];
mostang.com!davidm96c62502004-03-27 09:25:58 +0000132 return s;
133}
134
135static void
136measure_init (void)
137{
hp.com!davidm3be31f52004-03-30 22:57:06 +0000138# define N 100
mostang.com!davidm50c2be02004-03-31 07:29:27 +0000139# define M 10 /* must be at least 2 to get steady-state */
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000140 double stop, start, get_cold, get_warm, init_cold, init_warm, delta;
hp.com!davidm3be31f52004-03-30 22:57:06 +0000141 struct
142 {
143 unw_cursor_t c;
144 char padding[1024]; /* should be > 2 * max. cacheline size */
145 }
146 cursor[N];
147 struct
148 {
149 unw_context_t uc;
150 char padding[1024]; /* should be > 2 * max. cacheline size */
151 }
152 uc[N];
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000153 int i, j;
mostang.com!davidm96c62502004-03-27 09:25:58 +0000154
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000155 /* Run each test M times and take the minimum to filter out noise
156 such dynamic linker resolving overhead, context-switches,
157 page-in, cache, and TLB effects. */
mostang.com!davidm96c62502004-03-27 09:25:58 +0000158
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000159 get_cold = 1e99;
160 for (j = 0; j < M; ++j)
161 {
hp.com!davidm3be31f52004-03-30 22:57:06 +0000162 dummy += sum (big, sizeof (big)); /* flush the cache */
163 for (i = 0; i < N; ++i)
164 uc[i].padding[511] = i; /* warm up the TLB */
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000165 start = gettime ();
166 for (i = 0; i < N; ++i)
hp.com!davidm3be31f52004-03-30 22:57:06 +0000167 unw_getcontext (&uc[i].uc);
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000168 stop = gettime ();
169 delta = (stop - start) / N;
170 if (delta < get_cold)
171 get_cold = delta;
172 }
hp.com!davidm3be31f52004-03-30 22:57:06 +0000173
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000174 init_cold = 1e99;
175 for (j = 0; j < M; ++j)
176 {
177 dummy += sum (big, sizeof (big)); /* flush cache */
hp.com!davidm3be31f52004-03-30 22:57:06 +0000178 for (i = 0; i < N; ++i)
179 uc[i].padding[511] = i; /* warm up the TLB */
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000180 start = gettime ();
181 for (i = 0; i < N; ++i)
hp.com!davidm3be31f52004-03-30 22:57:06 +0000182 unw_init_local (&cursor[i].c, &uc[i].uc);
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000183 stop = gettime ();
184 delta = (stop - start) / N;
185 if (delta < init_cold)
186 init_cold = delta;
187 }
mostang.com!davidm96c62502004-03-27 09:25:58 +0000188
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000189 get_warm = 1e99;
190 for (j = 0; j < M; ++j)
191 {
192 start = gettime ();
193 for (i = 0; i < N; ++i)
hp.com!davidm3be31f52004-03-30 22:57:06 +0000194 unw_getcontext (&uc[0].uc);
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000195 stop = gettime ();
196 delta = (stop - start) / N;
197 if (delta < get_warm)
198 get_warm = delta;
199 }
mostang.com!davidm96c62502004-03-27 09:25:58 +0000200
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000201 init_warm = 1e99;
202 for (j = 0; j < M; ++j)
203 {
204 start = gettime ();
205 for (i = 0; i < N; ++i)
hp.com!davidm3be31f52004-03-30 22:57:06 +0000206 unw_init_local (&cursor[0].c, &uc[0].uc);
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000207 stop = gettime ();
208 delta = (stop - start) / N;
209 if (delta < init_warm)
210 init_warm = delta;
211 }
mostang.com!davidm96c62502004-03-27 09:25:58 +0000212
213 printf ("unw_getcontext : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
mostang.com!davidmfc7b49b2004-03-28 00:24:33 +0000214 1e9 * get_cold, 1e9 * get_warm);
mostang.com!davidm96c62502004-03-27 09:25:58 +0000215 printf ("unw_init_local : cold avg=%9.3f nsec, warm avg=%9.3f nsec\n",
216 1e9 * init_cold, 1e9 * init_warm);
217}
218
mostang.com!davidm12876ef2003-09-24 05:02:14 +0000219int
220main (int argc, char **argv)
221{
hp.com!davidm3be31f52004-03-30 22:57:06 +0000222 struct rlimit rlim;
223
224 rlim.rlim_cur = RLIM_INFINITY;
225 rlim.rlim_max = RLIM_INFINITY;
226 setrlimit (RLIMIT_STACK, &rlim);
227
228 memset (big, 0xaa, sizeof (big));
229
mostang.com!davidm12876ef2003-09-24 05:02:14 +0000230 if (argc > 1)
mostang.com!davidmc7fdc722004-03-20 09:54:28 +0000231 {
232 maxlevel = atol (argv[1]);
233 if (argc > 2)
234 iterations = atol (argv[2]);
235 }
mostang.com!davidm12876ef2003-09-24 05:02:14 +0000236
mostang.com!davidm96c62502004-03-27 09:25:58 +0000237 measure_init ();
238
mostang.com!davidm7a346fb2003-11-20 01:10:03 +0000239 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
mostang.com!davidm96c62502004-03-27 09:25:58 +0000240 doit ("no cache ");
mostang.com!davidm7a346fb2003-11-20 01:10:03 +0000241
mostang.com!davidm7a346fb2003-11-20 01:10:03 +0000242 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL);
mostang.com!davidm96c62502004-03-27 09:25:58 +0000243 doit ("global cache ");
mostang.com!davidm7a346fb2003-11-20 01:10:03 +0000244
mostang.com!davidm7a346fb2003-11-20 01:10:03 +0000245 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD);
mostang.com!davidm96c62502004-03-27 09:25:58 +0000246 doit ("per-thread cache");
hp.com!davidm5e446b22003-11-27 06:52:54 +0000247
mostang.com!davidm12876ef2003-09-24 05:02:14 +0000248 return 0;
249}