[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