C++ High precision clock calculation 高精度计时器

Adam posted @ Thu, 13 Sep 2012 12:28:13 +0800 in C++ with tags c++ , 3170 readers

本计时器精确到微秒。目前版本V1.0.0

Download:Clock-V1.0.0.7z

 

目录关系:

 

 Clock
├── Clock
├── Core
│     ├── Clock.hpp
│     └── Clock.tcc
└── test
        └── test.cpp

 

文件:Clock/Clock

#pragma once

/**
*	Clock - High precision clock calculation --C++--
*	This file is under GNU General Public Licence,
*	free to copy or edit.
*
*
*	Copyright (c) 2012
*	Adam Basfop Cavendish
*
*	Permission to use, copy, modify, distribute and sell this software
*	and its documentation for any purpose is hereby granted without fee,
*	provided that the above copyright notice appear in all copies and
*	that both that copyright notice and this permission notice appear
*	in supporting documentation.  Adam Basfop Cavendish makes no
*	representations about the suitability of this software for any
*	purpose. It is provided "as is" without express or implied warranty.
*
*
*	@version	V1.0.0, last edited on 09. 13, 2012.
*	@file		Clock/Clock
*	@brief		This is a header for High precision Clock
*				calculating the time elapse between two
*				period of time.
*	@info		Any project compiled with this file should
*				be at least compiled with 2011 c++ standard,
*				for example: g++ -std=c++0x test.cpp
*/

#include "Core/Clock.hpp"
#include "Core/Clock.tcc"

 

文件:Clock/Core/Clock.hpp

 

#pragma once

#include <chrono>
#include <ratio>
#include <string>
#include <iostream>
#include <iomanip>
#include <stdexcept>

template <typename clock = std::chrono::high_resolution_clock>
class Clock
{
	typedef std::chrono::duration<int, std::ratio<3600*24>> chrono_days;
public: // functions
	// constructors
	
	/**
	 * @brief	Default constructor - creating a empty Clock,
	 *			initialized at zero
	 */
	Clock() : start_time(nullptr) {}

	/**
	 * @brief	Constructs a Clock at a initialized time with a time_point
	 *			initialized at tp minus the clock's epoch time
	 */
	Clock(typename clock::time_point tp) : start_time(nullptr) {
		total_time += tp;
	}// constructor(time_point)

	/**
	 * @brief	Constructs a Clock at a initialized time with a duration
	 *			initialized at duration.
	 */
	template <typename Duration>
	Clock(Duration du) : start_time(nullptr) {
		total_time += du;
	}// constructor(duration)

	/**
	 * @brief	Start calculating the time, until pause() is called.
	 */
	void start() {
		if(start_time != nullptr)
			throw std::runtime_error("Clock Already started!");
		start_time = new typename clock::time_point(clock::now());
	}//start()

	/**
	 * @brief	Pause the time, and the total_time will be
	 *			increased by paused_time minus started_time
	 */
	void pause() {
		typename clock::time_point pause_time(clock::now());
		if(start_time == nullptr)
			throw std::runtime_error("Clock has not been started!");
		total_time += pause_time - *start_time;
		delete start_time;
		start_time = nullptr;
	}//pause()

	/**
	 * @brief	Clear the Clock, and the time of the Clock
	 *			will be set to zero
	 */
	void clear() {
		if(start_time != nullptr) {
			delete start_time;
			start_time = nullptr;
		}//if
		std::chrono::time_point<clock> tp;
		total_time = tp;
	}//clear()

	/**
	 * @brief	add time to the Clock by duration du
	 * @param	Duration du, the duration to be increased
	 */
	template <typename Duration>
	void addTime(const Duration &du) {
		total_time += du;
	}//addTime(Duration)

	/**
	 * @brief	reduce time from the Clock by duration du
	 * @param	Duration du, the duration to be reduced from the Clock
	 */
	template <typename Duration>
	void reduceTime(const Duration &du) {
		total_time -= du;
	}//reduceTime(Duration)


	/**
	 * @brief	make up a time_point according to the time
	 */
	typename clock::time_point makeTimePoint(
			int year,
			int month,
			int day,
			int hour = 0,
			int minute = 0,
			int second = 0,
			int millisecond = 0,
			int microsecond = 0
	);

