Arthur,
the real time clock could be run from any frequency of crystal but 32,768Hz is the most common because it's cheap, low frequency (and therefore low power) and divides easily to give seconds.
Paul.
Announcement
Collapse
No announcement yet.
Discussion of 'Timer Macros' in Source Code forum
Collapse
X
-
Originally posted by Paul Dixon View PostIn order to determine real frequency you'll need a known independent clock. The only one in the PC is the real time clock which has its own crystal.
I think this clock is running at about 32767 hertz, or I'm wrong?
Leave a comment:
-
Hi Paul
For me, what the crystal oscillates at and what multiplier is used is academic. The system tells me what the Performance Counter frequency is from QueryPerformanceFrequency.
All I'm doing is to take a snapshot of the Time Stamp Counter, let the Performance Counter run for 10 seconds, according to the frequency, and then take another snapshot of the Time Stamp Counter. All the tests that I have done show that the Performance Counter and the Time Stamp Counter are 'ticking' over at the same rate; or differ by an insignificant amount for the purposes of comparing code snippets.
> but if they're both derived from the same crystal then that doesn't give a very useful result
Well, actually it does.
The issue in the Source Code forum is can I use TIX and the frequency of the Performance Counter in the same breath, so to speak.
Well, I cannot find any evidence to suggest that I should not use
Code:Tix qTimer For i = 1 To 10000000 t = Rnd Next Tix End qTimer sTimeTaken = Using$("#####.##",qTimer*1000/qFreq) + "ms"
I found an interesting discussion here and downloaded CpuClockSpeed.zip. The Preformance Counter is used here as well.
This gave 2666.91Mhz. My Performance Counter frequency for this Window's session is 2666910000.
If the code two posts back gives widely differing frequencies then the Performance Counter frequency should not be used in the snippet above as we may not get accurate millisecond results; we would have to determine a multiplier.
For comparing code it depends how we make the comparison. If we are concerned about overhead then it will be eliminated by subtracting results. If we are concerned about the ticks to time conversion this will be eliminated on division since '1000/qFreq' will be in both the numerator and denominator.
I think that our discussion has drifted somewhat - getting an accurate figure for the CPU speed has not being my concern - the relationship between the two Counters is what I've been concerned about.
David,
that won't work. TIX is counting CPU clock cycles, QueryPerformanceFrequency is getting the frequency of the high speed timer which is a different timer running a lot slower than the CPU.
the CPU and the high performance counters have the same base crystal.Last edited by David Roberts; 28 Aug 2008, 10:30 AM. Reason: Forgot to put in link to other discussion.
Leave a comment:
-
David,
The Performance Counters generally run at 3.579545MHz (or sometimes half that, 1.789772.5MHz) which is derived from the original timers of the PC from years ago. The cheapest clock crystal around was the NTSC colour burst frequency crystal so to save a few pennies that was used in the PC.
Your code precalculates the result of the performance counter because you use:
Code:qTargetPerfCtr = qTargetPerfCtr + qPerfFreq*10
You could use the performance counter as a base for timing the CPU but if they're both derived from the same crystal then that doesn't give a very useful result either although it could tell you the multiplier used inside the PC.
Your measurements come out around 2.6669GHz for the CPU. 2666900000 / 3579545 = 745.03 so it's likely that your internal multiplier is 745 and that your CPU is really running at 745*3.579545MHz = 2.666761GHz.
In order to determine real frequency you'll need a known independent clock. The only one in the PC is the real time clock which has its own crystal.
Paul.
Leave a comment:
-
Thanks Paul.
> ... so it wouldn't be surprising if you eliminated all the errors and found that TIX and Performance counters kept step with each other.
It seems to be so with my system.
The following code takes a stab at getting the frequency of the Time Stamp Counter. It simply takes a snapshot of the Time Stamp Counter, runs with the Performance Counter for 10 seconds and then takes another snapshot of the Time Stamp Counter. Other code that I have seen uses a one second interval. Completion is determined when a target counter is passed and there may be a small 'overshoot'. With a 10 second span divided by 10 this 'overshoot' will be reduced by a factor of 10. 24 tests are carried out, with a pause of one and two seconds between tests, and the two largest and the two smallest are discarded. The code will, then take between four and five minutes to run.
With one trial I got a TSC frequency of 2666870024 compared with a PC frequency of 2666870000. I had rebooted since my earlier posts which had a PC frequency of 2666880000.
Here's a couple more, after reboots, 2666899823/2666900000 and 2666939894/2666940000.
On my system, then I can use the Performance Counter frequency to convert TIX returns to time as in the Source Code forum. This is recommended if timing code is to be used in different Window's sessions as we may get different tick counts.
In view of your comments it may be worthwhile for folks to run the following before accepting my 'PBWin9 & PBCC5 version' of my timer macros.
Added:
> TIX definitely uses the time stamp counter.
I, how can I put it, had a close 'look' and indeed it does.
Code:' PBCC 5 #Compile Exe #Optimize speed #Register None #Dim All #Tools Off %NOMMIDS = 1 %NOGDI = 1 #Include "WIN32API.INC" Function PBMain() As Long Local qPerfFreq, qTSFreq, qTargetPerfCtr, qCurrentPerfCtr, qTSCbegin, qTSCend, Tot As Quad Local i As Long Dim x(1 To 24) As Quad ' If you have a single core remove the next three lines Local hProcess As Dword hProcess = GetCurrentProcess() SetProcessAffinityMask( hProcess, 1) ' ie CPU 0 QueryPerformanceFrequency qPerfFreq For i = 1 To 24 ' We will only use 20 QueryPerformanceCounter qTargetPerfCtr ' Determine Performance Counter in 10 seconds time qTargetPerfCtr = qTargetPerfCtr + qPerfFreq*10 ' Take a snapshot of Time Stamp Counter !RDTSC !lea esi, qTSCbegin !mov [esi], eax !mov [esi+4], edx Do QueryPerformanceCounter qCurrentPerfCtr Loop While qCurrentPerfCtr < qTargetPerfCtr ' We pull out then when qCurrentPerfCtr >= qTargetPerfCtr ' Take another snapshot at, or earliest after, qTargetPerfCtr !RDTSC !lea esi, qTSCend !mov [esi], eax !mov [esi+4], edx x(i) = (qTSCend - qTSCbegin)\10 ' Our 10 seconds again Sleep Rnd(1000,2000) ' Avoid looping 'back to back' Next Array Sort x() For i = 3 To 22 ' Throw out the two largest and the two smallest Tot = Tot + x(i) Next qTSFreq = Tot/20 Print "Time Stamp Counters per second ";qTSFreq Print "Performance Counters per second";qPerfFreq Print "Difference"; Abs(qTSFreq - qPerfFreq) Waitkey$ End Function
Last edited by David Roberts; 27 Aug 2008, 01:54 PM.
Leave a comment:
-
David,
TIX definitely uses the time stamp counter.
TIX QuadVal reads the time stamp counter into QuadVal giving the number of CPU ticks since the CPU was last reset.
TIX END QuadVal reads the timestamp counter, subracts QuadVal and puts the result back into QuadVal so giving the elapsed number of CPU ticks.
Paul.
Edit: most clocks in the computer apart from the Real Time Clock are derived from the same crystal so it wouldn't be surprising if you eliminated all the errors and found that TIX and Performance counters kept step with each other.Last edited by Paul Dixon; 25 Aug 2008, 02:39 PM.
Leave a comment:
-
Paul
!RDTSC - very posh!
I've rewritten the above - that 'time1 = time' was badly placed.
Added cpuid and threw in an #optimize speed.
Code:Function PBMain() As Long Local time1, time2, time As Quad, hProcess As Dword, t1, t2 As Dword Ptr InitializeTimer ' If you have single core remove the next two lines hProcess = GetCurrentProcess() SetProcessAffinityMask( hProcess, 1) ' ie CPU 0 ' Time Stamp t1 = VarPtr(time1) t2 = VarPtr(time2) !cpuid !RDTSC !mov esi, t1 !mov [esi], eax !mov [esi+4], edx Sleep 100000 !cpuid !RDTSC !mov esi, t2 !mov [esi], eax !mov [esi+4],edx Print time2 - time1 ' TIX TIX Time Sleep 100000 TIX End time Print time ' Performnce counters StartTimer Sleep 100000 StopTimer Print qStop - qStart Waitkey$ End Function
266684375520
266664862270
266664661980
That Time Stamp figure is edging toward the figure got from 'QueryPerformanceFrequency qFreq' at 266688000000 for a 'perfect' Sleep 100000.
Added: The last two figures are pushing seven significant figure coincidence. I reckon that TIX is not reading the Time Stamp but is using the Performance counters.Last edited by David Roberts; 25 Aug 2008, 02:12 PM.
Leave a comment:
-
David,
with PBCC5 you can use !RDTSC to read the time stamp counter instead of !DW &H310f. Much nicer!
TIX just reads the time stamp counter anyway and stores it in the specified QUAD so you no longer need the read it and store it explicitly in ASM, just use TIX/TIX END instead.
I don't like
CPUfreq = TSC/((cnt2-cnt1)/freq) ...... (1)
Maybe I should have been more explicit and said:
Code:TimeTaken=(cnt2-cnt1)/freq CPUFreq=TSC/TimeTaken.
Leave a comment:
-
> I'm looking at something else which seems to cast doubt on my using the frequency of the high resolution timer but I cannot quite get my head around the results yet.
Forget that - the method used is suspect.
Have a look at this:
Code:#Compile Exe #Register None #Dim All #TOOLS OFF %NOMMIDS = 1 %NOGDI = 1 #Include "WIN32API.INC" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Global qFreq, qOverhead, qStart, qStop As Quad Global f As String Macro InitializeTimer f = "#####.##" QueryPerformanceFrequency qFreq QueryPerformanceCounter qStart ' Intel suggestion. First use may be suspect QueryPerformanceCounter qStart ' So, wack it twice <smile> QueryPerformanceCounter qStop qOverhead = qStop - qStart ' Relatively small End Macro Macro StartTimer = QueryPerformanceCounter qStart Macro StopTimer = QueryPerformanceCounter qStop Macro sTimeTaken = Using$(f,(qStop - qStart - qOverhead)*1000/qFreq) + "ms" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Function PBMain() As Long Local time1, time As Quad, hProcess As Dword, t As Dword Ptr InitializeTimer ' If you have single core remove the next two lines hProcess = GetCurrentProcess() SetProcessAffinityMask( hProcess, 1) ' ie CPU 0 ' Time Stamp t = VarPtr(time) !dw &h310f !mov esi, t !mov [esi], eax !mov [esi+4],edx time1 = time Sleep 100000 !dw &h310f !mov esi, t !mov [esi], eax !mov [esi+4],edx Print time - time1 ' TIX TIX time Sleep 100000 TIX End time Print time ' Performnce counters StartTimer Sleep 100000 StopTimer Print qStop - qStart Waitkey$ End Function
266660772380
266664907340
266664675970
If we have a time of a few hundred milliseconds then using 'QueryPerformanceFrequency qFreq' instead of one of the above will 'throw' our timing out by a few hundredths of a millisecond. I won't be losing much Sleep over that.
Leave a comment:
-
If you really want to get some indication of how long SLEEP or any other function takes to execute, you might just want to put it in its own procedure and enable PROFILE. That will tell you how many times and much total time your program spent in that procedure.
PROFILE is a terrific tool for optimization in that it tells you where your program is spending most of its time.... that is, where a little extra effort can actually deliver some benefit.
The caution here is, PROFILE itself requires some overhead, so what it tells you is the relative times each procedure of your program is taking.. not the absolute time when the program is run in production ("#TOOLS OFF") mode.
But as I said in the other forum, SLEEP() is not designed to be used as a timer, so the information you would gather from using PROFILE or any other tool in this exercise is meaningless.
MCM
Leave a comment:
-
Discussion of 'Timer Macros' in Source Code forum
Paul
I don't like
CPUfreq = TSC/((cnt2-cnt1)/freq) ...... (1)
If we tidy that up we get
CPUfreq = k * freq where k = TSC/(cnt2-cnt1) ...... (2)
From your code
TSC = X + Execution time of QPC + TIX overhead
cnt2 - cnt1 = Execution time of TIX + X + QPC overhead
where X = Sleep 1000
The influence of the execution times and overheads diminishes as the time to execute X increases.
On my machine, freq = 2,666,880,000
Sleep 1000 => CPUfreq = 2,666,882,926
Sleep 10000 => CPUfreq = 2,666,880,292
Sleep 60000 => CPUfreq = 2,666,880,048
In maths jargon, as X tends to infinity CPUfreq tends to freq.
TIX overhead?
TIX TIXOverhead
TIX End TIXOverhead
on my machine gives TIXOverhead of 70 CPU cycles.
Unless my logic is up the 'Swanee', (1) is not the way to go to give a time element to TIX.
I'm looking at something else which seems to cast doubt on my using the frequency of the high resolution timer but I cannot quite get my head around the results yet.Last edited by David Roberts; 25 Aug 2008, 04:54 AM.Tags: None
Leave a comment: