On 02.06.2010 15:21, Carl-Daniel Hailfinger wrote:
> Do not trust the OS at all and measure timer precision before
> calibrating the delay loop and use that measurement to get reasonable
> precision for our own delay code.
>   

Changes in this patch:
Print a measurement for a delay of 4x the OS timer resolution.
Be precise about how bad the deviation was if we had to recalculate.

Tests on DOS and Windows appreciated. I tested on Linux.

Signed-off-by: Carl-Daniel Hailfinger <[email protected]>

Index: flashrom-measure_delay_precision_dos/udelay.c
===================================================================
--- flashrom-measure_delay_precision_dos/udelay.c       (Revision 1026)
+++ flashrom-measure_delay_precision_dos/udelay.c       (Arbeitskopie)
@@ -37,6 +37,30 @@
        }
 }
 
+unsigned long measure_os_delay_resolution(void)
+{
+       unsigned long timeusec;
+       struct timeval start, end;
+       unsigned long counter = 0;
+       
+       gettimeofday(&start, 0);
+       timeusec = 0;
+       
+       while (!timeusec && (++counter < 1000000000)) {
+               gettimeofday(&end, 0);
+               timeusec = 1000000 * (end.tv_sec - start.tv_sec) +
+                          (end.tv_usec - start.tv_usec);
+               /* Protect against time going forward too much. */
+               if ((end.tv_sec > start.tv_sec) &&
+                   ((end.tv_sec - start.tv_sec) >= LONG_MAX / 1000000 - 1))
+                       timeusec = 0;
+               /* Protect against time going backwards during leap seconds. */
+               if ((end.tv_sec < start.tv_sec) || (timeusec > LONG_MAX))
+                       timeusec = 0;
+       }
+       return timeusec;
+}
+
 unsigned long measure_delay(int usecs)
 {
        unsigned long timeusec;
@@ -61,10 +85,16 @@
 void myusec_calibrate_delay(void)
 {
        unsigned long count = 1000;
-       unsigned long timeusec;
+       unsigned long timeusec, resolution;
        int i, tries = 0;
 
        msg_pinfo("Calibrating delay loop... ");
+       resolution = measure_os_delay_resolution();
+       if (resolution) {
+               msg_pdbg("OS timer resolution is %u usecs, ", resolution);
+       } else {
+               msg_pinfo("OS timer resolution is unusable. ");
+       }
 
 recalibrate:
        count = 1000;
@@ -94,9 +124,25 @@
                 * a scheduler delay or something similar.
                 */
                for (i = 0; i < 4; i++) {
-                       if (measure_delay(100) < 90) {
-                               msg_pdbg("delay more than 10%% too short, "
-                                        "recalculating... ");
+                       if (resolution && (resolution < 10)) {
+                               timeusec = measure_delay(100);
+                       } else if (resolution && (resolution < ULONG_MAX / 
200)) {
+                               timeusec = (measure_delay(resolution * 10) * 
100) / (resolution * 10);
+                       } else {
+                               /* This workaround should be active for broken
+                                * OS and maybe libpayload. The criterion
+                                * here is horrible or non-measurable OS timer
+                                * resolution which will result in
+                                * measure_delay(100)=0 whereas a longer delay
+                                * (1000 ms) may be sufficient
+                                * to get a nonzero time measurement.
+                                */
+                               timeusec = measure_delay(1000000) / 10000;
+                       }
+                       if (timeusec < 90) {
+                               msg_pdbg("delay more than 10%% too short (got "
+                                        "%lu%% of expected delay), "
+                                        "recalculating... ", timeusec);
                                goto recalibrate;
                        }
                }
@@ -113,6 +159,8 @@
        msg_pdbg("1000 myus = %ld us, ", timeusec);
        timeusec = measure_delay(10000);
        msg_pdbg("10000 myus = %ld us, ", timeusec);
+       timeusec = measure_delay(resolution * 4);
+       msg_pdbg("%ld myus = %ld us, ", resolution * 4, timeusec);
 
        msg_pinfo("OK.\n");
 }


-- 
http://www.hailfinger.org/


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to