From owner-svn-src-head@FreeBSD.ORG Tue Jul 31 10:58:51 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 56152106564A; Tue, 31 Jul 2012 10:58:51 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 40D5D8FC16; Tue, 31 Jul 2012 10:58:51 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q6VAwp30019780; Tue, 31 Jul 2012 10:58:51 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q6VAwp18019777; Tue, 31 Jul 2012 10:58:51 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201207311058.q6VAwp18019777@svn.freebsd.org> From: Alexander Motin Date: Tue, 31 Jul 2012 10:58:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r238943 - head/sys/dev/acpica X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 31 Jul 2012 10:58:51 -0000 Author: mav Date: Tue Jul 31 10:58:50 2012 New Revision: 238943 URL: http://svn.freebsd.org/changeset/base/238943 Log: 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. Sponsored by: iXsystems, Inc. Modified: head/sys/dev/acpica/acpi_cpu.c Modified: head/sys/dev/acpica/acpi_cpu.c ============================================================================== --- head/sys/dev/acpica/acpi_cpu.c Tue Jul 31 08:05:40 2012 (r238942) +++ head/sys/dev/acpica/acpi_cpu.c Tue Jul 31 10:58:50 2012 (r238943) @@ -876,7 +876,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); sbuf_trim(&sb); sbuf_finish(&sb); } @@ -921,6 +922,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; @@ -960,11 +962,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; } } @@ -980,11 +983,10 @@ acpi_cpu_idle() * we are called inside critical section, delaying context switch. */ 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 = PM_USEC(acpi_TimerDelta(end_time, start_time)); - if (curthread->td_critnest == 0) + 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; @@ -1008,7 +1010,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); /* @@ -1018,7 +1026,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 && @@ -1028,8 +1040,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; }