Reorder and renovate timer functions taking into account ngspice multiprocessor capabilities

by using available high performance functions first.
Deprecated ftime() still acts as a backup function.
Solution is portable for today's operating systems and compilers.
This commit is contained in:
dwarning 2024-10-18 17:50:30 +02:00 committed by Holger Vogt
parent a42ea98471
commit 3faed1647a
8 changed files with 169 additions and 157 deletions

View File

@ -906,12 +906,12 @@ AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stddef.h sys/file.h sys/param
# Check time and resources headers and functions:
AC_STRUCT_TM
AC_STRUCT_TIMEZONE
AC_CHECK_FUNCS([localtime])
AC_CHECK_FUNCS([time localtime])
AC_CHECK_FUNCS([ftime gettimeofday])
# Do not use time or getrusage function for CPU time measurement under OpenMP
AC_CHECK_FUNCS([queryperformancecounter clock_gettime gettimeofday ftime])
# Do not use times or getrusage function for CPU time measurement under OpenMP
if test "x$enable_openmp" = xno; then
AC_CHECK_FUNCS([time getrusage])
AC_CHECK_FUNCS([times getrusage])
fi
AC_CHECK_FUNCS([utimes])
AC_CHECK_FUNCS([getrlimit ulimit], [break])

View File

@ -77,19 +77,13 @@ init_rlimits(void)
ft_ckspace();
}
PerfTimer timer;
void
init_time(void)
{
#ifdef HAVE_GETRUSAGE
#else
# ifdef HAVE_TIMES
# else
# ifdef HAVE_FTIME
ftime(&timebegin);
# endif
# endif
#endif
perf_timer_get_time(&timebegin);
perf_timer_start(&timer);
}
@ -169,38 +163,33 @@ printres(char *name)
if (!name || eq(name, "totalcputime") || eq(name, "cputime")) {
int total_sec, total_msec;
# ifdef HAVE_GETRUSAGE
int ret;
struct rusage ruse;
memset(&ruse, 0, sizeof(ruse));
ret = getrusage(RUSAGE_SELF, &ruse);
if (ret == -1)
perror("getrusage(): ");
#if defined (USE_OMP) \
|| defined (HAVE_QUERYPERFORMANCECOUNTER) || defined(HAVE_CLOCK_GETTIME) \
|| defined (HAVE_GETTIMEOFDAY) || defined(HAVE_TIMES) \
|| defined (HAVE_GETRUSAGE) || defined(HAVE_FTIME)
total_sec = (int) (ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec);
total_msec = (int) (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec) / 1000;
cpu_elapsed = "CPU";
# else
# ifdef HAVE_TIMES
struct tms ruse;
times(&ruse);
clock_t x = ruse.tms_utime + ruse.tms_stime;
clock_t hz = (clock_t) sysconf(_SC_CLK_TCK);
total_sec = x / hz;
total_msec = ((x % hz) * 1000) / hz;
cpu_elapsed = "CPU";
# else
# ifdef HAVE_FTIME
struct timeb timenow;
ftime(&timenow);
timediff(&timenow, &timebegin, &total_sec, &total_msec);
perf_timer_stop(&timer);
perf_timer_elapsed_sec_ms(&timer, &total_sec, &total_msec);
#ifdef USE_OMP
cpu_elapsed = "elapsed";
# else
# define NO_RUDATA
# endif
# endif
# endif
#elif defined(HAVE_QUERYPERFORMANCECOUNTER)
cpu_elapsed = "elapsed";
#elif defined(HAVE_CLOCK_GETTIME)
cpu_elapsed = "elapsed";
#elif defined(HAVE_GETTIMEOFDAY)
cpu_elapsed = "elapsed";
#elif defined(HAVE_TIMES)
cpu_elapsed = "CPU";
#elif defined(HAVE_GETRUSAGE)
cpu_elapsed = "CPU";
#elif defined(HAVE_FTIME)
cpu_elapsed = "elapsed";
#endif
#else
# define NO_RUDATA
#endif
#ifndef NO_RUDATA

View File

@ -117,15 +117,17 @@
# include <sys/time.h>
# include <sys/resource.h>
# endif
#else
# ifdef HAVE_TIMES
# include <sys/times.h>
# include <sys/param.h>
# else
# ifdef HAVE_FTIME
# include <sys/timeb.h>
# endif
# endif
#endif
#ifdef HAVE_TIMES
# include <sys/times.h>
# include <sys/param.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
# include <sys/time.h>
#endif
#ifdef HAVE_FTIME
# include <sys/timeb.h>
#endif
#ifdef HAVE_UNISTD_H

View File

@ -8,35 +8,28 @@ Copyright 1990 Regents of the University of California. All rights reserved.
#include "ngspice/ngspice.h"
#include <string.h>
#if defined(HAS_WINGUI) || defined(__MINGW32__) || defined(_MSC_VER)
#ifdef HAVE_QUERYPERFORMANCECOUNTER
#define WIN32_LEAN_AND_MEAN
/*
* The ngspice.h file included above defines BOOLEAN (via bool.h) and this
* clashes with the definition obtained from windows.h (via winnt.h).
* However, BOOLEAN is not used by this file so we can work round this problem
* by undefining BOOLEAN before including windows.h
* SJB - April 2005
*/
#undef BOOLEAN
#include <windows.h>
#endif
#endif
#include "misc_time.h"
#ifdef HAVE_LOCALTIME
#include <time.h>
#ifdef USE_OMP
#include <omp.h>
#endif
#ifdef HAVE_GETRUSAGE
# include <sys/types.h>
# include <sys/time.h>
# include <sys/resource.h>
#else
# ifdef HAVE_TIMES
# include <sys/types.h>
# include <sys/times.h>
# include <sys/param.h>
# else
# ifdef HAVE_FTIME
/* default to ftime if we can't get real CPU times */
# include <sys/types.h>
# include <sys/timeb.h>
# endif
# endif
#endif
#ifdef HAVE_FTIME
# include <sys/timeb.h>
#endif
/* Return the date. Return value is static data. */
char *
@ -68,15 +61,13 @@ datestring(void)
/* return time interval in seconds and milliseconds */
#ifdef HAVE_FTIME
PerfTime timebegin;
struct timeb timebegin;
void timediff(struct timeb *now, struct timeb *begin, int *sec, int *msec)
void timediff(PerfTime *now, PerfTime *begin, int *sec, int *msec)
{
*msec = (int) now->millitm - (int) begin->millitm;
*sec = (int) now->time - (int) begin->time;
*msec = (int) now->milliseconds - (int) begin->milliseconds;
*sec = (int) now->seconds - (int) begin->seconds;
if (*msec < 0) {
*msec += 1000;
(*sec)--;
@ -85,8 +76,6 @@ void timediff(struct timeb *now, struct timeb *begin, int *sec, int *msec)
}
#endif
/*
* How many seconds have elapsed in running time.
* This is the routine called in IFseconds
@ -95,39 +84,65 @@ void timediff(struct timeb *now, struct timeb *begin, int *sec, int *msec)
double
seconds(void)
{
#ifdef HAVE_GETRUSAGE
int ret;
struct rusage ruse;
memset(&ruse, 0, sizeof(ruse));
ret = getrusage(RUSAGE_SELF, &ruse);
if(ret == -1) {
perror("getrusage(): ");
return 1;
}
return ((double)ruse.ru_utime.tv_sec + (double) ruse.ru_utime.tv_usec / 1000000.0);
#ifdef USE_OMP
// Usage of OpenMP time function
return omp_get_wtime();
#elif defined(HAVE_QUERYPERFORMANCECOUNTER)
// Windows (MSC and mingw) specific implementation
LARGE_INTEGER frequency, counter;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&counter);
return (double)counter.QuadPart / frequency.QuadPart;
#elif defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec / 1e9;
#elif defined(HAVE_GETTIMEOFDAY)
// Usage of gettimeofday
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1e6;
#elif defined(HAVE_TIMES)
// Usage of times
struct tms t;
clock_t ticks = times(&t);
return (double)ticks / sysconf(_SC_CLK_TCK);
#elif defined(HAVE_GETRUSAGE)
// Usage of getrusage
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
return usage.ru_utime.tv_sec + usage.ru_utime.tv_usec / 1e6;
#elif defined(HAVE_FTIME)
// Usage of ftime
struct timeb tb;
ftime(&tb);
return tb.time + tb.millitm / 1000.0;
#else
#ifdef HAVE_TIMES
struct tms tmsbuf;
times(&tmsbuf);
return((double) tmsbuf.tms_utime / HZ);
#else
#ifdef HAVE_FTIME
struct timeb timenow;
int sec, msec;
ftime(&timenow);
timediff(&timenow, &timebegin, &sec, &msec);
return(sec + (double) msec / 1000.0);
#else /* unknown */
/* don't know how to do this in general. */
return(-1.0); /* Obvious error condition */
#endif /* !FTIME */
#endif /* !SYSV */
#endif /* !BSD */
#error "No timer function available."
#endif
}
void perf_timer_start(PerfTimer *timer)
{
timer->start = seconds();
}
void perf_timer_stop(PerfTimer *timer)
{
timer->end = seconds();
}
void perf_timer_elapsed_sec_ms(const PerfTimer *timer, int *seconds, int *milliseconds)
{
double elapsed = timer->end - timer->start;
*seconds = (int)elapsed;
*milliseconds = (int)((elapsed - *seconds) * 1000.0);
}
void perf_timer_get_time(PerfTime *time)
{
double secs = seconds();
time->seconds = (int)secs;
time->milliseconds = (int)((secs - time->seconds) * 1000.0);
}

View File

@ -9,12 +9,23 @@
char * datestring(void);
double seconds(void);
#ifdef HAVE_FTIME
typedef struct {
double start;
double end;
} PerfTimer;
extern struct timeb timebegin;
typedef struct {
int seconds;
int milliseconds;
} PerfTime;
void timediff(struct timeb *, struct timeb *, int *, int *);
#endif
void perf_timer_start(PerfTimer *);
void perf_timer_stop(PerfTimer *);
void perf_timer_elapsed_sec_ms(const PerfTimer *, int *, int *);
void perf_timer_get_time(PerfTime *);
extern PerfTime timebegin;
void timediff(PerfTime *, PerfTime *, int *, int *);
#endif

View File

@ -155,10 +155,6 @@ static bool cont_condition;
#include "ngspice/stringskip.h"
#include "frontend/variable.h"
#ifdef HAVE_FTIME
#include <sys/timeb.h>
#endif
/* To interupt a spice run */
#include <signal.h>
typedef void (*sighandler)(int);
@ -1908,26 +1904,32 @@ void SetAnalyse(
static unsigned int ng_id1 = 0, ng_id2 = 0;
bool thread1;
#ifdef HAVE_FTIME
struct timeb timenow; /* actual time stamp */
#if defined (USE_OMP) \
|| defined (HAVE_QUERYPERFORMANCECOUNTER) \
|| defined (HAVE_CLOCK_GETTIME) \
|| defined (HAVE_GETTIMEOFDAY) \
|| defined (HAVE_TIMES) \
|| defined (HAVE_GETRUSAGE) \
|| defined (HAVE_FTIME)
PerfTime timenow; /* actual time stamp */
int diffsec, diffmillisec; /* differences actual minus prev. time stamp */
int result; /* return value from callback function */
char* s; /* outputs to callback function */
int OldPercent; /* Previous progress value */
char OldAn[128]; /* Previous analysis type */
char olds[128]; /* previous output */
static struct timeb timebefore; /* previous time stamp */
static PerfTime timebefore; /* previous time stamp */
/* thread 1 */
static int OldPercent1 = -2; /* Previous progress value */
static char OldAn1[128]; /* Previous analysis type */
static char olds1[128]; /* previous output */
static struct timeb timebefore1; /* previous time stamp */
static PerfTime timebefore1; /* previous time stamp */
/* thread2 */
static int OldPercent2 = -2; /* Previous progress value */
static char OldAn2[128]; /* Previous analysis type */
static char olds2[128]; /* previous output */
static struct timeb timebefore2; /* previous time stamp */
static PerfTime timebefore2; /* previous time stamp */
/*set the two thread ids */
unsigned int ng_idl = threadid_self();
@ -1945,20 +1947,16 @@ void SetAnalyse(
strcpy(OldAn, OldAn1);
strcpy(olds, olds1);
OldPercent = OldPercent1;
timebefore.dstflag = timebefore1.dstflag;
timebefore.millitm = timebefore1.millitm;
timebefore.time = timebefore1.time;
timebefore.timezone = timebefore1.timezone;
timebefore.milliseconds = timebefore1.milliseconds;
timebefore.seconds = timebefore1.seconds;
}
else if (ng_idl == ng_id2) {
thread1 = FALSE;
strcpy(OldAn, OldAn2);
strcpy(olds, olds2);
OldPercent = OldPercent2;
timebefore.dstflag = timebefore2.dstflag;
timebefore.millitm = timebefore2.millitm;
timebefore.time = timebefore2.time;
timebefore.timezone = timebefore2.timezone;
timebefore.milliseconds = timebefore2.milliseconds;
timebefore.seconds = timebefore2.seconds;
}
else
return;
@ -1972,7 +1970,7 @@ void SetAnalyse(
return;
/* get actual time */
ftime(&timenow);
perf_timer_get_time(&timenow);
timediff(&timenow, &timebefore, &diffsec, &diffmillisec);
s = TMALLOC(char, 128);
@ -2023,16 +2021,12 @@ void SetAnalyse(
sprintf( s, "%s: %3.1f%%", Analyse, (double)DecaPercent/10.);
}
if (thread1) {
timebefore1.dstflag = timenow.dstflag;
timebefore1.millitm = timenow.millitm;
timebefore1.time = timenow.time;
timebefore1.timezone = timenow.timezone;
timebefore1.milliseconds = timenow.milliseconds;
timebefore1.seconds = timenow.seconds;
}
else {
timebefore2.dstflag = timenow.dstflag;
timebefore2.millitm = timenow.millitm;
timebefore2.time = timenow.time;
timebefore2.timezone = timenow.timezone;
timebefore2.milliseconds = timenow.milliseconds;
timebefore2.seconds = timenow.seconds;
}
/* info when previous analysis period has finished */
if (strcmp(OldAn, Analyse)) {

View File

@ -38,7 +38,7 @@
#include "hist_info.h" /* history management */
#include "ngspice/bool.h" /* bool defined as unsigned char */
#include "misc/misc_time.h" /* timediff */
#include "misc/misc_time.h" /* timer functions and structure */
#include "ngspice/memory.h" /* TMALLOC */
#include "winmain.h"
@ -220,8 +220,8 @@ SetAnalyse(char *Analyse, /* in: analysis type */
static int OldPercent = -2; /* Previous progress value */
static char OldAn[128]; /* Previous analysis type */
char s[128], t[128]; /* outputs to analysis window and task bar */
static struct timeb timebefore; /* previous time stamp */
struct timeb timenow; /* actual time stamp */
static PerfTime timebefore; /* previous time stamp */
PerfTime timenow; /* actual time stamp */
int diffsec, diffmillisec; /* differences actual minus prev. time stamp */
WaitForIdle();
@ -232,7 +232,7 @@ SetAnalyse(char *Analyse, /* in: analysis type */
return;
/* get actual time */
ftime(&timenow);
perf_timer_get_time(&timenow);
timediff(&timenow, &timebefore, &diffsec, &diffmillisec);
OldPercent = DecaPercent;
@ -255,10 +255,8 @@ SetAnalyse(char *Analyse, /* in: analysis type */
sprintf(s, " %s: %3.1f%%", Analyse, (double)DecaPercent/10.);
sprintf(t, "%s %3.1f%%", PACKAGE_STRING, (double)DecaPercent/10.);
}
timebefore.dstflag = timenow.dstflag;
timebefore.millitm = timenow.millitm;
timebefore.time = timenow.time;
timebefore.timezone = timenow.timezone;
timebefore.milliseconds = timenow.milliseconds;
timebefore.seconds = timenow.seconds;
/* info when previous analysis period has finished */
if (strcmp(OldAn, Analyse)) {
if ((ft_nginfo || ft_ngdebug) && (strcmp(OldAn, "")))

View File

@ -163,6 +163,9 @@
/* Define to 1 if you have the `fork' function. */
/* #undef HAVE_FORK */
/* Define to 1 if you have the `queryperformancecounter' function. */
#define HAVE_QUERYPERFORMANCECOUNTER 1
/* Define to 1 if you have the `ftime' function. */
#define HAVE_FTIME 1