Archived

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

666_1337

processor frequency

Recommended Posts

666_1337    122
hi everybody. i''m writing a game with thousands of things moving arround. since every object is isolated from from most of the other objects, i have to calculate the elapsed time for every unit. ... there''s now about one million gettimeofday calls per sec, and i thought i could speed things up using the 686-assembly rdtsc-command. ... asm("rdtsc\n" "mov %%edx, %0\n" "mov %%eax, 1+%0\n" :"=m"(_time) ; well... now i have the actual processor clocks stored in _time. and substracting the old amount of processor clocks gets me "delta clocks". now i would need to divide this value by the processor''s frequency. but where do i get it from (I of course know it, but i need to run this code on other machines)?

Share this post


Link to post
Share on other sites
Tybalt    122
You could simplyfy this by using QueryPerformanceFrequency and it''s associated timer/counter.

Why would you call gettimeofday one million times per second. Surely just call it once per second. It''s not likely to change much in the next second.

Share this post


Link to post
Share on other sites
Michalson    1657
You''d have to get it the same way any other app gets it (like DXDiag): By using the actual clock and measuring how many clock cycles happen in a certain amount of time (so 1 million cycles in 1 second would mean 1MHz). The longer the amount of time the more accurate, but keep in mind that clock speed is *NOT* a reliable way to measure time. The rdtsc opcodes are meant for performance profiling on a known machine. Many (and pretty soon all) laptops can vary their clockspeed in realtime in order to conserve battery power, and you''ll likely see this coming to the desktop too (the Pentium 4 already does this in response to temperature). Instead of doing many doing many timeofday calls, why not do one timeofday call for every X units, and cache the result.

Share this post


Link to post
Share on other sites
666_1337    122
you mean i should share an object (or a pointer to a object) to every unit, that contains the elapsed time?

well...

void display(void)
{
struct timeval t;
gettimeofday(&t, NULL);
float delta_T = _t.tv_sec - time.tv_sec + ((_t.tv_usec - time.tv_usec) / 1.0E6);
time = t;

glClear(GL_COLOR_BUFFER_BITS | GL_ACCUM_BUFFER_BITS | GL_DEPTH_BUFFER_BITS | GL_STENCIL_BUFFER_BITS);
glMatrixMode(GL_PROJECTION);
glLoadMatrix(g_projection_matrix);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-cam -> xRot, 1, 0, 0);
glRotatef(-cam -> yRot, 0, 1, 0);
glRotatef(-cam -> zRot, 0, 0, 1);
glTranslatef( -cam->position.x, -cam->position.y, cam->position.z);

glGetFloatv(GL_MODELVIEW_MATRIX, modl);
g_viewfrustum -> refresh(g_projection_matrix, modl);
g_unit_root -> refreshPositions(delta_T);
g_terrain -> draw();
g_unit_root -> drawAll();
cam -> drawInfos(delta_T);

glutSwapBuffers();
}

and this is the unit's func:

void unitController :: refreshPositions(float elapsedTime)
{
int i;
for(i = 0; i < MAX_UNITS_ACTIVE; i++)
{
if(_units.isUsed)
{
_units[i].position.x += _units[i].orientation.x*elapsedTime;
_units[i].position.y += _units[i].orientation.y*elapsedTime;
_units[i].position.z += _units[i].orientation.z*elapsedTime;

_units[i].orientation.x += _units[i].isTurningX*elapsedTime*_units[i].omegaX;
_units[i].orientation.y += _units[i].isTurningY*elapsedTime*_units[i].omegaY;
_units[i].orientation.z += _units[i].isTurningZ*elapsedTime*_units[i].omegaZ;
}
}
}


now this should work...?
p.s. how do i make a code box in in a posting?

[edited by - 666_1337 on March 7, 2003 11:12:41 AM]

Share this post


Link to post
Share on other sites
taZman    122
I would suggest QueryPerformanceCounter to...There is one issue with using it though...Not on processors support it, though must new ones should..

here is what I use for timing...
PerfTimer.h

  
/*

This class is simple to use. Just declare a variable(s) as type CPerfTimer,
call Start() to start timimg and call Stop() to stop timimg. You can pause a
timer by calling Stop() and then you can call Start() to resume. Retrieve the
elapsed time by calling an Elapsed..() function. Assignment, addition,
subtraction and comparison are supported. There are a few information calls
available also. All calls except Start and Stop can be performed on a timer
without stopping it.

*/


#ifndef __PERFTIMER_H__
#define __PERFTIMER_H__

