processor frequency
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)?
our new version has many new and good features. sadly, the good ones are not new and the new ones are not good
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.
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.
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.
you mean i should share an object (or a pointer to a object) to every unit, that contains the elapsed time?
well...
and this is the unit's func:
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.position.x += _units.orientation.x*elapsedTime;<br> _units.position.y += _units.orientation.y*elapsedTime;<br> _units.position.z += _units.orientation.z*elapsedTime;<br><br> _units.orientation.x += _units.isTurningX*elapsedTime*_units.omegaX;<br> _units.orientation.y += _units.isTurningY*elapsedTime*_units.omegaY;<br> _units.orientation.z += _units.isTurningZ*elapsedTime*_units.omegaZ;<br> }<br> }<br> }<br></code><br><br>now this should work…?<br>p.s. how do i make a code box in in a posting?<br><br><SPAN CLASS=editedby>[edited by - 666_1337 on March 7, 2003 11:12:41 AM]</SPAN> </i>
our new version has many new and good features. sadly, the good ones are not new and the new ones are not good
[source]< /source > //but same format as above
[edited by - kordova on March 7, 2003 11:23:23 AM]
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
PerfTimer.c
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 operationprotected: 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 threadspublic: 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 operatorinline const CPerfTimer& CPerfTimer::operator=(const CPerfTimer& Src) { Copy(Src); return *this; }// Math operatorsinline 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 secondsinline 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 operatorsinline 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 secondsinline 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; }
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
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]
pseudo code
// globalDWORD 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]
Evillive2
March 07, 2003 06:25 PM
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...
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...
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
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
Always remember, you''re unique. Just like everyone else.Greven
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement