git: 53880f09fb1b - main - acpi: add counters for cumulative time spent in each sleep state.

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Tue, 11 Nov 2025 20:45:24 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=53880f09fb1b485cf5c4af2b81081112e0c7cea3

commit 53880f09fb1b485cf5c4af2b81081112e0c7cea3
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2025-11-07 03:45:24 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2025-11-11 20:45:09 +0000

    acpi: add counters for cumulative time spent in each sleep state.
    
    Add this so it can be consumed/graphed.
    
    Differential Revision:  https://reviews.freebsd.org/D53633
    Reviewed by:    gallatin, imp
---
 sys/dev/acpica/acpi_cpu.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index f9b9a386c0c5..2cd6c8bd4758 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -92,6 +92,7 @@ struct acpi_cpu_softc {
     int			 cpu_non_c2;	/* Index of lowest non-C2 state. */
     int			 cpu_non_c3;	/* Index of lowest non-C3 state. */
     u_int		 cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
+    uint64_t		 cpu_cx_duration[MAX_CX_STATES];/* Cx cumulative sleep */
     /* Values for sysctl. */
     struct sysctl_ctx_list cpu_sysctl_ctx;
     struct sysctl_oid	*cpu_sysctl_tree;
@@ -185,6 +186,7 @@ static void	acpi_cpu_quirks(void);
 static void	acpi_cpu_quirks_piix4(void);
 static int	acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARGS);
 static int	acpi_cpu_usage_counters_sysctl(SYSCTL_HANDLER_ARGS);
+static int	acpi_cpu_duration_counters_sysctl(SYSCTL_HANDLER_ARGS);
 static int	acpi_cpu_set_cx_lowest(struct acpi_cpu_softc *sc);
 static int	acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS);
 static int	acpi_cpu_global_cx_lowest_sysctl(SYSCTL_HANDLER_ARGS);
@@ -1055,6 +1057,12 @@ acpi_cpu_startup_cx(struct acpi_cpu_softc *sc)
 	"cx_usage_counters", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
 	(void *)sc, 0, acpi_cpu_usage_counters_sysctl, "A",
 	"Cx sleep state counters");
+    SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
+        SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)), OID_AUTO,
+	"cx_duration_counters", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+	(void *)sc, 0, acpi_cpu_duration_counters_sysctl, "A",
+	"Cx sleep duration cumulative time");
+
 #if defined(__i386__) || defined(__amd64__)
     SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
         SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)), OID_AUTO,
@@ -1168,6 +1176,7 @@ acpi_cpu_idle(sbintime_t sbt)
 	if (!cx_next->do_mwait && curthread->td_critnest == 0)
 		end_time = min(end_time, 500000 / hz);
 	sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + end_time) / 4;
+	sc->cpu_cx_duration[cx_next_idx] += end_time;
 	return;
     }
 
@@ -1224,6 +1233,7 @@ acpi_cpu_idle(sbintime_t sbt)
     else
 	end_time = ((end_ticks - start_ticks) << 20) / cpu_tickrate();
     sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + end_time) / 4;
+    sc->cpu_cx_duration[cx_next_idx] += end_time;
 }
 #endif
 
@@ -1408,6 +1418,26 @@ acpi_cpu_usage_counters_sysctl(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
+static int
+acpi_cpu_duration_counters_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct acpi_cpu_softc *sc = (struct acpi_cpu_softc *)arg1;
+	struct sbuf	 sb;
+	char		 buf[128];
+	int		 error, i;
+
+	sbuf_new_for_sysctl(&sb, buf, sizeof(buf), req);
+	for (i = 0; i < sc->cpu_cx_count; i++) {
+		if (i > 0)
+			sbuf_putc(&sb, ' ');
+		sbuf_printf(&sb, "%ju", (uintmax_t) sc->cpu_cx_duration[i]);
+	}
+	error = sbuf_finish(&sb);
+	sbuf_delete(&sb);
+	return (error);
+}
+
+
 #if defined(__i386__) || defined(__amd64__)
 static int
 acpi_cpu_method_sysctl(SYSCTL_HANDLER_ARGS)