	/**
	 * @brief	Convert the Clock to system time
	 *			print example: Thu Jan  1 08:00:00 1970
	 */
	std::string toString(const typename clock::time_point &start_time_point) {
		std::time_t t = clock::to_time_t(
				start_time_point + total_time.time_since_epoch()
		);	// convert to system time
		std::string ts = ctime(&t);	// convert to calendar time
		ts.resize(ts.size() - 1);	// skip trailing newline
		return ts;
	}//toString()

	/**
	 * @brief	print the Clock's counting time
	 * @param	os --		The ostream for print, default is std::cout
	 * @param	option --	The option for printing.
	 *						Using DAY, HOUR, MIN, SEC, MILLI, MICRO, NANO
	 *						for printing day, hour, minute, second,
	 *						millisecond, microsecond, nanosecond part of
	 *						the information.
	 *						Using '|' to print multiple parts.
	 *						default is to print all of them.
	 *
	 * @param	hint --		The hint message for printing, default: "Clock: "
	 * @example	print example: "Clock: 00 Day(s) 00 Hours(s) 00 Min(s) \
	 *							00 Second(s) 000 Milli(s) 000 Micro(s) 000 Nano(s)"
	 */
	void print(
			std::ostream &os = std::cout,
			const int option = (DAY | HOUR | MIN | SEC | MILLI | MICRO | NANO),
			const std::string &hint = "Clock: "
			);

	/**
	 * @brief	execute a file and calculate the elapsed time of the execution
	 * @param	cmdline --	the command line, example: execute_file("a.out 100 99 98");
	 */
	int execute_file(const char *cmdline);
	int execute_file(const std::string &cmdline);
	
	/**
	 * @brief	Create cmdline using argc and argv starting at argc = argc_start.
	 *			This function is written for those who want to execute a file
	 *			that is inputed by arguments.
	 */
	const std::string createCmdline(int argc, char *argv[], int argc_start = 1);

	// geters and seters
	
	/**
	 * @brief	get the total_time time_point
	 */
	const typename clock::time_point getTotalTime() { return total_time; }

	/**
	 * @brief	get the information of the Clock
	 */
	const chrono_days getDays() {
		return std::chrono::duration_cast<chrono_days>
			(total_time.time_since_epoch());
	}//getDays()
	const std::chrono::hours getHours() {
		return std::chrono::duration_cast<std::chrono::hours>
			(total_time.time_since_epoch() % chrono_days(1));
	}//getHours()
	const std::chrono::minutes getMinutes() {
		return std::chrono::duration_cast<std::chrono::minutes>
			(total_time.time_since_epoch() % std::chrono::hours(1));
	}//getMinutes()
	const std::chrono::seconds getSeconds() {
		return std::chrono::duration_cast<std::chrono::seconds>
			(total_time.time_since_epoch() % std::chrono::minutes(1));
	}//getSeconds()
	const std::chrono::milliseconds getMilliseconds() {
		return std::chrono::duration_cast<std::chrono::milliseconds>
			(total_time.time_since_epoch() % std::chrono::seconds(1));
	}//getMilliseconds()
	const std::chrono::microseconds getMicroseconds() {
		return std::chrono::duration_cast<std::chrono::microseconds>
			(total_time.time_since_epoch() % std::chrono::milliseconds(1));
	}//getMicroseconds()
	const std::chrono::nanoseconds getNanoseconds() {
		return std::chrono::duration_cast<std::chrono::nanoseconds>
			(total_time.time_since_epoch() % std::chrono::microseconds(1));
	}//getNanoseconds()

	// destructors
	~Clock() { if(start_time != nullptr) delete start_time; }
private: // functions
	
	/**
	 * @brief	to check whether the cmdline str has space ' ' or '\t' in it
	 *			supports the '\' to merge two lines
	 */
	bool hasSpace(const char *str);
#if defined (WINDOWS) || (__WINDOWS__) || (_WIN64) || (_WIN32) || \
	(WIN64) || (WIN32)
	int windows_execute(const char *cmdline);
#elif defined (__linux) || (__unix) || (__posix) || \
	(__linux__) || (__unix__) || (__posix__)
	int posix_execute(const char *cmdline);
#endif // OS-Check

public:	// variables
	/**
	 * @brief	The static value for option in print,
	 *			use them to print the specific part.
	 * @param	ALL = DAY | HOUR | MIN | SEC | MILLI | MICRO | NANO
	 */
	enum {
		DAY =		(1 << 6),
		HOUR =		(1 << 5),
		MIN =		(1 << 4),
		SEC =		(1 << 3),
		MILLI =		(1 << 2),
		MICRO =		(1 << 1),
		NANO =		(1 << 0),
		ALL =		(0x3F),
		COMMON =	(0x0E),
	}; // enum
private: // variables
	typename clock::time_point total_time;
	typename clock::time_point *start_time;
};//class Clock

 

