aboutsummaryrefslogtreecommitdiff
blob: 8995ebb23ef247facd8c89e305e11996df972d23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* This testcase is part of GDB, the GNU debugger.

   Copyright 2010-2018 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* This program tests tracepoint speed. It consists of two identical
   loops, which in normal execution will run for exactly the same
   amount of time. A tracepoint in the second loop will slow it down
   by some amount, and then the program will report the slowdown
   observed.  */

/* While primarily designed for the testsuite, it can also be used
   for interactive testing.  */

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>

int trace_speed_test (void);

/* We mark these globals as volatile so the speed-measuring loops
   don't get totally emptied out at high optimization levels.  */

volatile int globfoo, globfoo2, globfoo3;

volatile short globarr[80000];

int init_iters = 10 * 1000;

int iters;

int max_iters = 1000 * 1000 * 1000;

int numtps = 1;

unsigned long long now2, now3, now4, now5;
int total1, total2, idelta, mindelta, nsdelta;
int nspertp = 0;

/* Return CPU usage (both user and system - trap-based tracepoints use
   a bunch of system time).  */

unsigned long long
myclock ()
{
  struct timeval tm;
  gettimeofday (&tm, NULL);
  return (((unsigned long long) tm.tv_sec) * 1000000) + tm.tv_usec;
}

int
main(int argc, char **argv)
{
  int problem;

  iters = init_iters;

  while (1)
    {
      numtps = 1;  /* set pre-run breakpoint here */

      /* Keep trying the speed test, with more iterations, until
	 we get to a reasonable number.  */
      while (problem = trace_speed_test())
	{
	  /* If iteration isn't working, give up.  */
	  if (iters > max_iters)
	    {
	      printf ("Gone over %d iterations, giving up\n", max_iters);
	      break;
	    }
	  if (problem < 0)
	    {
	      printf ("Negative times, giving up\n");
	      break;
	    }

	  iters *= 2;
	  printf ("Doubled iterations to %d\n", iters);
	}

      printf ("Tracepoint time is %d ns\n", nspertp);

      /* This is for the benefit of interactive testing and attaching,
	 keeps the program from pegging the machine.  */
      sleep (1);  /* set post-run breakpoint here */

      /* Issue a little bit of output periodically, so we can see if
	 program is alive or hung.  */
      printf ("%s keeping busy, clock=%llu\n", argv[0], myclock ());
    }
  return 0;
}

int
trace_speed_test (void)
{
  int i;

  /* Overall loop run time deltas under 1 ms are likely noise and
     should be ignored.  */
  mindelta = 1000;

  // The bodies of the two loops following must be identical.

  now2 = myclock ();
  globfoo2 = 1;
  for (i = 0; i < iters; ++i)
    {
      globfoo2 *= 45;
      globfoo2 += globfoo + globfoo3; 
      globfoo2 *= globfoo + globfoo3; 
      globfoo2 -= globarr[4] + globfoo3; 
      globfoo2 *= globfoo + globfoo3; 
      globfoo2 += globfoo + globfoo3; 
    }
  now3 = myclock ();
  total1 = now3 - now2;

  now4 = myclock ();
  globfoo2 = 1;
  for (i = 0; i < iters; ++i)
    {
      globfoo2 *= 45;
      globfoo2 += globfoo + globfoo3;  /* set tracepoint here */
      globfoo2 *= globfoo + globfoo3; 
      globfoo2 -= globarr[4] + globfoo3; 
      globfoo2 *= globfoo + globfoo3; 
      globfoo2 += globfoo + globfoo3; 
    }
  now5 = myclock ();
  total2 = now5 - now4;

  /* Report on the test results.  */

  nspertp = 0;

  idelta = total2 - total1;

  printf ("Loops took %d usec and %d usec, delta is %d usec, %d iterations\n",
	  total1, total2, idelta, iters);

  /* If the second loop seems to run faster, things are weird so give up.  */
  if (idelta < 0)
    return -1;

  if (idelta > mindelta
      /* Total test time should be between 15 and 30 seconds.  */
      && (total1 + total2) > (15 * 1000000)
      && (total1 + total2) < (30 * 1000000))
    {
      nsdelta = (((unsigned long long) idelta) * 1000) / iters;
      printf ("Second loop took %d ns longer per iter than first\n", nsdelta);
      nspertp = nsdelta / numtps;
      printf ("%d ns per tracepoint\n", nspertp);
      printf ("Base iteration time %d ns\n",
	      ((int) (((unsigned long long) total1) * 1000) / iters));
      printf ("Total test time %d secs\n", ((int) ((now5 - now2) / 1000000)));

      /* Speed test ran with no problem.  */
      return 0;
    }

  /* The test run was too brief, or otherwise not useful.  */
  return 1;
}