Stuart McLachlan
stuart at lexacorp.com.pg
Tue Feb 10 23:09:32 CST 2009
JC is using the timeGetTime() API call. Windows95/98 has a 1ms resolution for this W2K/XP generally have a resolution of about 10ms My Vista machiine has a resolution of 1ms, so it looks as though MS may have fixed this. Note however: - you can use the timeBeginPeriod() API call to increase the granularity in W2K/XP. - it is a low priority call and can be delayed or even dropped if the queue is busy. Another problem is that it rolls over every 49 days so there is a *very* slight possibility that the Stop time may be much smaller than the Start time. If your programmers want accurate time, they should be using QueryPerformanceFrequency and QueryPerformanceCounter, using them you can get sub- microsecond (close to nanosecond) accuracy. Try pasting this into a Module and see what your numbers are like. <start code> Option Explicit Declare Function QueryPerformanceCounter Lib "Kernel32" _ (X As Currency) As Boolean Declare Function QueryPerformanceFrequency Lib "Kernel32" _ (X As Currency) As Boolean Declare Function GetTickCount Lib "Kernel32" () As Long Declare Function timeGetTime Lib "winmm.dll" () As Long Sub Test_Timers() Dim Ctr1 As Currency, Ctr2 As Currency, Freq As Currency Dim Count1 As Long, Count2 As Long, Loops As Long ' ' Time QueryPerformanceCounter ' If QueryPerformanceCounter(Ctr1) Then QueryPerformanceCounter Ctr2 Debug.Print "Start Value: "; Format$(Ctr1, "0.0000") Debug.Print "End Value: "; Format$(Ctr2, "0.0000") QueryPerformanceFrequency Freq Debug.Print "QueryPerformanceCounter minimum resolution: 1/" & _ Freq * 10000; " sec" Debug.Print "API Overhead: "; (Ctr2 - Ctr1) / Freq; "seconds" Else Debug.Print "High-resolution counter not supported." End If ' ' Time GetTickCount ' Debug.Print Loops = 0 Count1 = GetTickCount() Do Count2 = GetTickCount() Loops = Loops + 1 Loop Until Count1 <> Count2 Debug.Print "GetTickCount minimum resolution: "; _ (Count2 - Count1); "ms" Debug.Print "Took"; Loops; "loops" ' ' Time timeGetTime ' Debug.Print Loops = 0 Count1 = timeGetTime() Do Count2 = timeGetTime() Loops = Loops + 1 Loop Until Count1 <> Count2 Debug.Print "timeGetTime minimum resolution: "; _ (Count2 - Count1); "ms" Debug.Print "Took"; Loops; "loops" End Sub <end code> On 11 Feb 2009 at 15:35, MACE, Terry wrote: > John, > > When I run this I get times of 15,31,16,31,16, 109 or some numbers very > close to these. Programmers I work with (I'm not one) tell me that while > the tick count may be a 1mS interval, Windows XP cannot display time at > anywhere near this resolution and effectively time samples, hence the > results I'm getting. > > This operation of Windows (inability to have time to less than 10mS) > prevents them from having a Windows based system for their application. > > Regards > > Terry Mace > Logistics Support Officer & Maintenance Supervisor > > > -----Original Message----- > From: accessd-bounces at databaseadvisors.com > [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of jwcolby > Sent: Wednesday, 11 February 2009 4:08 AM > To: Access Developers discussion and problem solving > Subject: [AccessD] Classes and Events - EVENTS NOT REQUIRED > > To this point the classes we have looked at were specifically designed > to allow you to "wrap" an > object that generates events and add code and variables to process those > events. This lecture will > demonstrate that classes have other uses and do not have to wrap other > objects. > > The class introduced today will be clsTimer, a means of timing events > (things happening) in your > code. The class is perhaps the simplest class I have ever written, and > perhaps the simplest class > you will ever see. > > * Click Insert / Class > * Save immediately as clsTimer > * Insert the following code into the class: > > Private Declare Function apiGetTime Lib "winmm.dll" _ > Alias "timeGetTime" () As Long > > Private lngStartTime As Long > > Private Sub Class_Initialize() > StartTimer > End Sub > > Function EndTimer() > EndTimer = apiGetTime() - lngStartTime > End Function > > Sub StartTimer() > lngStartTime = apiGetTime() > End Sub > > * Compile and save the class. > > Notice that in the header of the class we have a function definition > apiGetTime that calls out to > Windows. This function gets the windows tick timer and has a resolution > of 1 millisecond, or one > thousandth of a second. This simply means that we can't time anything > that takes less than one > thousandth of a second without resorting to timing it several times. It > returns a long integer that > is simply an absolute number of "ticks". Since when? It doesn't > matter, it is just "this is the > tick count RIGHT NOW". > > To compute a "time" (and we aren't really doing that, we are calculating > a time since the first > time), you get the tick count and store it, then later you get another > tick and compare it to the > first tick. The difference is the number of 1000ths of a second since > the first tick count. > > Notice that we have no mInit() method in this class. Notice also that > the Class_Initialize calls > the StartTimer() function. As you know now, the Class_Initialize is a > class event that fires as the > class loads, so this tells the class to load the first tick time as soon > as the class instance loads. > > In the header of the class we dimensioned a long variable lngStartTime. > This will be used to store > the starting tick count. StartTimer() simply calls out to Windows, gets > the current tick count from > Windows, and stores that count to lngStartTime. > > EndTimer() simply calls out to Windows again to get the current tick > count, subtracts the current > count to the previous count stored in lngStartTime and returns that > count to you the programmer. > > That's it folks! This class has in the header a function definition to > call Windows and a place to > store the count. In the body of the class it then has two methods to > start the "timer" and to > return the ticks since the timer started. You are not going to see many > classes simpler than that. > > So let's discuss why we need to encapsulate this in a class. You might > be saying that you can do > the same thing without the class but a class allows you to create as > many of these timers as you > want. Let's build some test code to see how this thing works and why we > might need several. > > * In the tools menu click Insert / MODULE. We are building a > normal module this time, NOT a class > module. > * Immediately save the module as basTimerTest > * Into this new module insert the following code: > > Function TmrTest() > Dim lngCtr1 As Long > Dim lngCtr2 As Long > Dim clsTmr1 As clsTimer > Dim clsTmr2 As clsTimer > > Set clsTmr1 = New clsTimer > For lngCtr1 = 1 To 5 > Set clsTmr2 = New clsTimer > For lngCtr2 = 1 To 100000 > Pi > Next lngCtr2 > Debug.Print clsTmr2.EndTimer > Next lngCtr1 > Debug.Print clsTmr1.EndTimer > End Function > > Function Pi() As Double > Dim dblPi As Double > dblPi = 4 * Atn(1) > Pi = dblPi > End Function > > Notice that we dim two timers, then we SET the timers on the outside of > their respective loops. As > you know, the SET statement loads the class, at which point the > Class_Initialize fires which grabs > the first timer tick from windows. > > The Debug.Print statement simply calls the .EndTimer method of the class > and prints it to the debug > window. > > Voila, a timer, with a resolution of one thousandth of a second. > > TmrTest simulates a real world code where you have two loops, and inner > loop and an outer loop. > > The inner loop times how long it takes to calculate Pi. Notice that > modern computers are so fast > that I have to do it a hundred thousand times in order to get enough > "tick counts" (thousandths of a > second) to even get a number to use. The outer loop simply times how > long it takes to run the inner > loop 5 times. > > I have intentionally kept this thing simple, but your outer loop might > time how long it takes to > read a thousand records and the inner loop might be replaced with timing > how long it takes to ... > transform a string from comma delimited to pipe delimited or something > like that. > > In this lecture we have demonstrated that a class encapsulates all of > the code required to perform > its function, plus the variables required to store its data. It also > demonstrates that you can use > as many instances of the class as you need. If you need one or a > hundred timers, you just dim and > SET the variables and you are off to the races so to speak. > > Classes are used to encapsulate code and data required to implement a > system. You're your > imagination is the only limit to what that system can be. > > -- > John W. Colby > www.ColbyConsulting.com > -- > AccessD mailing list > AccessD at databaseadvisors.com > http://databaseadvisors.com/mailman/listinfo/accessd > Website: http://www.databaseadvisors.com > "Warning: > The information contained in this email and any attached files is > confidential to BAE Systems Australia. If you are not the intended > recipient, any use, disclosure or copying of this email or any > attachments is expressly prohibited. If you have received this email > in error, please notify us immediately. VIRUS: Every care has been > taken to ensure this email and its attachments are virus free, > however, any loss or damage incurred in using this email is not the > sender's responsibility. It is your responsibility to ensure virus > checks are completed before installing any data sent in this email to > your computer." > > > > -- > AccessD mailing list > AccessD at databaseadvisors.com > http://databaseadvisors.com/mailman/listinfo/accessd > Website: http://www.databaseadvisors.com