/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* MHz.c
 * Primitives for Windows 2000
 * Compute processor's clock rate(MHz)
 *
 * This program returns the processor's clock rate(MHz) as an integer. 
 * If fail, it returns -1.
 *
 * The program can iterate a couple of times specified by the parameter, 
 * IterC. Each iteration is a sample of one second. In each iteration, 
 * it reads the system time and cycle counter, delays about one 
 * second, read the system time and cycle counter again. Computing the 
 * clock rate by dividing the difference of system time by the difference
 * of cycle counter.
 * 
 * Warning: if run on Windows 95/98, SetThreadAffinityMask() may malfunction.
 *
 * Qianmin Yi (t-qianyi)
 * August 99
 */

#include <import_windows.h>
//include <mmlite.h>

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//#include <nt.h>

//#include <ntrtl.h>

//#include <nturtl.h>

#include <windows.h>
#include <winbase.h>
//#include <string.h>

//#include <stdarg.h>

//#include <stdlib.h>

//#include <stdio.h>

//#include <malloc.h>


//#include "CycleNew.h"


__inline __int64 GetCycleCount ()
{
__asm   _emit   0x0F
__asm   _emit   0x31    /* rdtsc */
    // return EDX:EAX       implied return causes annoying warning

};

/*---------------------------------------------------------------------------*/
int MHz(
    int IterC                           // # of iterations.

)
{
    int i;
    int TimeUnit = 10000000;            // resolution 100 ns              

    int DelayTime = 1000;               // time-out interval in milliseconds. 1 second.

    LONGLONG ElapsedTime;               // time elapsed between StartTime and EndTime. Unit depends on TimeUnit.

    int ClockRate;                      // MHz

    int AveClockRate, SumClockRate;

    LARGE_INTEGER CounterFrequency, StartTime, EndTime;     /* for system's high resolution timer */

    int AffiBit = 1;                            // For setting affinity mask

    DWORD OldAffiMask;                          // Origin thread affinity mask

    HANDLE ProcHd, ThreadHd;
    DWORD ProcAffiMask, SysAffiMask;

    __int64 StartCycleCount, EndCycleCount;
    __int64 CountPerIter;

    if (IterC <= 0)
    {
        return -1;
    }

    // Get current process handle and thread handle.

    ProcHd = GetCurrentProcess();
    ThreadHd = GetCurrentThread();

    if ( !ProcHd )
    {
        //printf("Fail to get current process handle: %d \n", GetLastError());

        return -1;
    }
    if ( !ThreadHd )
    {
        //printf("Fail to get current thread handle: %d \n", GetLastError());

        return -1;
    }

    /* Set current thread's affinity mask. */
    if ( !GetProcessAffinityMask(ProcHd, &ProcAffiMask, &SysAffiMask) )
    {
        //printf("Fail GetProcessAffinityMask: %d \n", GetLastError());

        return -1;
    }
    //printf("ProcAffiMasi = %u, SysAffiMask = %u \n", ProcAffiMask, SysAffiMask);

    
    while ( !(AffiBit & ProcAffiMask) )
    {
        //printf("debug. left shift once. \n");

        AffiBit = AffiBit << 1;
    }
    //printf("AffiBit = %d \n", AffiBit);

    
    OldAffiMask = SetThreadAffinityMask(ThreadHd, AffiBit);
    //printf("OldAffiMask = %u \n", OldAffiMask);


    if ( !OldAffiMask )
    {
        //printf("Fail to SetThreadAffinityMask: %d.\n", GetLastError());

        return -1;
    }
    //printf("AffiBit = %u \n", AffiBit);

    /* Get high resolution timer's frequency. */
    QueryPerformanceFrequency(&CounterFrequency);

    SumClockRate = 0;
    for ( i = 0; i < IterC; i++ )
    {
        QueryPerformanceCounter(&StartTime);
        StartCycleCount = GetCycleCount();

        Sleep(DelayTime);
        
        EndCycleCount = GetCycleCount();
        QueryPerformanceCounter(&EndTime);

        // Compute result.

        ElapsedTime = (EndTime.QuadPart - StartTime.QuadPart) * TimeUnit 
            / CounterFrequency.QuadPart;
        //printf("debug. ElapsedTime = %I64d \n", ElapsedTime);


        CountPerIter = EndCycleCount - StartCycleCount;
        //printf("debug. CountPerIter = %I64d \n", CountPerIter);


        if ( ElapsedTime <= 0 )
        {
            SetThreadAffinityMask(ThreadHd, OldAffiMask);
                        //printf("Elapsed < 0 ??\n");

            return -1;
        }

        ClockRate = (int)((CountPerIter * 100 / ElapsedTime  + 5) / 10);
        //printf("debug. ClockRate = %d MHz \n", ClockRate);


        SumClockRate += ClockRate;
    } // end for(i IterC)


    AveClockRate = SumClockRate / IterC;

    if ( !SetThreadAffinityMask(ThreadHd, OldAffiMask) )
    {
        //printf("Fail to SetThreadAffinityMask back: %d.\n", GetLastError());

        return -1;
    }
    
    return AveClockRate;
}