184 lines
5.0 KiB
C
184 lines
5.0 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2010-2015 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>
|
|
|
|
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, tm2;
|
|
struct rusage ru;
|
|
getrusage (RUSAGE_SELF, &ru);
|
|
tm = ru.ru_utime;
|
|
tm2 = ru.ru_stime;
|
|
return (((unsigned long long) tm.tv_sec) * 1000000) + tm.tv_usec
|
|
+ (((unsigned long long) tm2.tv_sec) * 1000000) + tm2.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", max_iters);
|
|
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 2 and 5 seconds. */
|
|
&& (total1 + total2) > (2 * 1000000)
|
|
&& (total1 + total2) < (5 * 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;
|
|
}
|