Closed Bug 176881 Opened 22 years ago Closed 22 years ago

PRInterval timers may be incorrect on Windows with processor speed > 4 GHz

Categories

(NSPR :: NSPR, defect, P1)

x86
Windows XP
defect

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: wtc, Assigned: wtc)

Details

Attachments

(4 files, 1 obsolete file)

In ntmisc.c, we have void _PR_MD_INTERVAL_INIT() { LARGE_INTEGER count; if (QueryPerformanceFrequency(&count)) { while(count.LowPart > PR_INTERVAL_MAX) { count.LowPart >>= 1; _nt_bitShift++; _nt_highMask = (_nt_highMask << 1)+1; } _nt_ticksPerSec = count.LowPart; PR_ASSERT(_nt_ticksPerSec > PR_INTERVAL_MIN); } else _nt_ticksPerSec = -1; } Note that the code assumes count.HighPart is 0 and ignores it. count.LowPart is an unsigned 32-bit integer (DWORD). On some computers, the result returned by QueryPerformanceFrequency will be the clock speed of the CPU, and our code will break if the processor runs faster than 2^32 Hz, or ~ 4 GHz.
Summary: PRInterval timers may be incorrect on Windows with processor speed >= 4 GHz → PRInterval timers may be incorrect on Windows with processor speed > 4 GHz
Attached patch Proposed patch (obsolete) (deleted) — Splinter Review
Mike, I'd appreciate it if you could review this patch. With this patch, NSPR no longer ignores the high 32 bits of the performance counter frequency. I also cleaned up the code a little bit. 1. I found that _nt_highMask is not really necessary and deleted it. 2. I replaced the multiple-step computation of the current time stamp into a single arithmetic expression in _PR_MD_GET_INTERVAL. I don't know why the original code does the shifting and addition in separate statements and reuses count.LowPart to store the intermediate and final results. I think combining these statements into one expression makes the code easier to understand.
Attached patch Proposed patch v2 (deleted) — Splinter Review
Please use this patch instead. The previous patch was generated from an unreleased version of the file.
Attachment #109124 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Priority: -- → P1
Target Milestone: --- → 4.3
I tested this code on my machine, which has a frequency of 3579545ticks/sec (less than 32 bits). It tests fine in that case and does not differ from the original implementation. But I don't have a higher frequency clock to test with here, so I can't test that case. Visual inspection looks right. To be honest, I wonder if we aren't over-engineering here. Do we really need a sub-millisecond timer? Maybe just obliterate all this stuff and use GetTickCount() (units in milliseconds, 10ms resolution). There are enough platform-specific warnings in the MSFT documentation that I don't really trust QueryPerformanceCounter() to work in a portable way (MP issues, clock speed issues, HW issues). I'm pretty sure that attempting to use it will have future incompatibilities which we can probably avoid by using a more supported call.
On current processors we need to patch the NSPR library to artificially make the performance counter frequency greater than 4 GHz. The patches will be attached next.
Apply this patch to mozilla/nsprpub/pr/src/md/windows/ntinrval.c, rev. 3.8. Adjust the value of SHIFT until 'freq' is more than 32 bits. Then run the test program against the modified NSPR library. You'll see that the elapsed time is larger than 1000 ms (the expected value).
Apply this patch to mozilla/nsprpub/pr/src/md/windows/ntinrval.c, rev. 3.10. Adjust the value of SHIFT until 'freq' is more than 32 bits. (This step actually requires running the test program, which prints the value of 'freq'.) Then run the test program against the modified NSPR library. You'll see that the elapsed time is 1000 ms (the expected value).
Mike, Thank you for the code review. I've checked in the patch. I agree that QueryPerformanceCounter() has many problems and I will consider using GetTickCount(). The purpose of this bug is to document a potential problem of our code, just in case someone will install old NSPR releases (<= 4.2.2) on a 4GHz machine. I hope we can track down the causes of the problems reported in the original bug about PRIntervalTime (bug 115865) before making the decision to switch from QueryPerformanceCounter() to GetTickCount(). In the meantime I want to fix this known bug in our code.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: