C99 and GMP tuning
Vincent Lefevre
vincent at vinc17.net
Tue Apr 10 12:27:47 UTC 2018
First, I've attached a new version of my clock-times.c program
(note: it was initially written to measure the performance of
the time functions, but it can also be used to get resolution
and accuracy information by providing a second argument, like
1.000000001).
On 2018-04-09 17:45:16 +0200, Torbjorn Granlund wrote:
> sav_ix at ukr.net writes:
>
> Presumably this should lead to dropping support of old systems, which
> compilers do not provide C99 support. On the other side, more recent
> OSes provide better 'clock()' implementation, which accuracy
> (depending of used OS) in times or magnitudes better, compared to
> 'getrusage()'.
>
> After moving to C99, can GMP Developers consider to drop use of non
> portable 'getrusage()', 'rusage' etc. in favor of 'clock()'? The
> advantage in addition to portability could be that the running time of
> the tuning be shortened (need be verified).
>
> This seems completely unrelated to C90 vs C99.
>
> I also think you're wrong. If you are aware of a specific system where
> clock() is more accurate than getrusage, then let us know. But please
> don't base that on beliefs, instead check that it is actually the case.
Here's an example, on a Debian GNU/Linux 8 (jessie) machine:
patate:.../testcases/c-impl> ./clock-times clock 1.000000001
Clock units per second: 1000000
Number of calls: 3674488 (1.000001 s)
Number of calls: 7326182 (2.000001 s)
Number of calls: 10974092 (3 s)
patate:.../testcases/c-impl> ./clock-times getrusage 1.000000001
Number of calls: 20205917 (1.004 s)
Number of calls: 39477071 (2.004 s)
Number of calls: 57081362 (3 s)
This is still the case even on a Debian GNU/Linux 9 (stretch)
machine, i.e. with the latest Debian/stable:
joooj:.../testcases/c-impl> ./clock-times clock 1.000000001
Clock units per second: 1000000
Number of calls: 297212 (1.000003 s)
Number of calls: 588038 (2.000003 s)
Number of calls: 886368 (3.000002 s)
joooj:.../testcases/c-impl> ./clock-times getrusage 1.000000001
Number of calls: 709220 (1.004 s)
Number of calls: 1346154 (2.004 s)
Number of calls: 2043699 (3 s)
With Debian/unstable, this is equivalent:
cventin:.../testcases/c-impl> ./clock-times clock 1.000000001
Clock units per second: 1000000
Number of calls: 1706929 (1.000001 s)
Number of calls: 3423555 (2.000001 s)
Number of calls: 5140163 (3 s)
cventin:.../testcases/c-impl> ./clock-times getrusage 1.000000001
Number of calls: 6191249 (1.000001 s)
Number of calls: 12118336 (2.000001 s)
Number of calls: 18049410 (3 s)
So, on these examples, clock may win compared to getrusage,
but it does not lose.
--
Vincent Lefèvre <vincent at vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
-------------- next part --------------
/* Performance of clock(), times() and clock_gettime() function calls.
*
* Usage: clock-times <type> [ <num> ]
* where <type> is the type of the clock (see the code below) and
* <num> is the interval between two outputs; if set to something
* like 1.000000001, this also allows one to have an idea on the
* accuracy. By default, the test is done on 3 seconds (either the
* CPU time or the wall-clock time, depending on the type); this
* can be changed by compiling with -DNSEC=... (but in practice,
* dealing with <num> should be sufficient).
*
* When comparing the results, be aware of the difference between
* the CPU time and the wall-clock time if the process doesn't take
* 100% CPU time!
*
* Man pages under Linux:
* time(7) - overview of time and timers
* clock(3), clock(3posix) - report CPU time used
* times(2), times(3posix) - get process times
* clock_getres(2), clock_getres(3posix) - clock and timer functions
* (clock_getres, clock_gettime, clock_settime)
* getrusage(2), getrusage(3posix) - get resource usage
* gettimeofday(2), gettimeofday(3posix) - get the date and time
*
* See also: http://stackoverflow.com/q/12392278/3782797 (Measure time
* in Linux - getrusage vs clock_gettime vs clock vs gettimeofday?) and
* https://www.gnu.org/software/libc/manual/html_node/Date-and-Time.html
* specifically for GNU systems.
*
* Note: Using clock() may not be a good idea, except for portability,
* since the result includes the system time (on GNU systems), which
* generally depends on external events. However, in most cases, the
* system time should remain much smaller than the user time.
* About user time vs system time:
* http://stackoverflow.com/q/556405/3782797
*
* TODO: add times-u (user time) and times-c (cumulated user+sys times).
*/
#define SVNID "$Id: clock-times.c 107487 2018-04-10 11:37:32Z vinc17/cventin $"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> /* for sysconf() */
#include <time.h> /* for clock() - processor time */
#include <sys/times.h> /* for times() - real time */
#include <sys/resource.h> /* for getrusage() */
#ifndef NSEC
#define NSEC 3
#endif
static inline double tsdiff (struct timespec t1, struct timespec t0)
{
return (t1.tv_sec - t0.tv_sec + ((double) t1.tv_nsec - t0.tv_nsec) / 1e9);
}
static inline double tvdiff (struct timeval t1, struct timeval t0)
{
return (t1.tv_sec - t0.tv_sec + ((double) t1.tv_usec - t0.tv_usec) / 1e6);
}
static inline void out (unsigned long ncalls, double t)
{
static unsigned long old_ncalls = 0;
if (ncalls != old_ncalls)
{
printf ("Number of calls: %lu (%.12g s)\n", ncalls, (t));
old_ncalls = ncalls;
}
}
#define LOOP(T,DIFF) \
do \
{ \
T c0, c; \
int n = 1; \
\
ncalls = 1; \
F(c0); \
do \
{ \
ncalls++; \
F(c); \
t = (DIFF); \
if (d >= 0 && t >= n * d) \
{ \
out (ncalls, t); \
n++; \
} \
} \
while (t < NSEC); \
} \
while (0)
/* See /usr/include/linux/time.h */
struct { clockid_t id; char *s; } clocks[] =
{
{ CLOCK_REALTIME, "REALTIME" },
#ifdef CLOCK_MONOTONIC
{ CLOCK_MONOTONIC, "MONOTONIC" },
#endif
#ifdef CLOCK_REALTIME_COARSE
{ CLOCK_REALTIME_COARSE, "REALTIME_COARSE" },
#endif
#ifdef CLOCK_MONOTONIC_COARSE
{ CLOCK_MONOTONIC_COARSE, "MONOTONIC_COARSE" },
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
{ CLOCK_PROCESS_CPUTIME_ID, "PROCESS_CPUTIME_ID" },
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
{ CLOCK_THREAD_CPUTIME_ID, "THREAD_CPUTIME_ID" },
#endif
};
static void err (const char *s)
{
int errnum = errno;
fprintf (stderr, "clock-times: %s failed (%s)\n", s, strerror (errnum));
exit (2);
}
int main (int argc, char **argv)
{
unsigned long ncalls;
double d = -1, t;
if (argc != 2 && argc != 3)
{
usage:
fprintf (stderr, "Usage: clock-times "
"\"clock\" | \"times\" | \"CLOCK_\"... [ num ]\n");
return 1;
}
if (argc == 3)
{
char *end;
d = strtod (argv[2], &end);
}
if (strcmp (argv[1], "clock") == 0)
{
#undef F
#define F(C) C = clock ()
printf ("Clock units per second: %.8g\n", (double) CLOCKS_PER_SEC);
LOOP (double, (c - c0) / CLOCKS_PER_SEC);
}
else if (strcmp (argv[1], "getrusage") == 0) /* user time only */
{
struct rusage usage;
#undef F
#define F(C) \
do \
{ \
if (getrusage (RUSAGE_SELF, &usage)) \
err ("getrusage"); \
C = usage.ru_utime; \
} \
while (0);
LOOP (struct timeval, tvdiff (c, c0));
}
else if (strcmp (argv[1], "times") == 0)
{
struct tms buffer;
clock_t clock_ticks;
#undef F
#define F(C) C = times (&buffer)
/* Note: here we retrieve the wall-clock time! */
clock_ticks = sysconf (_SC_CLK_TCK);
printf ("Clock units per second: %.8g\n", (double) clock_ticks);
LOOP (double, (c - c0) / clock_ticks);
}
else if (strncmp (argv[1], "CLOCK_", 6) == 0)
{
clockid_t clk_id;
char *ptr = argv[1] + 6, *endptr, *s = NULL;
if (*ptr != '\0' &&
(clk_id = strtol (argv[1] + 6, &endptr, 10), *endptr == '\0'))
{
int i;
for (i = 0; i < sizeof clocks / sizeof clocks[0]; i++)
if (clocks[i].id == clk_id)
{
s = clocks[i].s;
goto id_ok;
}
}
else
{
int i;
for (i = 0; i < sizeof clocks / sizeof clocks[0]; i++)
if (strcmp (clocks[i].s, ptr) == 0)
{
clk_id = clocks[i].id;
s = clocks[i].s;
goto id_ok;
}
fprintf (stderr, "clock-times: unknown clock_gettime clock type\n");
return 1;
}
id_ok:
{
struct timespec c;
if (clock_getres (clk_id, &c))
err ("clock_getres");
printf ("Clock resolution (id %ld [CLOCK_%s]): ",
(long) clk_id, s ? s : "?");
if (c.tv_sec)
printf ("%ld.%09ld s\n", (long) c.tv_sec, c.tv_nsec);
else
printf ("%ld ns\n", c.tv_nsec);
}
#undef F
#define F(C) clock_gettime (clk_id, &C) && (err ("clock_gettime"), 0)
LOOP (struct timespec, tsdiff (c, c0));
}
else
goto usage;
out (ncalls, t);
return 0;
}
More information about the gmp-discuss
mailing list