diff --git a/src/Makefile.am b/src/Makefile.am index f4b293925bfcfdf989889db768d60e3de778c985..b75bd93c24913c96817afc409e397e808d43b4d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,13 +35,13 @@ endif # List required headers include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ engine.h swift.h serial_io.h timers.h debug.h scheduler.h proxy.h parallel_io.h \ - common_io.h single_io.h multipole.h map.h tools.h partition.h + common_io.h single_io.h multipole.h map.h tools.h partition.h clocks.h # Common source files AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ serial_io.c timers.c debug.c scheduler.c proxy.c parallel_io.c \ units.c common_io.c single_io.c multipole.c version.c map.c \ - kernel.c tools.c part.c partition.c + kernel.c tools.c part.c partition.c clocks.c # Include files for distribution, not installation. nobase_noinst_HEADERS = approx_math.h atomic.h cycle.h error.h inline.h kernel.h vector.h \ diff --git a/src/clocks.c b/src/clocks.c new file mode 100644 index 0000000000000000000000000000000000000000..0d0e89bac3ccb05420a5ca21ccb54dbabfa93783 --- /dev/null +++ b/src/clocks.c @@ -0,0 +1,145 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Peter W. Draper (p.w.draper@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @file clocks.c + * @brief support for measuring intervals in seconds. Use cycle.h + * or timers.h for relative times. + */ + +/* Config parameters. */ +#include "../config.h" + +/* Standard headers. */ +#include <stdio.h> +#include <unistd.h> + +/* Local headers. */ +#include "clocks.h" + +/* 0.25 of a second in nanoseconds. */ +#define SLEEPTIME 250000000 + +/** + * @brief Get the current time. + * + * @param time the current time. + */ +void clocks_gettime(struct clockstime *time) { + +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &time->time); +#else + time->time = getticks(); +#endif +} + + +/** + * @brief Get difference in milli-seconds between two times. + * + * @param start the start time. + * @param end the end time. + * + * @return the difference in milli-secinds. + */ +double clocks_diff(struct clockstime *start, struct clockstime *end) +{ +#ifdef HAVE_CLOCK_GETTIME + struct timespec temp; + if ((end->time.tv_nsec - start->time.tv_nsec) < 0) { + temp.tv_sec = end->time.tv_sec - start->time.tv_sec - 1; + temp.tv_nsec = 1000000000 + end->time.tv_nsec - start->time.tv_nsec; + } else { + temp.tv_sec = end->time.tv_sec - start->time.tv_sec; + temp.tv_nsec = end->time.tv_nsec - start->time.tv_nsec; + } + return (double)temp.tv_sec * 1000.0 + (double)temp.tv_nsec * 1.0E-6; +#else + return elapsed(end->time, start-time) / clocks_cpufreq() * 1000; +#endif + +} + +/** + * @brief Estimate the CPU frequency in Hz. + * + * The technique is either to read the value from the cpuinfo_max_freq + * file, or use a clock timed nanosleep, or use the macro CPU_TPS. + * + * Only evaulated once. + * + * @result the CPU frequency. + */ +unsigned long long clocks_cpufreq() { + static unsigned long long cpufreq = 0; + + /* If already evaluated return that. */ + if (cpufreq > 0) + return cpufreq; + + /* Look for the system value, if available. */ +#ifdef __linux__ + FILE *file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", + "r"); + if (file != NULL) { + unsigned long long maxfreq; + if (fscanf(file, "%llu", &maxfreq) == 1) { + cpufreq = maxfreq; + } + fclose(file); + } +#endif + +#ifdef HAVE_CLOCK_GETTIME + /* If not try to time a nanosleep() in ticks. */ + if (cpufreq == 0) { + struct clockstime time1; + struct clockstime time2; + + struct timespec sleep; + sleep.tv_sec = 0; + sleep.tv_nsec = SLEEPTIME; + + clocks_gettime(&time1); + ticks tic = getticks(); + + /* Could do some calculation, but constant_tsc should protect us. */ + nanosleep(&sleep, NULL); + + clocks_gettime(&time2); + ticks toc = getticks(); + double realsleep = clocks_diff(&time1, &time2); + + cpufreq = (signed long long) (double)(toc - tic) * 1.0 / realsleep; + } +#endif + + /* Final attempt */ +#ifdef CPU_TPS + if (cpufreq == 0) + cpufreq = CPU_TPS; +#endif + + /* If all fails just report ticks in any times. */ + if (cpufreq == 0) + cpufreq = 1; + + return cpufreq; +} diff --git a/src/clocks.h b/src/clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..b97033029e46e1708d334500dcbf63ceaee46415 --- /dev/null +++ b/src/clocks.h @@ -0,0 +1,38 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Peter W. Draper (p.w.draper@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_CLOCKS_H +#define SWIFT_CLOCKS_H + +#include <time.h> +#include "cycle.h" + +/* Struct to record a time for the clocks functions. */ +struct clockstime { +#ifdef HAVE_CLOCK_GETTIME + struct timespec time; +#else + ticks time; +#endif +}; + +void clocks_gettime(struct clockstime *time); +double clocks_diff(struct clockstime *start, struct clockstime *end); +unsigned long long clocks_cpufreq(); + +#endif /* SWIFT_CLOCKS_H */