| Page 5 Timing an Event in DataFlexby Curtis KrauskopfUsing SYSDATE 
                          for Microsecond TimingWith 
                          some clever tinkering, we now have the tools to be able 
                          to have SYSDATE and SYSDATE4 tell us (indirectly) in 
                          what fraction of a second an event happened. This technique 
                          is so accurate that it is able to tell me, within 40 
                          microseconds (0.000040 seconds), how long an event took. In 
                          delay.src, 
                          I showed how we could synchronize the start of an event 
                          with the beginning of a second. Since we have the program's 
                          execution synchronized with the system clock, we can 
                          use that to our advantage by incrementing a counter 
                          during an entire second. That will tell us how many 
                          times the counter can be incremented on that hardware 
                          (based on its CPU and the DataFlex runtime that is executing). 
                           Once 
                          we have that information, we can then let the event 
                          that we're really interested in timing happen. When 
                          that finishes, we increment a different counter to count 
                          the amount of time that remained in the second after 
                          the event finished. Subtracting that number from the 
                          number of increments in a whole second will tell us 
                          what fraction of a second the event consumed. Here's 
                          a diagram of this whole process: 
 This 
                          diagram shows the following events: 
                           
                            | Second | Event |   
                            | :06 | The 
                              program starts at some fraction of a second after 
                              the system clock rolled over to the sixth second 
                              in the minute. The program immediately enters a 
                              wait loop that repeats until the clock rolls over 
                              to :07. |   
                            | :07 | The 
                              program calibrates itself by incrementing an integer 
                              for an entire second. This tells us how many times 
                              an integer can be incremented per second. |   
                            | :08 | The 
                                event being measured starts. In this example, 
                                it also stops in the same second, but that's not 
                                necessary. The event could stop in any second 
                                and the rest of this process would remain the 
                                same (and just as accurate). After 
                                the event stops, we immediately enter a loop that 
                                increments a different integer. The number of 
                                incrementations that are made before the next 
                                second (:09) tells us how much time was left after 
                                the event finished.  |   
                            | :09 | At 
                                :09, the loop that increments the second integer 
                                finishes and we can report the results. |  The 
                          equation to calculate the fraction of a second used 
                          by the event is in equation #1: 
                           
                            | (1) |  | amount_used  = | calibration - post_event calibration
 |  |  In 
                          equation 1, both calibration and post_event 
                          are the number of integer incrementations completed 
                          in the appropriate phases. calibration is incremented 
                          during an entire second to calibrate the number of integer 
                          increments that can happen per second. post_event 
                          is incremented immediately after the event being timed 
                          has finished. post_event indicates how much time 
                          was left in the second that the event stopped. As 
                          an example, let's say that the calibration phase incremented 
                          an integer 25,000 times. After the event, let's say 
                          that the second integer (post_event) incremented 
                          4,000 times. The fraction of a second used by the event 
                          is in equation #2: 
                           
                            | (2) |  | amount_used  = | 25000 - 4000 25000
 | =  0.84 seconds |  |  A 
                          DataFlex program that demonstrates this concept is: 
                           
                            | // accurate.src
// by Curtis Krauskopf at www.decompile.com
//
// This program shows how to make SYSDATE4 detect
// fractions of a second.  On a 1 Ghz Dell computer
// running DataFlex 3.1d, I'm able to get a
// resolution of 40 microseconds.
//
//
date today
integer hour minute second start
date before after
integer before_hour before_minute before_second
integer after_hour after_minute after_second
integer calibration
integer finish_ticks
// First phase:  Initialize all variables
move 0 to calibration
move 0 to finish_ticks
// Second phase:  enter a loop that waits until
// the second on the system clock changes.
sysdate4 today hour minute start
repeat
  sysdate4 today hour minute second
until start ne second
// Execution and the system clock are now synchronized.
// Enter a loop that increments a counter for an
// entire second.
repeat
  sysdate4 before before_hour before_minute before_second
  increment calibration
until before_second NE second
// Now that we have calibrated the number of integer
// increments per second, we can test how long our
// event takes:
showln "Press any key to stop the test."
string akey 1
inkey akey
// The event if finished, but we need to record the
// amount of time that is left in this second.
sysdate4 after after_hour after_minute after_second
repeat
  sysdate4 today hour minute second
  increment finish_ticks
until after_second NE second
// Now we can report how long the event took:
show   "Calibration recorded " calibration
showln " increments per second."
showln
show   "The event had " finish_ticks
showln " increments before the second changed."
showln
show   "The event took "
number before_time   // Accumulated number of seconds
number after_time
move (integer(before) * 3600 * 24) to before_time
move (before_time + (before_hour * 3600)) to before_time
move (before_time + (before_minute * 60)) to before_time
move (before_time + (before_second)) to before_time
move (integer(after) * 3600 * 24) to after_time
move (after_time + (after_hour * 3600)) to after_time
move (after_time + (after_minute * 60)) to after_time
move (after_time + (after_second)) to after_time
show (after_time - before_time)
// Fractional numbers converted to strings in DataFlex have
// a leading 0.  This block converts the result (a number)
// to a string and then removes the leading "0"
string result
move (number(calibration) - finish_ticks / calibration) to result
replace "0." in result with "."
show result
showln " seconds."
showln
showln
showln "Press any key to continue."
inkey akey
 |  The 
                          output for this program looks like this: On 
                          a Windows system, if you run the program several times 
                          (remember the rules 
                          of thumb when testing event timing on a computer), 
                          you might have noticed something odd. The calibration 
                          value reported in each test run might be different! Here 
                          are some snapshots of four test runs on my system running 
                          DataFlex 3.1d: The 
                          problem is that the Windows operating system is stealing 
                          timeslices from the program. If I boot to MS-Dos and 
                          run the same test program, I get calibration results 
                          that are only a few increments from each other. Copyright 
                          2003 The Database Managers, Inc. |