Files
lammps/src/timer.cpp
2025-04-24 07:53:05 -04:00

284 lines
7.8 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
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"
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
#include "fmt/chrono.h"
#endif
#include "tokenizer.h"
#include <cstring>
#include <ctime>
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
Timer::Timer(LAMMPS *_lmp) : Pointers(_lmp)
{
_level = NORMAL;
_sync = OFF;
_timeout = -1.0;
_s_timeout = -1.0;
_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 = platform::cputime();
current_wall = platform::walltime();
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 = platform::cputime();
current_wall = platform::walltime();
const double delta_cpu = current_cpu - previous_cpu;
const double delta_wall = current_wall - previous_wall;
cpu_array[SYNC] += delta_cpu;
wall_array[SYNC] += delta_wall;
cpu_array[ALL] += delta_cpu;
wall_array[ALL] += delta_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 = platform::cputime();
current_wall = platform::walltime();
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 = platform::cputime();
current_wall = platform::walltime();
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 = platform::cputime();
return (current_cpu - cpu_array[which]);
}
/* ---------------------------------------------------------------------- */
double Timer::elapsed(enum ttype which)
{
if (_level == OFF) return 0.0;
double current_wall = platform::walltime();
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 = platform::walltime() - 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 = platform::walltime() - timeout_start;
// broadcast time to ensure 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()
{
double remain = _timeout + timeout_start - platform::walltime();
// never report a negative remaining time.
if (remain < 0.0) remain = 0.0;
return (_timeout < 0.0) ? 0.0 : remain;
}
/* ----------------------------------------------------------------------
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) {
try {
_timeout = utils::timespec2seconds(arg[iarg]);
} catch (TokenizerException &) {
error->all(FLERR, "Illegal timeout time: {}", arg[iarg]);
}
} else {
utils::missing_cmd_args(FLERR, "timer timeout", error);
}
} 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 every frequency: {}", arg[iarg]);
} else {
utils::missing_cmd_args(FLERR, "timer every", error);
}
} else {
error->all(FLERR, "Unknown timer keyword {}", arg[iarg]);
}
++iarg;
}
timeout_start = platform::walltime();
if (comm->me == 0) {
// format timeout setting
std::string timeout = "off";
if (_timeout >= 0.0) {
#if defined(FMT_STATIC_THOUSANDS_SEPARATOR)
char outstr[200];
struct tm *tv = gmtime(&((time_t) _timeout));
strftime(outstr, 200, "%02d:%M:%S", tv);
timeout = outstr;
#else
std::tm tv = fmt::gmtime((std::time_t) _timeout);
timeout = fmt::format("{:02d}:{:%M:%S}", tv.tm_yday * 24 + tv.tm_hour, tv);
#endif
}
utils::logmesg(lmp, "New timer settings: style={} mode={} timeout={}\n", timer_style[_level],
timer_mode[_sync], timeout);
}
}