Archived

This topic is now archived and is closed to further replies.

Simple clock counter attempt:

This topic is 6364 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

    
#include "windows.h"

 __int64 GetClock()
{
	__int64 rslt;
	__asm
	{
		__emit 0x0f	// RDTSC - read time-stamp counter		__emit 0x31

		mov dword ptr [rslt],eax
		mov dword ptr [rslt+4],edx
	}
	return ( rslt );
}

void main(void)
{
	__int64 start;
	__int64 end;
	__int64 diff;

	start = GetClock();

	Sleep(1000);

	end = GetClock();

	diff = end - start;
}
    
I get an unhandled exception with this code on the RDTSC line. Any clues? I found a few other example of how to do this but they were like 3 pages long and really hard to follow...

Share this post


Link to post
Share on other sites
Look through previous posts for the QueryPerformanceCounter and QueryPerformanceFrequency api''s. They have a very high resolution of 100''ths or 1000''s of a millisecond and is only two api calls! Work great, only down fall if that it only works on Pentiums or greater (No 486,386,etc..)

On the older machines use GetTickCount which you can also find info about with a search of threads. :-)

I''ve never used this rtsc clock so I don''t know how it works, but you can e-mail me assembler questions if you need too.

See ya,
Ben

Share this post


Link to post
Share on other sites
Yah it appears that you want to time a procedure and you''ll later replace the sleep 1000 with some real code and time how long it takes to execute. Is that right? If so definately use the PerformanceTimer functions. Otherwise tell me what your trying to do...
- Ben

Share this post


Link to post
Share on other sites
Yep thats exactly what I want to do, just time how long (in cycles) an event takes. My goal was eventially make a class that held values and did the math AND also subtract it''s own working time from the calculations.

In the end I''d like to say : "This loop takes 300 cycles and that one takes 400"

Share this post


Link to post
Share on other sites
You have a Pentium, right?

See if this runs for you. I just compiled and ran it.

At the end, I had these values (on my P-II 450 w/ NT 4.0)

t_start = 214098140771222
t_end = 214098148610579
t_diff = 7839357

Here''s the whole program:

    
#include "windows.h"
#include "math.h"

__int64 GetClock()
{
__int64 rslt;

__asm {
__emit 0x0f // RDTSC - read time-stamp counter

__emit 0x31
mov dword ptr [rslt],eax
mov dword ptr [rslt+4],edx
}
return ( rslt );
}

int main(int argc, char* argv[])
{
__int64 t_start;
__int64 t_end;
__int64 t_diff;

int n;
double d;

t_start = GetClock();

// Loop a bit

for(n = 1; n <= 81920; n++)
{
d = sqrt((double) n);
}

t_end = GetClock();

t_diff = t_end - t_start;

return(0);
}


Like I said.. Worked fine on my setup ; VC++ 6.0 Console Project.

// CHRIS

Share this post


Link to post
Share on other sites
Just noticed.. Did you copy/paste your code right?
Your "__emit 0x31" comes after your comment -- on the same line. If that''s the case, it won''t get compiled and you''ll just have the 0x0F emit''d; missing the 0x31 will certainly cause problems.

// CHRIS

Share this post


