| /* This testcase is part of GDB, the GNU debugger. |
| |
| Copyright 2010-2017 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; |
| 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", 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 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; |
| } |