/*
Copyright 2007 William Hart and David Harvey
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#ifndef FLINT_PROFILER_H
#define FLINT_PROFILER_H
#include "flint.h"
#undef ulong
#define ulong ulongxx /* interferes with system includes */
#include
#if defined( _MSC_VER )
#include
#include "gettimeofday.h"
#pragma intrinsic( __rdtsc )
#else
#include
#endif
#if defined (__WIN32) && !defined(__CYGWIN__)
#ifdef __cplusplus
FLINT_DLL void GetSystemTimeAsFileTime(FILETIME*);
static __inline__ int gettimeofday(struct timeval * p, void * tz)
{
union {
slong slong ns100;
FILETIME ft;
} now;
GetSystemTimeAsFileTime(&(now.ft));
p->tv_usec=(slong)((now.ns100 / WORD(10)L) % WORD(1000000)L );
p->tv_sec= (slong)((now.ns100-(WORD(116444736000000000)L))/WORD(10000000)L);
return 0;
}
#else
FLINT_DLL int gettimeofday(struct timeval * p, void * tz);
#endif
#elif !defined(_MSC_VER)
#include
#endif
#undef ulong
#define ulong mp_limb_t
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
ulong size;
ulong peak;
ulong hwm;
ulong rss;
} meminfo_t[1];
FLINT_DLL void get_memory_usage(meminfo_t meminfo);
typedef struct
{
slong cpu;
slong wall;
} timeit_t[1];
static __inline__
void timeit_start(timeit_t t)
{
struct timeval tv;
gettimeofday(&tv, 0);
t->wall = - tv.tv_sec * 1000 - tv.tv_usec / 1000;
t->cpu = - clock() * 1000 / CLOCKS_PER_SEC;
}
static __inline__
slong timeit_query_wall(timeit_t t)
{
struct timeval tv;
gettimeofday(&tv, 0);
return t->wall + tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static __inline__
void timeit_stop(timeit_t t)
{
struct timeval tv;
gettimeofday(&tv, 0);
t->wall += tv.tv_sec * 1000 + tv.tv_usec / 1000;
t->cpu += clock() * 1000 / CLOCKS_PER_SEC;
}
/******************************************************************************
Timer based on the x86 cycle counter
******************************************************************************/
#if (defined( _MSC_VER ) || (GMP_LIMB_BITS == 64 && defined (__amd64__)) || \
(GMP_LIMB_BITS == 32 && (defined (__i386__) || \
defined (__i486__) || defined(__amd64__))))
#define FLINT_NUM_CLOCKS 20
#define FLINT_CLOCKSPEED 3100000000.0
extern double clock_last[FLINT_NUM_CLOCKS];
extern double clock_accum[FLINT_NUM_CLOCKS];
static __inline__
double get_cycle_counter()
{
#if defined( _MSC_VER )
return (double)__rdtsc();
#else
unsigned int hi;
unsigned int lo;
__asm("rdtsc; movl %%edx,%0; movl %%eax,%1"
: "=r" (hi), "=r" (lo)
:
: "%edx", "%eax");
return (double) hi * (1 << 30) * 4 + lo;
#endif
}
#define FLINT_CLOCK_SCALE_FACTOR (1000000.0 / FLINT_CLOCKSPEED)
static __inline__
void init_clock(int n)
{
clock_accum[n] = 0.0;
}
static __inline__
void init_all_clocks()
{
int i;
for (i = 0; i < FLINT_NUM_CLOCKS; i++)
clock_accum[i] = 0.0;
}
static __inline__
double get_clock(int n)
{
return clock_accum[n] * FLINT_CLOCK_SCALE_FACTOR;
}
static __inline__
void start_clock(int n)
{
clock_last[n] = get_cycle_counter();
}
static __inline__
void stop_clock(int n)
{
double now = get_cycle_counter();
clock_accum[n] += (now - clock_last[n]);
}
/******************************************************************************
Framework for repeatedly sampling a single target
******************************************************************************/
static __inline__
void prof_start()
{
start_clock(0);
}
static __inline__
void prof_stop()
{
stop_clock(0);
}
typedef void (*profile_target_t)(void* arg, ulong count);
FLINT_DLL void prof_repeat(double* min, double* max, profile_target_t target, void* arg);
#define DURATION_THRESHOLD 5000.0
#define DURATION_TARGET 10000.0
#endif
/******************************************************************************
Simple timing macros
******************************************************************************/
#define TIMEIT_PRINT(__timer, __reps) \
flint_printf("cpu/wall(s): %g %g\n", \
__timer->cpu*0.001/__reps, __timer->wall*0.001 / __reps);
#define TIMEIT_REPEAT(__timer, __reps) \
do \
{ \
slong __timeit_k; \
__reps = 1; \
while (1) \
{ \
timeit_start(__timer); \
for (__timeit_k = 0; __timeit_k < __reps; __timeit_k++) \
{
#define TIMEIT_END_REPEAT(__timer, __reps) \
} \
timeit_stop(__timer); \
if (__timer->cpu >= 100) \
break; \
__reps *= 10; \
} \
} while (0);
#define TIMEIT_START \
do { \
timeit_t __timer; slong __reps; \
TIMEIT_REPEAT(__timer, __reps)
#define TIMEIT_STOP \
TIMEIT_END_REPEAT(__timer, __reps) \
TIMEIT_PRINT(__timer, __reps) \
} while (0);
#define TIMEIT_ONCE_START \
do \
{ \
timeit_t __timer; \
timeit_start(__timer); \
do { \
#define TIMEIT_ONCE_STOP \
} while (0); \
timeit_stop(__timer); \
TIMEIT_PRINT(__timer, 1) \
} while (0); \
#define SHOW_MEMORY_USAGE \
do { \
meminfo_t meminfo; \
get_memory_usage(meminfo); \
flint_printf("virt/peak/res/peak(MB): %.2f %.2f %.2f %.2f\n", \
meminfo->size / 1024.0, meminfo->peak / 1024.0, \
meminfo->rss / 1024.0, meminfo->hwm / 1024.0); \
} while (0);
#ifdef __cplusplus
}
#endif
#endif