[flashrom] [PATCH] Handle insufficient DOS timer precision

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Thu Jun 3 15:44:14 CEST 2010


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 <c-d.hailfinger.devel.2006 at gmx.net>

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/





More information about the flashrom mailing list