Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Nov 2012 16:19:28 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r243563 - stable/8/sys/dev/acpica
Message-ID:  <201211261619.qAQGJS3X026972@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Nov 26 16:19:27 2012
New Revision: 243563
URL: http://svnweb.freebsd.org/changeset/base/243563

Log:
  MFC r238943:
  Add several performance optimizations to acpi_cpu_idle().
  
  For C1 and C2 states use cpu_ticks() to measure sleep time instead of much
  slower ACPI timer. We can't do it for C3, as TSC may stop there. But it is
  less important there as wake up latency is high any way.
  
  For C1 and C2 states do not check/clear bus mastering activity status, as
  it is important only for C3. As side effect it can make CPU enter C2 instead
  of C3 if last BM activity was two sleeps back (unlike one before), but
  that may be even good because of collecting more statistics. Premature BM
  wakeup from C3, entered because of overestimation, can easily be worse then
  entering C2 from both performance and power consumption points of view.
  
  Together on dual Xeon E5645 system on sequential 512 bytes read test this
  change makes cpu_idle_acpi() as fast as simplest cpu_idle_hlt() and only
  few percents slower then cpu_idle_mwait(), while deeper states are still
  actively used during idle periods.
  
  To help with diagnostics, add C-state type into dev.cpu.X.cx_supported.
  
  PR:             kern/170021

Modified:
  stable/8/sys/dev/acpica/acpi_cpu.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/acpica/   (props changed)

Modified: stable/8/sys/dev/acpica/acpi_cpu.c
==============================================================================
--- stable/8/sys/dev/acpica/acpi_cpu.c	Mon Nov 26 15:34:28 2012	(r243562)
+++ stable/8/sys/dev/acpica/acpi_cpu.c	Mon Nov 26 16:19:27 2012	(r243563)
@@ -864,7 +864,8 @@ acpi_cpu_cx_list(struct acpi_cpu_softc *
     sbuf_new(&sb, sc->cpu_cx_supported, sizeof(sc->cpu_cx_supported),
 	SBUF_FIXEDLEN);
     for (i = 0; i < sc->cpu_cx_count; i++) {
-	sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cpu_cx_states[i].trans_lat);
+	sbuf_printf(&sb, "C%d/%d/%d ", i + 1, sc->cpu_cx_states[i].type,
+	    sc->cpu_cx_states[i].trans_lat);
 	if (sc->cpu_cx_states[i].type < ACPI_STATE_C3)
 	    sc->cpu_non_c3 = i;
     }
@@ -912,6 +913,7 @@ acpi_cpu_idle()
 {
     struct	acpi_cpu_softc *sc;
     struct	acpi_cx *cx_next;
+    uint64_t	cputicks;
     uint32_t	start_time, end_time;
     int		bm_active, cx_next_idx, i;
 
@@ -947,11 +949,12 @@ acpi_cpu_idle()
      * driver polling for new devices keeps this bit set all the
      * time if USB is loaded.
      */
-    if ((cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0) {
+    if ((cpu_quirks & CPU_QUIRK_NO_BM_CTRL) == 0 &&
+	cx_next_idx > sc->cpu_non_c3) {
 	AcpiReadBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, &bm_active);
 	if (bm_active != 0) {
 	    AcpiWriteBitRegister(ACPI_BITREG_BUS_MASTER_STATUS, 1);
-	    cx_next_idx = min(cx_next_idx, sc->cpu_non_c3);
+	    cx_next_idx = sc->cpu_non_c3;
 	}
     }
 
@@ -966,12 +969,12 @@ acpi_cpu_idle()
      * is an ISR.  Assume we slept no more then half of quantum.
      */
     if (cx_next->type == ACPI_STATE_C1) {
-	AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
+	cputicks = cpu_ticks();
 	acpi_cpu_c1();
-	AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
-        end_time = acpi_TimerDelta(end_time, start_time);
-	sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 +
-	    min(PM_USEC(end_time), 500000 / hz)) / 4;
+	end_time = ((cpu_ticks() - cputicks) << 20) / cpu_tickrate();
+	if (curthread->td_critnest == 0)
+		end_time = min(end_time, 500000 / hz);
+	sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + end_time) / 4;
 	return;
     }
 
@@ -993,7 +996,13 @@ acpi_cpu_idle()
      * get the time very close to the CPU start/stop clock logic, this
      * is the only reliable time source.
      */
-    AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
+    if (cx_next->type == ACPI_STATE_C3) {
+	AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
+	cputicks = 0;
+    } else {
+	start_time = 0;
+	cputicks = cpu_ticks();
+    }
     CPU_GET_REG(cx_next->p_lvlx, 1);
 
     /*
@@ -1003,7 +1012,11 @@ acpi_cpu_idle()
      * margin that we are certain to have a correct value.
      */
     AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
-    AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+    if (cx_next->type == ACPI_STATE_C3) {
+	AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+	end_time = acpi_TimerDelta(end_time, start_time);
+    } else
+	end_time = ((cpu_ticks() - cputicks) << 20) / cpu_tickrate();
 
     /* Enable bus master arbitration and disable bus master wakeup. */
     if (cx_next->type == ACPI_STATE_C3 &&
@@ -1013,8 +1026,6 @@ acpi_cpu_idle()
     }
     ACPI_ENABLE_IRQS();
 
-    /* Find the actual time asleep in microseconds. */
-    end_time = acpi_TimerDelta(end_time, start_time);
     sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + PM_USEC(end_time)) / 4;
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211261619.qAQGJS3X026972>