Skip to main content
gamedev.net
🔒 Locked

QueryPerformanceCounter

Started by randomname Oct 25, 2004 at 9:54 PM 16 replies 2.1k views
Original Post
randomname
randomname
I have debuged it ~3 hours (note: i CAN'T trace it!) and i just don't get what is wrong. In one place in my code (which is error free [as far as i can tell about one line of code]) QueryPerformanceCounter returns always 0 - and everywhere else what it is supposed to return. Provided that hardware supports it (and it sure as hell does) - it should NEVER fail - or what? ??? Any ideas?
LessBread
LessBread
"If the function fails, the return value is zero. To get extended error information, call GetLastError."

So what does GetLastError tell you?
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
randomname
randomname
It says: "The operation completed successfully.".
b2b3
b2b3
Try to call QueryPerformanceFrequency first. Then, if it fails (returns 0), test the value of LastError.
randomname
randomname
Haa! Found the problem (i think).
QueryPerformanceCounter goes nuts when the address modulo with 4 is not 0 ! (Likely a limitation of the rdtsc instruction. Can anyone confirm?)

0041503D Bad
00415091 Bad
00415154 Good
004151A8 Good
004294B4 Good

(That is what i found out - besides of a little syntactical problem in assert i had)

Now, why the hell are they not aligned to 4 (as i have set it to in project options)!?
izzo
izzo
Hm that's very odd, I don't know how likely that is. QueryPerformanceCounter accepts a LARGE_INTEGER which is just a 64-bit variable. Surely it doesn't matter if it's aligned or not? What are you passing in? Not that it should matter; it should just fill out that memory space that you pass in with the value.

cheers
sam
IFooBar
IFooBar
Just a thought, but just maybe, the value is being overwritten by an array over0run or something. A variable you declared before the LARGE_INTEGER might be oversteppings its memory bounds and going over the data in the LARGE_INTEGER.

int overarray[];LARGE_INTEGER li;QueryPerformaceCounter( &li );// <-- doing something with overarray here.cout<< li.QuadPart<< endl;


Just make sure you're checking 'li' right after you call QPC.


It's highly unlikely, but it *has* happened to me in the past so thought Id bring it up...
[size=2]aliak.net
randomname
randomname
Argh. The damn board logouts me silently all the time! Auto login doesn't seem to work at all somewhy!?

Yeah, the last anonymous is me.
izzo
izzo
Well it shouldn't re-order the elements in the struct. It will only align them, so it will (effectively) insert space into the struct. Were you passing that struct into QPC? Coz if so, then the struct that you pass in should probably look like the LARGE_INTEGER struct (i.e. it should be 64 bit - exactly - in size).

cheers
sam
LessBread
LessBread
LARGE_INTEGER needs an 8 byte alignment - which I believe is the default for MS - I could be wrong. This is more of an issue in contrasting LARGE_INTEGER with FILETIME - that is, don't pass a LARGE_INTEGER as a FILETIME and vice versa. For more info: Windows Data Alignment on IPF, x86, and x86-64. That link even has a sample using QPF and QPC.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
randomname
randomname
@izzo: "shouldn't re-order"
Aah... (mouth is singing and heart is worrying) c doesn't reorder anything - delphi/pascal does that. My bad.
Found out that by placing pack(1) pragma inside struct will do what i wanted - struct itself will be aligned to 4 and data in it to 1 (without inserting space to the end of struct).
No - i'm not giving a struct to QPC - just a __int64 subitem from it.

@LessBread: "LARGE_INTEGER needs an 8 byte alignment"
No. Where did you get that? Alignment of 1 is perfectly fine - just QPC triggers a error ... and somewhat rightfully so - when i think about it.

The execution time would depend on the address where the result is stored (non machine unit alignment and partial write and other odds). But for the funtion to be userful (in more demanding timings) - it's execution time should be constant. Still - it's stupid, it would make more sense to note it in spec and assume good pointers from users and not waste time for idiotic checks.

Btw: looked at intels instruction set spec (P4) and rdtsc returns it's value directly to EAX/EDX - no way to store it directly to some address.
randomname
randomname
Quote:
Original post by randomname
(non machine unit alignment and partial write and other odds)
\Me looks at QPC assembly: LOL, forget what i said. The way it does it - well, even if i call my grandmother and ask for time i'l likely get a more acurate answer. (Maybe not that bad, but you get the point).
LessBread
LessBread
Quote:
Original post by randomname
@LessBread: "LARGE_INTEGER needs an 8 byte alignment"
No. Where did you get that? Alignment of 1 is perfectly fine - just QPC triggers a error ... and somewhat rightfully so - when i think about it.


From Jeff Ricther's Advanced Windows 3rd Ed. page 446 in the discussion on SetWaitableTimer, "The address of all FILETIME structures must begin on an even 32-bit boundary, but the address of all LARGE_INTEGER structures must begin on an even 64-bit boundary."

The quote remains in the 4th edition (retitled "Programming Applications") in Chapter 9, "Waitable Timer Kernel Objects".
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
randomname
randomname
I see. Thanks. Did change the 8byte values to 8byte alignment anyway.

Why does Windows make such a pointless (look my previous post) constraint?
Jan Wassenberg
Jan Wassenberg
Quote:
Why does Windows make such a pointless (look my previous post) constraint?

hehe, not pointless.
Clues:
1) read the article LessBread provided about CPU alignment constraints (IA-32 pampers you; IA-64 does not).
2) the .QuadPart member allows the LARGE_INTEGER struct to be used as one 64-bit number.
Final piece of the puzzle: Windows API calls have to make sure user-specified addresses are valid before writing there. Due to the above, alignment checks are a part of that.

Quote:
Me looks at QPC assembly: LOL, forget what i said. The way it does it - well, even if i call my grandmother and ask for time i'l likely get a more acurate answer.

hmm. Why? What did you see there?
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
randomname
randomname
@Jan Wassenberg:
It's not timers job to care. A timer must have as less code as possible. But yeah - seems that QPC has got a lot of stuff todo (valid/aligned).

Win should provide a timer that does return its result in register(s) - me thinks.

"hmm. Why? What did you see there?"
Too much code ... just too much (i didn't even find the place where it gets the final value - it's prety annioning to trace. [especially as goes to int{whatever its number was} prety fast]).
Jan Wassenberg
Jan Wassenberg
Quote:
It's not timers job to care. A timer must have as less code as possible. But yeah - seems that QPC has got a lot of stuff todo (valid/aligned).

hehe. As annoying as it may seem, each routine that runs at CPL0 has to be paranoid about writing to memory. Mess up once, and the security of the entire system is compromised.

Quote:
Win should provide a timer that does return its result in register(s) - me thinks.

Windows is in theory portable, so you can't just specify that results go in e.g. edx:eax. There is such a calling convention on x86, but the C language return value is dedicated to returning the status (questionable but legit design decision).

Quote:
Too much code ... just too much (i didn't even find the place where it gets the final value - it's prety annioning to trace. [especially as goes to int{whatever its number was} prety fast]).

No one said QPC was simple :)
BTW, its complexity increases accuracy instead of the opposite - e.g. there is code to synchronize the timestamp counters between CPUs (on SMP systems). Now that would've been useful, if they hadn't gotten it wrong on earlier systems, and now everyone's writing their own workarounds.. sigh ;)
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.