Files
lammps/src/timer.cpp
Axel Kohlmeyer e070766915 including lmpwindows.h globally from lmptype.h does more harm than good
this addresses some (cross) compilation issues locally.
in the long run, this should be addressed by implementing issue #1884
where platform specific functionality is wrapped into a small library
of generic functions adapted for LAMMPS' needs (like utils:: does for
non-portable convenience functions).
2021-09-07 10:39:16 -04:00

302 lines
7.7 KiB
C++

// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include "timer.h"
#include "comm.h"
#include "error.h"
#include "fmt/chrono.h"
#include <cstring>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <cstdint>
#else
#include <sys/time.h>
#include <sys/resource.h>
#endif
using namespace LAMMPS_NS;
// Return the CPU time for the current process in seconds very
// much in the same way as MPI_Wtime() returns the wall time.
static double CPU_Time()
{
double rv = 0.0;
#ifdef _WIN32
// from MSD docs.
FILETIME ct,et,kt,ut;
union { FILETIME ft; uint64_t ui; } cpu;
if (GetProcessTimes(GetCurrentProcess(),&ct,&et,&kt,&ut)) {
cpu.ft = ut;
rv = cpu.ui * 0.0000001;
}
#else /* ! _WIN32 */
struct rusage ru;
if (getrusage(RUSAGE_SELF, &ru) == 0) {
rv = (double) ru.ru_utime.tv_sec;
rv += (double) ru.ru_utime.tv_usec * 0.000001;
}
#endif /* ! _WIN32 */
return rv;
}
/* ---------------------------------------------------------------------- */
Timer::Timer(LAMMPS *lmp) : Pointers(lmp)
{
_level = NORMAL;
_sync = OFF;
_timeout = -1;
_s_timeout = -1;
_checkfreq = 10;
_nextcheck = -1;
this->_stamp(RESET);
}
/* ---------------------------------------------------------------------- */
void Timer::init()
{
for (int i = 0; i < NUM_TIMER; i++) {
cpu_array[i] = 0.0;
wall_array[i] = 0.0;
}
}
/* ---------------------------------------------------------------------- */
void Timer::_stamp(enum ttype which)
{
double current_cpu=0.0, current_wall=0.0;
if (_level > NORMAL) current_cpu = CPU_Time();
current_wall = MPI_Wtime();
if ((which > TOTAL) && (which < NUM_TIMER)) {
const double delta_cpu = current_cpu - previous_cpu;
const double delta_wall = current_wall - previous_wall;
cpu_array[which] += delta_cpu;
wall_array[which] += delta_wall;
cpu_array[ALL] += delta_cpu;
wall_array[ALL] += delta_wall;
}
previous_cpu = current_cpu;
previous_wall = current_wall;
if (which == RESET) {
this->init();
cpu_array[TOTAL] = current_cpu;
wall_array[TOTAL] = current_wall;
}
if (_sync) {
MPI_Barrier(world);
if (_level > NORMAL) current_cpu = CPU_Time();
current_wall = MPI_Wtime();
cpu_array[SYNC] += current_cpu - previous_cpu;
wall_array[SYNC] += current_wall - previous_wall;
previous_cpu = current_cpu;
previous_wall = current_wall;
}
}
/* ---------------------------------------------------------------------- */
void Timer::barrier_start()
{
double current_cpu=0.0, current_wall=0.0;
MPI_Barrier(world);
if (_level < LOOP) return;
current_cpu = CPU_Time();
current_wall = MPI_Wtime();
cpu_array[TOTAL] = current_cpu;
wall_array[TOTAL] = current_wall;
previous_cpu = current_cpu;
previous_wall = current_wall;
}
/* ---------------------------------------------------------------------- */
void Timer::barrier_stop()
{
double current_cpu=0.0, current_wall=0.0;
MPI_Barrier(world);
if (_level < LOOP) return;
current_cpu = CPU_Time();
current_wall = MPI_Wtime();
cpu_array[TOTAL] = current_cpu - cpu_array[TOTAL];
wall_array[TOTAL] = current_wall - wall_array[TOTAL];
}
/* ---------------------------------------------------------------------- */
double Timer::cpu(enum ttype which)
{
double current_cpu = CPU_Time();
return (current_cpu - cpu_array[which]);
}
/* ---------------------------------------------------------------------- */
double Timer::elapsed(enum ttype which)
{
if (_level == OFF) return 0.0;
double current_wall = MPI_Wtime();
return (current_wall - wall_array[which]);
}
/* ---------------------------------------------------------------------- */
void Timer::set_wall(enum ttype which, double newtime)
{
wall_array[which] = newtime;
}
/* ---------------------------------------------------------------------- */
void Timer::init_timeout()
{
_s_timeout = _timeout;
if (_timeout < 0)
_nextcheck = -1;
else
_nextcheck = _checkfreq;
}
/* ---------------------------------------------------------------------- */
void Timer::print_timeout(FILE *fp)
{
if (!fp) return;
// format timeout setting
if (_timeout > 0) {
// time since init_timeout()
const double d = MPI_Wtime() - timeout_start;
// remaining timeout in seconds
int s = _timeout - d;
// remaining 1/100ths of seconds
const int hs = 100*((_timeout - d) - s);
// breaking s down into second/minutes/hours
const int seconds = s % 60;
s = (s - seconds) / 60;
const int minutes = s % 60;
const int hours = (s - minutes) / 60;
fprintf(fp," Walltime left : %d:%02d:%02d.%02d\n",
hours,minutes,seconds,hs);
}
}
/* ---------------------------------------------------------------------- */
bool Timer::_check_timeout()
{
double walltime = MPI_Wtime() - timeout_start;
// broadcast time to insure all ranks act the same.
MPI_Bcast(&walltime,1,MPI_DOUBLE,0,world);
if (walltime < _timeout) {
_nextcheck += _checkfreq;
return false;
} else {
if (comm->me == 0)
error->warning(FLERR,"Wall time limit reached");
_timeout = 0.0;
return true;
}
}
/* ---------------------------------------------------------------------- */
double Timer::get_timeout_remain()
{
return (_timeout < 0.0) ? 0.0 : _timeout + timeout_start - MPI_Wtime();
}
/* ----------------------------------------------------------------------
modify parameters of the Timer class
------------------------------------------------------------------------- */
static const char *timer_style[] = { "off", "loop", "normal", "full" };
static const char *timer_mode[] = { "nosync", "(dummy)", "sync" };
void Timer::modify_params(int narg, char **arg)
{
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],timer_style[OFF]) == 0) {
_level = OFF;
} else if (strcmp(arg[iarg],timer_style[LOOP]) == 0) {
_level = LOOP;
} else if (strcmp(arg[iarg],timer_style[NORMAL]) == 0) {
_level = NORMAL;
} else if (strcmp(arg[iarg],timer_style[FULL]) == 0) {
_level = FULL;
} else if (strcmp(arg[iarg],timer_mode[OFF]) == 0) {
_sync = OFF;
} else if (strcmp(arg[iarg],timer_mode[NORMAL]) == 0) {
_sync = NORMAL;
} else if (strcmp(arg[iarg],"timeout") == 0) {
++iarg;
if (iarg < narg) {
_timeout = utils::timespec2seconds(arg[iarg]);
} else error->all(FLERR,"Illegal timer command");
} else if (strcmp(arg[iarg],"every") == 0) {
++iarg;
if (iarg < narg) {
_checkfreq = utils::inumeric(FLERR,arg[iarg],false,lmp);
if (_checkfreq <= 0)
error->all(FLERR,"Illegal timer command");
} else error->all(FLERR,"Illegal timer command");
} else error->all(FLERR,"Illegal timer command");
++iarg;
}
timeout_start = MPI_Wtime();
if (comm->me == 0) {
// format timeout setting
std::string timeout = "off";
if (_timeout >= 0) {
std::time_t tv = _timeout;
timeout = fmt::format("{:%H:%M:%S}", fmt::gmtime(tv));
}
utils::logmesg(lmp,"New timer settings: style={} mode={} timeout={}\n",
timer_style[_level],timer_mode[_sync],timeout);
}
}