class CPerfTimer
{
public:
CPerfTimer(BOOL bStart = FALSE) {Init(bStart);}

CPerfTimer(const CPerfTimer& Src);

virtual ~CPerfTimer() {;}

void Start(BOOL bReset = FALSE); // Start from current value or optionally from 0

void Stop(); // Stop timing. Use Start afterwards to continue.


BOOL IsRunning(); // Returns FALSE if stopped.


BOOL IsSupported(); // Returns FALSE if performance counter not supported.

// Call after constructing at least one CPerfTimer


const double Resolution(); // Returns timer resolution in seconds

const double Resolutionms(); // Returns timer resolution in milliseconds

const double Resolutionus(); // Returns timer resolution in microseconds


const double Elapsed(); // Returns elapsed time in seconds

const double Elapsedms(); // Returns elapsed time in milliseconds

const double Elapsedus(); // Returns elapsed time in microseconds


const CPerfTimer& operator=(const CPerfTimer& Src); // Assignment operator


// Math operators

CPerfTimer operator+(const CPerfTimer& Src) const;
CPerfTimer operator-(const CPerfTimer& Src) const;
const CPerfTimer& operator+=(const CPerfTimer& Src);
const CPerfTimer& operator-=(const CPerfTimer& Src);
// For time in seconds

CPerfTimer operator+(const double Secs) const;
CPerfTimer operator-(const double Secs) const;
const CPerfTimer& operator+=(const double Secs);
const CPerfTimer& operator-=(const double Secs);

// Boolean comparison operators

BOOL operator<(const CPerfTimer& Src);
BOOL operator>(const CPerfTimer& Src);
BOOL operator<=(const CPerfTimer& Src);
BOOL operator>=(const CPerfTimer& Src);
// For time in seconds

BOOL operator<(const double Secs);
BOOL operator>(const double Secs);
BOOL operator<=(const double Secs);
BOOL operator>=(const double Secs);

virtual void Lock() const {;} // Override for thread safe operation

virtual void Unlock() const {;} // Override for thread safe operation

protected:
void Init(BOOL bStart);
void Copy(const CPerfTimer& Src);

private:
__int64 m_Start;
static __int64 m_Freq; // does not change while system is running

static __int64 m_Adjust; // Adjustment time it takes to Start and Stop

};

