svn commit: r195714 - in stable/7/sys: . contrib/pf dev/acpica
Alexander Motin
mav at FreeBSD.org
Thu Jul 16 08:27:13 UTC 2009
Author: mav
Date: Thu Jul 16 08:27:12 2009
New Revision: 195714
URL: http://svn.freebsd.org/changeset/base/195714
Log:
MFC rev. 191760, 191763, 191764.
Avoid comparing negative signed to positive unsignad values. It was
leading to a bug, when C-state does not decrease on sleep shorter then
declared transition latency. Fixing this deprecates workaround for broken
C-states on some hardware.
By the way, change state selecting logic a bit. Instead of last sleep
time use short-time average of it. Global interrupts rate in system is a
quite random value, to corellate subsequent sleeps so directly.
Make dev.cpu.X.cx_usage sysctl also report current average of sleep time.
Modified:
stable/7/sys/ (props changed)
stable/7/sys/contrib/pf/ (props changed)
stable/7/sys/dev/acpica/acpi_cpu.c
Modified: stable/7/sys/dev/acpica/acpi_cpu.c
==============================================================================
--- stable/7/sys/dev/acpica/acpi_cpu.c Wed Jul 15 22:27:36 2009 (r195713)
+++ stable/7/sys/dev/acpica/acpi_cpu.c Thu Jul 16 08:27:12 2009 (r195714)
@@ -79,7 +79,6 @@ struct acpi_cpu_softc {
int cpu_features; /* Child driver supported features. */
/* Runtime state. */
int cpu_non_c3; /* Index of lowest non-C3 state. */
- int cpu_short_slp; /* Count of < 1us sleeps. */
u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
/* Values for sysctl. */
struct sysctl_ctx_list cpu_sysctl_ctx;
@@ -875,43 +874,13 @@ acpi_cpu_idle()
return;
}
- /*
- * If we slept 100 us or more, use the lowest Cx state. Otherwise,
- * find the lowest state that has a latency less than or equal to
- * the length of our last sleep.
- */
- cx_next_idx = sc->cpu_cx_lowest;
- if (sc->cpu_prev_sleep < 100) {
- /*
- * If we sleep too short all the time, this system may not implement
- * C2/3 correctly (i.e. reads return immediately). In this case,
- * back off and use the next higher level.
- * It seems that when you have a dual core cpu (like the Intel Core Duo)
- * that both cores will get out of C3 state as soon as one of them
- * requires it. This breaks the sleep detection logic as the sleep
- * counter is local to each cpu. Disable the sleep logic for now as a
- * workaround if there's more than one CPU. The right fix would probably
- * be to add quirks for system that don't really support C3 state.
- */
- if (mp_ncpus < 2 && sc->cpu_prev_sleep <= 1) {
- sc->cpu_short_slp++;
- if (sc->cpu_short_slp == 1000 && sc->cpu_cx_lowest != 0) {
- if (sc->cpu_non_c3 == sc->cpu_cx_lowest && sc->cpu_non_c3 != 0)
- sc->cpu_non_c3--;
- sc->cpu_cx_lowest--;
- sc->cpu_short_slp = 0;
- device_printf(sc->cpu_dev,
- "too many short sleeps, backing off to C%d\n",
- sc->cpu_cx_lowest + 1);
- }
- } else
- sc->cpu_short_slp = 0;
-
- for (i = sc->cpu_cx_lowest; i >= 0; i--)
- if (sc->cpu_cx_states[i].trans_lat <= sc->cpu_prev_sleep) {
- cx_next_idx = i;
- break;
- }
+ /* Find the lowest state that has small enough latency. */
+ cx_next_idx = 0;
+ for (i = sc->cpu_cx_lowest; i >= 0; i--) {
+ if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) {
+ cx_next_idx = i;
+ break;
+ }
}
/*
@@ -936,10 +905,10 @@ acpi_cpu_idle()
/*
* Execute HLT (or equivalent) and wait for an interrupt. We can't
* calculate the time spent in C1 since the place we wake up is an
- * ISR. Assume we slept one quantum and return.
+ * ISR. Assume we slept half of quantum and return.
*/
if (cx_next->type == ACPI_STATE_C1) {
- sc->cpu_prev_sleep = 1000000 / hz;
+ sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + 500000 / hz) / 4;
acpi_cpu_c1();
return;
}
@@ -982,9 +951,9 @@ acpi_cpu_idle()
}
ACPI_ENABLE_IRQS();
- /* Find the actual time asleep in microseconds, minus overhead. */
+ /* Find the actual time asleep in microseconds. */
end_time = acpi_TimerDelta(end_time, start_time);
- sc->cpu_prev_sleep = PM_USEC(end_time) - cx_next->trans_lat;
+ sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + PM_USEC(end_time)) / 4;
}
/*
@@ -1106,8 +1075,9 @@ acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARG
sbuf_printf(&sb, "%u.%02u%% ", (u_int)(whole / sum),
(u_int)(fract / sum));
} else
- sbuf_printf(&sb, "0%% ");
+ sbuf_printf(&sb, "0.00%% ");
}
+ sbuf_printf(&sb, "last %dus", sc->cpu_prev_sleep);
sbuf_trim(&sb);
sbuf_finish(&sb);
sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
More information about the svn-src-stable
mailing list