2015-07-11 18:56:02 +08:00
|
|
|
/*
|
2019-06-22 20:21:32 +08:00
|
|
|
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>) (DKFZ) & IWR, University of Heidelberg
|
2015-07-11 18:56:02 +08:00
|
|
|
|
|
|
|
last modification: $LastChangedDate: 2015-06-10 19:19:10 +0200 (Mi, 10 Jun 2015) $ (revision $Rev: 3976 $)
|
|
|
|
|
|
|
|
This software 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
|
2019-02-08 00:24:46 +08:00
|
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
2015-07-11 18:56:02 +08:00
|
|
|
(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 Lesser General Public License (LGPL) for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <iostream>
|
2019-11-24 19:21:06 +08:00
|
|
|
#include <chrono>
|
2015-07-11 18:56:02 +08:00
|
|
|
|
2019-06-22 20:21:32 +08:00
|
|
|
#include "jkqtcommon_imexport.h"
|
2019-06-20 21:18:58 +08:00
|
|
|
|
2015-07-11 18:56:02 +08:00
|
|
|
#ifndef __WINDOWS__
|
|
|
|
# if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)
|
|
|
|
# define __WINDOWS__
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef __LINUX__
|
|
|
|
# if defined(linux)
|
|
|
|
# define __LINUX__
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
#include<windows.h>
|
|
|
|
#elif defined(__LINUX__)
|
|
|
|
#include <sys/time.h>
|
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef JKQTPHIGHRESTIMER_H
|
|
|
|
#define JKQTPHIGHRESTIMER_H
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief This class implements a high resolution timer capable of measuring time intervals with a resolution
|
|
|
|
* of some microseconds
|
2019-01-13 01:53:16 +08:00
|
|
|
* \ingroup jkqtptools_debugging
|
2015-07-11 18:56:02 +08:00
|
|
|
*
|
|
|
|
* \attention Note that this is a MS Windows specific implementation od a high-resolution timer using some of
|
|
|
|
* windows' API methods (namely \c QueryPerformanceCounter() and \c QueryPerformanceFrequency() ). So if you want
|
|
|
|
* to use this class on non-win32 systems you will have to find a way to implement it for your system!!!
|
|
|
|
*
|
|
|
|
* \attention Also note that a standard windows system is NOT a real time OS. So do not expect to get a high accuracy
|
|
|
|
* when timing operations using this timer. It gives you an accurate time stamp, but it can not guarantee when
|
|
|
|
* the code is executed!
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The timer works very simple:
|
|
|
|
* - you can start the timer with start() which means you set a time=0
|
2019-01-26 20:00:40 +08:00
|
|
|
* - then you can query the time difference to the last call of start() by using getTime().
|
2015-07-11 18:56:02 +08:00
|
|
|
* .
|
|
|
|
*
|
|
|
|
* There is also a test method test() which will try to give you a feel for the performance of the timer in
|
|
|
|
* a simple application on your computer.
|
|
|
|
* It simply does some thousand iterations and records the time needed for each single iteration. Then it may
|
|
|
|
* calculate a histogram, a mean value and a standard deviation from these times.
|
|
|
|
*
|
|
|
|
* This is the result of test() on a WinXP system, Athlon64 X2 3800+ (2GHz):
|
|
|
|
* \image html highrestimer.png
|
|
|
|
* Note that this histogram tells you more about how your system works than about the timer itself.
|
|
|
|
* What we can find out about the timer is that it really provides a resolution in the microsecond region. This can
|
|
|
|
* be seen, as there is a non-zero minimal measured interval (1.67619 usec). This basically tells us the run-time of
|
|
|
|
* the measurement loop. There are also bigger run-times which are produced, as this program ran on a multi-process
|
|
|
|
* (not process<b>or</b> !!!) OS, which means that the current process may be stalled to allow othe rprocesses to
|
|
|
|
* execute. If this would run on a single-process system we should only get one run-time, if we assume that all
|
|
|
|
* methods need a fixed amount of time. So we can use this method to test whether our system provides a sufficiently
|
|
|
|
* accurate time. The 1.68 usec give an upper bound for the timer interval and thus the resolution they do <b>not</b>
|
|
|
|
* represent the timer resolution. To get this nominal resolution in a windows system you could use the WinAPI method
|
2019-01-26 20:00:40 +08:00
|
|
|
* \c QueryPerformanceFrequency() which is used in the method getTime(). On my system the timer frequency is 3.57955 MHz
|
2015-07-11 18:56:02 +08:00
|
|
|
* which corresponds to a resolution of 0.2794 usec.
|
|
|
|
*
|
|
|
|
* \par win32 implementation issues:
|
|
|
|
* To implement this timer on windows systems I use two API calls from the windows kernel. They are:
|
|
|
|
* - <a href="http://msdn2.microsoft.com/en-us/library/ms644904.aspx">QueryPerformanceCounter()</a>
|
|
|
|
* - <a href="http://msdn2.microsoft.com/en-us/library/ms644905.aspx">QueryPerformanceFrequency()</a>
|
|
|
|
* .
|
|
|
|
* \n
|
|
|
|
* The first one is used to read times: In the start() method we simply save the current counter value to a variable.
|
2019-01-26 20:00:40 +08:00
|
|
|
* In getTime() we can then again use QueryPerformanceCounter() to get the current counter value and then calculate
|
2015-07-11 18:56:02 +08:00
|
|
|
* the difference between these two. Using QueryPerformanceFrequency() we can calculate the time difference in usecs
|
|
|
|
* from the counter value difference using:
|
|
|
|
* \f[ \Delta t=\frac{N_{\mbox{now}}-N_{\mbox{start}}}{\mbox{\texttt{QueryPerformanceFrequency()}}}\cdot 10^{6} \f]
|
|
|
|
*
|
|
|
|
* \par why not standard POSIX?
|
|
|
|
* The standard POSIX time functions available in a MinGW environment have a resolution that is in the range of
|
|
|
|
* some 10 milliseconds. This may be enough for many purposes, but for exact time measurement, as you will want
|
|
|
|
* to do it on measurement and control systems this is not sufficient. So I tried to find a possibility to
|
|
|
|
* implement a system-independent high-resolution timer. As most timer stuff depends on very low-level kernel
|
|
|
|
* calls on every operating system this seems to be nearly impossible. So I implemented this timer for win32 only,
|
|
|
|
* as this is the system we use in the lab.
|
|
|
|
*
|
|
|
|
* \par linux implementation possibility:
|
|
|
|
* This class does not implement a timer for Linux/Unix systems but I
|
|
|
|
* will provide you with a small hint how you could implement one here:
|
|
|
|
* The <a href="http://www.gnu.org/software/libc/manual/html_node/High_002dResolution-Calendar.html">\c gettimeofday()
|
|
|
|
* method</a> from the libc seems to have enough tim resolution for our pourposes, so try to use this for the high-
|
|
|
|
* resolution timer. As mentioned above this method is not available for MinGW in win32 which is the main development
|
|
|
|
* platform for this project.
|
|
|
|
*
|
2019-01-12 23:01:55 +08:00
|
|
|
* \test you can find an example application in the file \link test_hrestimer.cpp \endlink.
|
2015-07-11 18:56:02 +08:00
|
|
|
*
|
|
|
|
*/
|
2019-06-22 20:21:32 +08:00
|
|
|
class JKQTCOMMON_LIB_EXPORT JKQTPHighResTimer {
|
2015-07-11 18:56:02 +08:00
|
|
|
protected:
|
|
|
|
#ifdef __WINDOWS__
|
|
|
|
/** \brief internal: time stamp of the last call of start() */
|
|
|
|
LARGE_INTEGER last;
|
|
|
|
#else
|
2019-11-24 19:21:06 +08:00
|
|
|
std::chrono::system_clock::timepoint last;
|
2015-07-11 18:56:02 +08:00
|
|
|
#endif
|
2019-08-23 20:21:38 +08:00
|
|
|
/** \brief internal: timer frequency */
|
|
|
|
double freq;
|
2019-02-08 00:24:46 +08:00
|
|
|
public:
|
|
|
|
/** \brief class constructor. */
|
2015-07-11 18:56:02 +08:00
|
|
|
JKQTPHighResTimer();
|
2019-02-08 00:24:46 +08:00
|
|
|
/** \brief class destructor */
|
2015-07-11 18:56:02 +08:00
|
|
|
~JKQTPHighResTimer();
|
2019-02-08 00:24:46 +08:00
|
|
|
/** \brief start the timer */
|
|
|
|
void start();
|
|
|
|
/** \brief get the time since the last call of start() in microseconds */
|
|
|
|
double getTime();
|
|
|
|
/** \brief test the resolution
|
2015-07-11 18:56:02 +08:00
|
|
|
*
|
|
|
|
* mean value and standard deviation of 1000000 timer polls will be evaluated and returned in \c mean
|
|
|
|
* and \c stddev. If you supply \c histogram with a pointer to a memory array with \c histogram_size
|
|
|
|
* items this will hold afterwards a histogram of the data. \c histogram_x wil contain the time interval
|
|
|
|
* values of the histogram bins in \c histogram.
|
|
|
|
*
|
|
|
|
* To measure the resolution this method uses this code:
|
|
|
|
* \code
|
2019-01-26 20:00:40 +08:00
|
|
|
double l=getTime(), n;
|
2015-07-11 18:56:02 +08:00
|
|
|
for (unsigned long i=0; i<runs; i++) {
|
2019-01-26 20:00:40 +08:00
|
|
|
n=getTime();
|
2015-07-11 18:56:02 +08:00
|
|
|
h[i]=n-l;
|
|
|
|
l=n;
|
|
|
|
}
|
|
|
|
\endcode
|
|
|
|
*
|
|
|
|
*/
|
2019-02-08 00:24:46 +08:00
|
|
|
void test(double* mean, double* stddev, unsigned long* histogram=nullptr, double* histogram_x=nullptr, unsigned long histogram_size=0);
|
2015-07-11 18:56:02 +08:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // JKQTPHIGHRESTIMER_H
|