class CPerfTimerT : public CPerfTimer
{ // You only need to use types of this class if a timer is going to be shared between threads

public:
CPerfTimerT(BOOL bStart = FALSE)
{
m_hMutex = CreateMutex(NULL,FALSE,"");
Init(bStart);
}

CPerfTimerT(const CPerfTimerT& Src)
{
m_hMutex = CreateMutex(NULL,FALSE,"
");
Copy(Src);
}

CPerfTimerT(const CPerfTimer& Src)
{
m_hMutex = CreateMutex(NULL,FALSE,"
");
Copy(Src);
}

virtual ~CPerfTimerT()
{ CloseHandle(m_hMutex); }

const CPerfTimerT& operator=(const CPerfTimerT& Src) // Assignment operator

{
Copy(Src);
return *this;
}

virtual void Lock() const { WaitForSingleObject(m_hMutex,10000); }
virtual void Unlock() const { ReleaseMutex(m_hMutex); }
private:
HANDLE m_hMutex;
};

inline void CPerfTimer::Init(BOOL bStart)
{
if (!m_Freq)
{ // Initialization should only run once

QueryPerformanceFrequency((LARGE_INTEGER *)&m_Freq);
if (!m_Freq)
m_Freq = 1; // Timer will be useless but will not cause divide by zero

m_Start = 0;
m_Adjust = 0;
Start(); // Time a Stop

Stop();
m_Adjust = m_Start;
}
// This is the only part that normally runs

m_Start = 0;
if (bStart)
Start();
}

inline CPerfTimer::CPerfTimer(const CPerfTimer& Src)
{
Copy(Src);
}

inline void CPerfTimer::Copy(const CPerfTimer& Src)
{
if (&Src == this)
return; // avoid deadlock if someone tries to copy it to itself

Src.Lock();
Lock();
m_Start = Src.m_Start;
Unlock();
Src.Unlock();
}

inline void CPerfTimer::Start(BOOL bReset)
{ // Start from current value or optionally from 0

__int64 i;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
Lock();
if ((!bReset) && (m_Start < 0))
m_Start += i; // We are starting with an accumulated time

else
m_Start = i; // Starting from 0

Unlock();
}

inline void CPerfTimer::Stop()
{ // Stop timing. Use Start afterwards to continue

Lock();
if (m_Start <= 0)
{
Unlock();
return; // Was not running

}
__int64 i;
QueryPerformanceCounter((LARGE_INTEGER *)&i);
m_Start += -i; // Stopped timer keeps elapsed timer ticks as a negative

if (m_Start < m_Adjust) // Do not overflow

m_Start -= m_Adjust; // Adjust for time timer code takes to run

else
m_Start = 0; // Stop must have been called directly after Start

Unlock();
}

inline BOOL CPerfTimer::IsRunning()
{ // Returns FALSE if stopped.

Lock();
BOOL bRet = (m_Start > 0); // When < 0, holds elpased clicks

Unlock();
return bRet;
}
inline const double CPerfTimer::Elapsed()
{ // Returns elapsed time in seconds

CPerfTimer Result(*this);
Result.Stop();
return (double)(-Result.m_Start)/(double)m_Freq;
}

inline const double CPerfTimer::Elapsedms()
{ // Returns elapsed time in milliseconds

CPerfTimer Result(*this);
Result.Stop();
return (-Result.m_Start*1000.0)/(double)m_Freq;
}

inline const double CPerfTimer::Elapsedus()
{ // Returns elapsed time in microseconds

CPerfTimer Result(*this);
Result.Stop();
return (-Result.m_Start * 1000000.0)/(double)m_Freq;
}


// Assignment operator

inline const CPerfTimer& CPerfTimer::operator=(const CPerfTimer& Src)
{
Copy(Src);
return *this;
}


// Math operators

inline CPerfTimer CPerfTimer::operator+(const CPerfTimer& Src) const
{
CPerfTimer Result(*this);
Result += Src;
return Result;
}

inline CPerfTimer CPerfTimer::operator-(const CPerfTimer& Src) const
{
CPerfTimer Result(*this);
Result -= Src;
return Result;
}

inline const CPerfTimer& CPerfTimer::operator+=(const CPerfTimer& Src)
{
CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped

SrcStop.Stop();
Lock();
m_Start += SrcStop.m_Start;
Unlock();
return *this;
}

inline const CPerfTimer& CPerfTimer::operator-=(const CPerfTimer& Src)
{
CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped

SrcStop.Stop();
Lock();
m_Start -= SrcStop.m_Start;
Unlock();
return *this;
}

// For time in seconds

inline CPerfTimer CPerfTimer::operator+(const double Secs) const
{
CPerfTimer Result(*this);
Result += Secs;
return Result;
}

inline CPerfTimer CPerfTimer::operator-(const double Secs) const
{
CPerfTimer Result(*this);
Result += Secs;
return Result;
}

inline const CPerfTimer& CPerfTimer::operator+=(const double Secs)
{
Lock();
m_Start -= (__int64)(Secs*(double)m_Freq);
Unlock();
return *this;
}

inline const CPerfTimer& CPerfTimer::operator-=(const double Secs)
{
Lock();
m_Start += (__int64)(Secs*(double)m_Freq);
Unlock();
return *this;
}



// Boolean comparison operators

inline BOOL CPerfTimer::operator<(const CPerfTimer& Src)
{
BOOL bRet;
CPerfTimer Temp(Src);
Lock();
if (m_Start <= 0)
{
Temp.Stop();
bRet = (m_Start > Temp.m_Start);
Unlock();
return bRet;
}
else
if (Temp.m_Start > 0)
{
bRet = (m_Start < Temp.m_Start);
Unlock();
return bRet;
}
else
{
Unlock();
CPerfTimer ThisStop(*this);
ThisStop.Stop();
return (ThisStop.m_Start > Temp.m_Start);
}
}

inline BOOL CPerfTimer::operator>(const CPerfTimer& Src)
{
BOOL bRet;
CPerfTimer Temp(Src);
Lock();
if (m_Start <= 0)
{
Temp.Stop();
bRet = (m_Start < Temp.m_Start);
Unlock();
return bRet;
}
else
if (Temp.m_Start > 0)
{
bRet = (m_Start > Temp.m_Start);
Unlock();
return bRet;
}
else
{
Unlock();
CPerfTimer ThisStop(*this);
ThisStop.Stop();
return (ThisStop.m_Start < Temp.m_Start);
}
}

inline BOOL CPerfTimer::operator<=(const CPerfTimer& Src)
{
return !(*this > Src);
}

inline BOOL CPerfTimer::operator>=(const CPerfTimer& Src)
{
return !(*this < Src);
}

// For time in seconds

inline BOOL CPerfTimer::operator<(const double Secs)
{
BOOL bRet;
Lock();
if (m_Start <= 0)
{
bRet = (m_Start > (__int64)(-Secs*(double)m_Freq));
Unlock();
return bRet;
}
else
{
Unlock();
CPerfTimer ThisStop(*this);
ThisStop.Stop();
return (ThisStop.m_Start > (__int64)(-Secs*(double)m_Freq));
}
}

inline BOOL CPerfTimer::operator>(const double Secs)
{
BOOL bRet;
Lock();
if (m_Start <= 0)
{
bRet = (m_Start < (__int64)(-Secs*(double)m_Freq));
Unlock();
return bRet;
}
else
{
Unlock();
CPerfTimer ThisStop(*this);
ThisStop.Stop();
return (ThisStop.m_Start < (__int64)(-Secs*(double)m_Freq));
}
}

inline BOOL CPerfTimer::operator<=(const double Secs)
{
return !(*this > Secs);
}

inline BOOL CPerfTimer::operator>=(const double Secs)
{
return !(*this < Secs);
}

#endif //__PERFTIMER_H__



PerfTimer.c

  
#include "stdafx.h"
#include "PerfTimer.h"

// Declare and initialize static member vars that get set only once and never change

__int64 CPerfTimer::m_Freq = 0;
__int64 CPerfTimer::m_Adjust = 0;

// All functions defined inline for speed. After all, the performance counter is

// supposed to be able to time very short events fairly accurately.




BOOL CPerfTimer::IsSupported()
{ // Returns FALSE if performance counter not supported.

// Call after constructing at least one CPerfTimer

return (m_Freq > 1);
}

const double CPerfTimer::Resolution()
{ // Returns timer resolution in seconds

return 1.0/(double)m_Freq;
}

const double CPerfTimer::Resolutionms()
{ // Returns timer resolution in milliseconds

return 1000.0/(double)m_Freq;
}

const double CPerfTimer::Resolutionus()
{ // Returns timer resolution in microseconds

return 1000000.0/(double)m_Freq;
}

Share this post


Link to post
Share on other sites
evillive2    779
I think what your saying is that you are making a query to the time elapsed for each object and are looking for a way to reduce the overhead of doing this thousands of times each loop cycle? If this is the case, then QueryPerformaceCounter is probably the worst choice to do this with since it comes with the most overhead (from what I have read here in the forums anyway compared to GetTickCount/timeGetTime). How about having a global or static current_time that gets updated right before you start your loop through thousands of items and using that value to get your time delta for each object instead of making thousands of calls to your get time function? Or at least only update it every x amount of iterations through the loop...

pseudo code

// global
DWORD current_time = timeGetTime();
void game_loop()
{
// one call to the time function at the beginning
current_time = timeGetTime();
// ... loop through all the objects
int timeDelta = current_time - obj->last_update;
// ... do stuff with timeDelta
obj->last_update = current_time;
//... etc
}


I think I just repeated what Michalson was saying... I hope it helped...

edit: some of the spelling errors... man I suck at typeing


[edited by - evillive2 on March 7, 2003 1:53:17 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
good call..This gaming thing is still new to me...QueryPerformanceCounter is about the highest accuracy you can acheive but it does come at a cost...

Share this post


Link to post
Share on other sites
taZman    122
good call..This gaming thing is still new to me...QueryPerformanceCounter is about the highest accuracy you can acheive but it does come at a cost...

Share this post


Link to post
Share on other sites
Greven    100
May I suggest another alternative. On Win2K, and XP you can grab the registry key:
HKLM/HARDWARE/DESCRIPTION/System/CentralProcessor/0/~MHz
And if they have two processors you will also see a 1 key. It''s not guaranteed to be there I don''t believe, and it isn''t always completely accurate. But it sure does work well. Also in that key is the processor type, so you can tell if it''s an AMD, Intel, etc. Works pretty well. I''m not sure if it''s on 98, I haven''t run that for a while...




Always remember, you''''re unique. Just like everyone else.

Greven

Share this post


Link to post
Share on other sites
666_1337    122
sorry for not having said you earlier, but i use gcc on linux. there is no stdafx.h. to compile the source you(tazMan)'ve written there i've needed to add

    
#define BOOL int
#define FALSE 0
#define TRUE 1
#define NULL 0
#define __int64 long long

to the source, and i still have about one page of compiler error messages.

my original problem was, that time calling functions use to be inaccurate or inefficient on my machine. anyone knows an iso-c++ function to get the time? (getClock() gets me the time with a half second of precission. but i need it to be in at last 1/100 seconds).

[edited by - 666_1337 on March 9, 2003 4:55:14 AM] [/source]

[edited by - 666_1337 on March 9, 2003 4:55:42 AM]

Share this post


Link to post
Share on other sites