Link to post
Share on other sites
Thanks much. I might turn this in to a simple class that''ll manage the big ints. Does c++ have a 64bit integer thats isn''t platform specific? (I know LARGE_INTEGER is MS, not sure about __int64

Thanks..

PS : It''s interesting to not that if you drop the work and just call GetClock twice in a row the number of clock cycles that occurs in between doesn''t seem static. Some times you get ~200 then next you get ~220 etc. I was planning on just reducing the diff by the clocking overhead for a little more precision. Oh well...

Share this post


Link to post
Share on other sites
If you're running under windows, there are context switches happening all the time. How much time is taken away from your app is up to the process scheduler.

The RDTSC loads the current value of the processor's time-stamp counter into the EDX:EAX registers. The time-stamp counter is contained in a 64-bit MSR. The high-order 32 bits of the MSR are loaded into the EDX register, and the low-order 32 bits are loaded into the EAX register. The processor increments the time-stamp counter MSR every clock cycle and resets it to 0 whenever the processor is reset. The time stamp disable (TSD) flag in register CR4 restricts the use of the RDTSC instruction. When the TSD flag is clear, the RDTSC instruction can be executed at any privilege level; when the flag is set, the instruction can only be executed at privilege level 0. The time-stamp counter can also be read with the RDMSR instruction, when executing at privilege level 0. The RDTSC instruction is not a serializing instruction. Thus, it does not necessarily wait until all previous instructions have been executed before reading the counter. Similarly, subsequent instructions may begin execution before the read operation is performed. This instruction was introduced into the Intel Architecture in the Pentium r processor.

// CHRIS


Edited by - win32mfc on July 14, 2000 1:01:36 AM

Share this post


Link to post
Share on other sites
A gimp must make all possible mistakes before getting something right...

Never mind I was being an idiot again... I was running the app in debug mode. When I inlined the function and compiled as release I get a consistant 33 clocks... I can see how you example will still happen. What suprised me was that if you thread was to be suspended mid process I''s expect to see a massive or non at all, not small variances... anyway. I''m happy now

Share this post


Link to post
Share on other sites
i tried the program above, and i saw something that i think is not normal. the result was correct in debug mode, but in release mode, it gave me always the same result: 33 clocks. why? i have the for loop between the two call of the function. and it works in debug mode....

the source is exactly same that win32mfc posted...

anyone know why???

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hrmmm... thats interesting... I might look at that too...

In the meantime I''ve expanded the app to a little class:
    
class CClock
{
public:
CClock();
~CClock();

//Start the timer

inline void Reset(void);

//Obtain the timer time since last reset.

inline unsigned long ElapsedMilliseconds(void);
inline unsigned long ElapsedClockCycles(void);

private:
__int64 Freq; //Clock cycles per millisecond.

__int64 Start;
__int64 End;
__int64 Delta;
__int64 Overhead;
};


CClock::CClock()
{
__int64 Freq =0; //Clock cycles per millisecond.

__int64 Start =0;
__int64 End =0;
__int64 Delta =0;
__int64 Overhead=0;

//If this fails the frequency (freq) will remain 0.
QueryPerformanceFrequency((LARGE_INTEGER*)&Freq);

//Calculate Overhead

Reset();
ElapsedClockCycles();
Overhead = Delta;

}

inline void CClock::Reset(void)
{
Sleep(0); //A thread can relinquish the remainder of its time slice by calling

//this function with a sleep time of zero milliseconds. We do this to

//ensure short timings arn''t interupted by the scheduler. (Average
//desktop schedule time is 40ms)
if (Freq)
{
__int64 tempStart=0;
__asm
{
__emit 0x0f // RDTSC - read time-stamp counter

__emit 0x31
mov dword ptr [tempStart],eax
mov dword ptr [tempStart+4],edx
}
Start=tempStart;
}
else
Start = (__int64)(GetTickCount()*1000);

}


inline unsigned long CClock::ElapsedMilliseconds(void)
{
if (Freq)
{
__int64 tempEnd=0;
__asm
{
__emit 0x0f // RDTSC - read time-stamp counter

__emit 0x31
mov dword ptr [tempEnd],eax
mov dword ptr [tempEnd+4],edx
}
End=tempEnd;
}
else
End = (__int64)(GetTickCount()*1000);

return (unsigned long)(1000*(End-Start));
}


inline unsigned long CClock::ElapsedClockCycles(void)
{
__int64 tempEnd=0;
__asm
{
__emit 0x0f // RDTSC - read time-stamp counter

__emit 0x31
mov dword ptr [tempEnd],eax
mov dword ptr [tempEnd+4],edx
}
End=tempEnd;
Delta = End - Start - Overhead;
return (unsigned long)(Delta);
}


void main (void)
{
CClock *Clock = new CClock;
Clock->Reset();
cout << Clock->ElapsedClockCycles();
}


However this returns grossly incorrect results in release mode. Now since I added a little more code now it''s grossly wrong in debug as well. I *think* that when you get problems between release and debug it means uninitialised variables.

I performed a test. The Freq variable in release mode doesn''t seem to retain it''s data once I leave the constructor... Whats up with that? Its a class scope variable???

The other problem I seem to have here is that My class private data is not available from within the assembler. Should I be able to do that?

gimp

Share this post


Link to post
Share on other sites