文件:Clock/Core/Clock.tcc

 

#include "Clock.hpp"

#include <iostream>
#include <chrono>
#include <string>
#include <cstring>
#include <stdexcept>
#include <ctime>

#if defined (WINDOWS) || defined (__WINDOWS__) || defined (_WIN64) || defined (_WIN32) || \
	defined (WIN64) || defined (WIN32)

#include <windows.h>

#elif defined (__linux) || defined (__unix) || defined (__posix) || \
	defined (__linux__) || defined (__unix__) || defined (__posix__)

#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#endif // OS-Check

template <typename clock>
typename clock::time_point Clock<clock>::makeTimePoint(
		int year,
		int month,
		int day,
		int hour,
		int minute,
		int second,
		int millisecond,
		int microsecond
		)
{
	struct std::tm t;
	t.tm_sec = second;		// second of minute (0 .. 59 and 60 for leap seconds)
	t.tm_min = minute;		// minute of hour (0 .. 59)
	t.tm_hour = hour;		// hour of day (0 .. 23)
	t.tm_mday = day;		// day of month (0 .. 31)
	t.tm_mon = month-1;		// month of year (0 .. 11)
	t.tm_year = year-1900;	// year since 1900
	t.tm_isdst = -1;		// determine whether daylight saving time
	std::time_t tt = std::mktime(&t);
	if(tt == -1)
		throw std::domain_error("Invalid time, time_point cannot be made");
	if(millisecond < 0 || millisecond > 999 ||
			microsecond < 0 || microsecond > 999)
//			nanosecond < 0 || nanosecond > 999)
		throw std::domain_error("Invalid time, time_point cannot be made");

	typename clock::time_point ret_tp = clock::from_time_t(tt);
	std::chrono::milliseconds milli(millisecond);
	std::chrono::microseconds micro(microsecond);
//	std::chrono::nanoseconds nano(nanosecond);
	ret_tp += milli;
	ret_tp += micro;
//	ret_tp += nano;

	return ret_tp;
}//makeTimePoint(year, month, day, hour, minute, second, millisecond, microsecond)

template <typename clock>
void Clock<clock>::print(
		std::ostream &os,
		const int option,
		const std::string &hint)
{
	if(option <= 0)
		return;

	os << hint << std::setfill('0');
	if((option & DAY) > 0)
		os << std::setw(2) << getDays().count() << " Day(s) ";
	if((option & HOUR) > 0)
		os << std::setw(2) << getHours().count() << " Hours(s) ";
	if((option & MIN) > 0)
		os << std::setw(2) << getMinutes().count() << " Min(s) ";
	if((option & SEC) > 0)
		os << std::setw(2) << getSeconds().count() << " Second(s) ";
	if((option & MILLI) > 0)
		os << std::setw(3) << getMilliseconds().count() << " Milli(s) ";
	if((option & MICRO) > 0)
		os << std::setw(3) << getMicroseconds().count() << " Micro(s) ";
	if((option & NANO) > 0)
		os << std::setw(3) << getNanoseconds().count() << " Nano(s) ";
	os << std::endl;
}//print(os, option, hint)

template <typename clock>
int Clock<clock>::execute_file(const char *cmdline)
{
#if defined (WINDOWS) || defined (__WINDOWS__) || defined (_WIN64) || defined (_WIN32) || \
	defined (WIN64) || defined (WIN32)
	return windows_execute(cmdline);
#elif defined (__linux) || defined (__unix) || defined (__posix) || \
	defined (__linux__) || defined (__unix__) || defined (__posix__)
	return posix_execute(cmdline);
#endif // OS-Check
}//execute_file(char *)

template <typename clock>
int Clock<clock>::execute_file(const std::string &cmdline)
{
#if defined (WINDOWS) || defined (__WINDOWS__) || defined (_WIN64) || defined (_WIN32) || \
	defined (WIN64) || defined (WIN32)
	return windows_execute(cmdline.c_str());
#elif defined (__linux) || defined (__unix) || defined (__posix) || \
	defined (__linux__) || defined (__unix__) || defined (__posix__)
	return posix_execute(cmdline.c_str());
#endif // OS-Check
}//execute_file(string)

