

#include "WFProfiler.h"
#include "stdio.h"
#include "stdlib.h"

#define CPUID  __asm _emit 0x0F __asm _emit 0xA2 
#define RDTSC  __asm _emit 0x0F __asm _emit 0x31 
#define PUSHAD __asm _emit 0x60                  
#define POPAD  __asm _emit 0x61                  
        
typedef struct WF_PROFILER
{    

  unsigned Base;
  unsigned StartHigh;
  unsigned StartLow;
  unsigned EndHigh;
  unsigned EndLow;
  unsigned Started;

} WF_PROFILER, *WF_PROFILERptr, **WF_PROFILERlist;

__int64 __fastcall Duration( WF_PROFILER& pro );
void __fastcall SetDuration( WF_PROFILER& pro );
void __fastcall Reset( WF_PROFILER& pro );

#define StartNow(pro) __asm                                                                      \
{                                    /* Actual Reason for Instruction:                        */ \
  __asm PUSHAD                       /* Save all registers before we begin...                 */ \
  __asm CPUID                        /* Tell the CPU to Serialize Instruction Execution       */ \
  __asm MOV [pro].Started, 1         /* Show we have started this profiler going              */ \
  __asm RDTSC                        /* Read the CPU Clock Cycle Count                        */ \
  __asm MOV [pro].StartHigh, EDX     /* Move the High DWORD into the Profile settings (start) */ \
  __asm MOV [pro].StartLow, EAX      /* Move the Low DWORD into the Profile settings (start)  */ \
  __asm POPAD                        /* Restore the registers the way they were               */ \
}

#define StopNow(pro) __asm                                                                       \
{                                    /* Actual Reason for Instruction:                        */ \
  __asm PUSHAD                       /* Save all registers before we begin...                 */ \
  __asm CPUID                        /* Tell the CPU to Serialize Instruction Execution       */ \
  __asm MOV [pro].Started, 0         /* Show we have finished this profiler test              */ \
  __asm RDTSC                        /* Read the CPU Clock Cycle Count                        */ \
  __asm MOV [pro].EndHigh, EDX       /* Move the High DWORD into the Profile settings (end)   */ \
  __asm MOV [pro].EndLow, EAX        /* Move the Low DWORD into the Profile settings (end)    */ \
  __asm POPAD                        /* Restore the registers the way they were               */ \
}

#define Start(p) \
{                \
  StartNow(p);   \
  StopNow(p);    \
  SetDuration(p);\
  StartNow(p);   \
  StopNow(p);    \
  SetDuration(p);\
  StartNow(p);   \
  StopNow(p);    \
  SetDuration(p);\
  StartNow(p);   \
  StopNow(p);    \
  SetDuration(p);\
  StartNow(p);   \
}

#define Stop(p) StopNow(p);


static void Clear( WF_PROFILER& pro );
static void Clear(WF_PROFILER& pro)
{
  pro.Base=0;
  pro.StartHigh=0;
  pro.StartLow=0;
  pro.EndHigh=0;
  pro.EndLow=0;
  pro.Started=0;
}

void __fastcall Reset(WF_PROFILER& pro)
{
  // we need to clear if nothing was initialized...
  if (1!=pro.Started) Clear(pro);
}

__int64 __fastcall Duration(WF_PROFILER& pro)                                                
{                                                                     
  if (1 == pro.Started) return 0;                        // Error! Still working...
  __int64 baseEnd = ((__int64) pro.EndHigh << 32) | pro.EndLow;
  __int64 baseStart = ((__int64) pro.StartHigh << 32) | pro.StartLow;
  return (baseEnd - baseStart) - pro.Base;                // We're done. Return the total...
}

void __fastcall SetDuration(WF_PROFILER& pro)       
{               
  if (0 == pro.Started)   
  {
    __int64 baseEnd = ((__int64) pro.EndHigh << 32) | pro.EndLow;
    __int64 baseStart = ((__int64) pro.StartHigh << 32) | pro.StartLow;
    unsigned newBase = (unsigned) (baseEnd - baseStart);
    if (0==pro.Base) pro.Base = newBase;
     else  pro.Base = (pro.Base <= newBase) ? pro.Base : newBase;   // Keep the lowest value...
  }                                              
}


WF_PROFILER profile;

void  initcpucounter()
{
   Reset(profile);
     Start(profile);

}

__int64   getcpucount()
{

    Stop(profile);
      return Duration(profile);

}




