/// \file
/// Performance timer functions.
#ifndef __PERFORMANCE_TIMERS_H_
#define __PERFORMANCE_TIMERS_H_

#include <stdio.h>

/// Timer handles
enum TimerHandle{totalTimer, loopTimer, timestepTimer,
                 positionTimer, velocityTimer,  redistributeTimer,
                 atomHaloTimer, computeForceTimer, eamHaloTimer,
                 commHaloTimer, commReduceTimer, numberOfTimers};

/// Use the startTimer and stopTimer macros for timers in code regions
/// that may be performance sensitive.  These can be compiled away by
/// defining NTIMING.  If you are placing a timer anywere outside of a
/// tight loop, consider calling profileStart and profileStop instead.
///
/// Place calls as follows to collect time for code pieces.
/// Time is collected everytime this portion of code is executed. 
///
///     ...
///     startTimer(computeForceTimer);
///     computeForce(sim);
///     stopTimer(computeForceTimer);
///     ...
///
#ifndef NTIMING
#define startTimer(handle)    \
   /*cudaDeviceSynchronize();*/   \
   do                         \
   {                          \
      profileStart(handle);   \
   } while(0)
#define stopTimer(handle)     \
   /*cudaDeviceSynchronize();*/   \
   do                         \
   {                          \
      profileStop(handle);    \
   } while(0)
#else
#define startTimer(handle)
#define stopTimer(handle)
#endif

/// Use profileStart and profileStop only for timers that should *never*
/// be turned off.  Typically this means they are outside the main
/// simulation loop.  If the timer is inside the main loop use
/// startTimer and stopTimer instead.
void profileStart(const enum TimerHandle handle);
void profileStop(const enum TimerHandle handle);

/// Use to get elapsed time (lap timer).
double getElapsedTime(const enum TimerHandle handle);

/// Print timing results.
void printPerformanceResults(int nGlobalAtoms);

/// Print timing results to Yaml file
void printPerformanceResultsYaml(FILE* file);
#endif