template <typename clock>
const std::string Clock<clock>::createCmdline(int argc, char *argv[], const int argc_start)
{
	std::string cmdline;
    for (int i = argc_start; i < argc; ++i) {
		bool hs = hasSpace(argv[i]);
        if (hs)
            cmdline += "\"";
        cmdline += argv[i];
        if (hs)
            cmdline += "\"";
        cmdline += " ";
    }//for

	return cmdline;
}//createCmdline(argc, argv, argc_start)

// private functions

template <typename clock>
bool Clock<clock>::hasSpace(const char *str)
{
	char last;
	if(str == NULL)
		return false;
	while('\0' != *str) {
		if(((' ' == *str) || ('\t' == *str)) && ('\\' != last))
			return true;
		last = *str++;
	}//while
	return false;
}//hasSpace(str)

#if defined (WINDOWS) || defined (__WINDOWS__) || defined (_WIN64) || defined (_WIN32) || \
	defined (WIN64) || defined (WIN32)

template <typename clock>
int Clock<clock>::windows_execute(const char *cmdline)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

    // Start the child process.
    CreateProcess(NULL, TEXT((char *)cmdline), NULL,
			NULL, FALSE, 0, 
			NULL, NULL, &si,
			&pi);
	// Start calculating the time
	start();

    // Wait until child process exits.
    WaitForSingleObject(pi.hProcess, INFINITE);
	// Process exits, stop the calculation and add to the total_time
	pause();

    // Get the return value of the child process
    DWORD ret;
    GetExitCodeProcess(pi.hProcess, &ret);

    // Close process and thread handles.
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return ret;
}//windows_execute(const char *)

#elif defined (__linux) || defined (__unix) || defined (__posix) || \
	defined (__linux__) || defined (__unix__) || defined (__posix__)

template <typename clock>
int Clock<clock>::posix_execute(const char *cmdline)
{
	// Store the return status of the file
	int ret_status;
	// the child process pid
	pid_t pid;

	if((pid = fork()) < 0) {
		std::cerr << "Errno: " << errno
			<< " ErrMsg: " << strerror(errno) << std::endl;
		throw std::runtime_error("fork() Failed!");
	} else if(pid == 0) {
		// child process
		execl("/bin/sh", "sh", "-c", cmdline, (char *)0);
		// if gets here, execl error
		std::cerr << "Errno: " << errno
			<< " ErrMsg: " << strerror(errno) << std::endl;
		throw std::runtime_error("execl() Failed!");
	} else {
		// parent process
		
		// start calculating the time
		start();
		// wait until the file exits
		if(waitpid(pid, &ret_status, 0) < 0) {
			if(EINTR != errno) {
				std::cerr << "Errno: " << errno
					<< " ErrMsg: " << strerror(errno) << std::endl;
				throw std::runtime_error("waitpid() Failed!");
			} else {
				// if the process is interupted
				ret_status = -1;
			}//if-else
		}
		// stop the calculation and add to the total_time
		pause();
	}//if-else

	return WEXITSTATUS(ret_status);
}//posix_execute(cont char *)
#endif // OS-Check

 

文件:Clock/test/test.cpp

 

#include "../Clock"

#include <iostream>
#include <chrono>
#include <sstream>
using namespace std;
using namespace std::chrono;

int main(int argc, char *argv[])
{
	if(argc < 2) {
		cout << "No argv" << endl;
		return 1;
	}//if

	const int maxn = 100000;

	Clock<system_clock> c;

	c.start();
	for(int i = 0; i < maxn; ++i);
	c.pause();

	cout << "i 0:" << maxn << endl;
	c.print(cout, c.MIN | c.SEC | c.MILLI | c.MICRO, "Clock shows: ");

	cout << endl << "clear:" << endl;
	c.clear();
	c.print(clog);

	cout << endl << "addTime, reduceTime:" << endl;
	c.addTime(seconds(100));
	c.addTime(milliseconds(99));
	c.reduceTime(microseconds(1));
	c.print();

	cout << endl << "toString:" << endl;
	system_clock::time_point start_time = c.makeTimePoint(2012, 9, 13);
	cout << c.toString(start_time) << endl;
	
	cout << endl << "execute_file: " << endl;
	c.clear();
	string cmdline = c.createCmdline(argc, argv);
	int ret = c.execute_file(cmdline);
	stringstream ss;
	ss << endl << "Program returns: " << ret << " Time: ";
	string ret_str = ss.str();
	c.print(cout, c.COMMON,ret_str);

	return 0;
}//main

 


Login *


loading captcha image...
(type the code from the image)
or Ctrl+Enter