#ifndef HIGH_RES_TIMER_H
#define HIGH_RES_TIMER_H

// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 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 General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
		\brief Declares timer classes for performance tuning
		\author Ed Millard (emillard@direcway.com)
*/

#include <boost/utility.hpp>
#include <iostream>
#include <string>

//#define ENABLE_HIGH_RES_TIMERS

namespace k3d
{

////////////////////////////////////////////////////////////////////////////////////////////////
// nanotime

#if defined K3D_HAVE_X86

/// Retrieves current time in seconds using an x86-specific CPU counter, useful for doing high-resolution timing
inline double nanotime()
{
	unsigned long long int val;
	__asm__ __volatile__("rdtsc" : "=A" (val) : );
	return static_cast<double>(val) / 1000000000.0;
}

#else

#warning "Using fallback implementation of nanotime() for your platform that uses clock() for portability, but limited accuracy.  You should consider contributing a more accurate implementation for your platform if one exists.  See configure.ac, acinclude.m4, and the K3D_CHECK_X86 macro for an example of how to detect a specific CPU type."

#include <ctime>

/// Retrieves current time in seconds using clock() for portable, but relatively inaccurate, timing
inline double nanotime()
{
	return static_cast<double>(std::clock()) / static_cast<double>(CLOCKS_PER_SEC);
}

#endif

////////////////////////////////////////////////////////////////////////////////////////////////
// timer

/// Measures elapsed time using a high-resolution timer.  Intentionally modelled on boost::timer
class timer
{
public:
	timer() :
		m_start(nanotime())
	{
	}
	
	void restart()
	{
		m_start = nanotime();
	}
	
	double elapsed() const
	{
		return nanotime() - m_start;
	}
	
private:
	double m_start;
};

/////////////////////////////////////////////////////////////////////////////////////////////////
// progress_timer

/// Measures elapsed time using a high-resolution timer, printing the results to a stream on destruction.  Intentionally modelled on boost::progress_timer
class progress_timer :
	public timer,
	public boost::noncopyable
{
public:
	progress_timer(std::ostream& Stream = std::cerr) :
		m_stream(Stream)
	{
	}
	
	~progress_timer()
	{
		m_stream << elapsed() << " s\n";
	}

private:
	std::ostream& m_stream;
};

} // namespace k3d

#endif // !HIGH_RES_TIMER_H
