From patchwork Thu Apr 1 11:45:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Pratik R. Sampat" X-Patchwork-Id: 12178713 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B9C5DC43461 for ; Thu, 1 Apr 2021 17:53:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 982BA61159 for ; Thu, 1 Apr 2021 17:53:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236107AbhDARxr (ORCPT ); Thu, 1 Apr 2021 13:53:47 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:8226 "EHLO mx0b-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236478AbhDARpM (ORCPT ); Thu, 1 Apr 2021 13:45:12 -0400 Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.43/8.16.0.43) with SMTP id 131BZGTV145437; Thu, 1 Apr 2021 07:45:15 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=LuDD8VzmtFl5Y8oY6EKB24UqifZWh7WEjtXEmMC2hko=; b=CEDmJcu9s1CXHGA8JMfcITgC0TvDAC7j2TisHYEu0TdjuWLgub1KNgzZeOkcTrhzcMix /fKHbDlt/SZnLAqeRoEWoVDijtDVTiXOXae+o+AJ+JGF/oPVJ9lbOi6sJjqUDROO8DpI li+EMT+fp+cP7zHejXKNpBuWqUscqcFbV5BNvO0Bw6UdE1hXjugGbRWqf671cMNy4E5M lg4Gna4q2hYpB/lEZOozEwycSH6/pf/3NAcWvzoiUOm8ZmbFQmUzYhKFgpNGDBfSH3PC Mu4ep8tQM0m/+JJROZRgG3gzhqvjsdWddQj8vXJoncAfqkz/SSufBfUiEwkUyCo+1zxI 1g== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 37n2ea13sp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 07:45:15 -0400 Received: from m0098421.ppops.net (m0098421.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 131BdBIe158179; Thu, 1 Apr 2021 07:45:14 -0400 Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 37n2ea13s2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 07:45:14 -0400 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.0.43/8.16.0.43) with SMTP id 131Bg5iD004696; Thu, 1 Apr 2021 11:45:12 GMT Received: from b06cxnps4074.portsmouth.uk.ibm.com (d06relay11.portsmouth.uk.ibm.com [9.149.109.196]) by ppma03ams.nl.ibm.com with ESMTP id 37n28rrev9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 11:45:12 +0000 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 131Bj9iW36307344 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 1 Apr 2021 11:45:09 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B17FDA4069; Thu, 1 Apr 2021 11:45:09 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 76415A4053; Thu, 1 Apr 2021 11:45:07 +0000 (GMT) Received: from pratiks-thinkpad.ibmuc.com (unknown [9.199.46.97]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP; Thu, 1 Apr 2021 11:45:07 +0000 (GMT) From: Pratik Rajesh Sampat To: rjw@rjwysocki.net, daniel.lezcano@linaro.org, shuah@kernel.org, dsmythies@telus.net, ego@linux.vnet.ibm.com, svaidy@linux.ibm.com, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, pratik.r.sampat@gmail.com, psampat@linux.ibm.com Subject: [RFC v2 1/2] cpuidle: Extract IPI based and timer based wakeup latency from idle states Date: Thu, 1 Apr 2021 17:15:03 +0530 Message-Id: <20210401114504.13466-2-psampat@linux.ibm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210401114504.13466-1-psampat@linux.ibm.com> References: <20210401114504.13466-1-psampat@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: pjj6RQbFSGyJlsuQ7MEJLwdjiD3ZVneC X-Proofpoint-ORIG-GUID: B8lTuSTebxeXt1Eq8NgfHj7w0yCUYSHu X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.369,18.0.761 definitions=2021-04-01_04:2021-03-31,2021-04-01 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 adultscore=0 bulkscore=0 clxscore=1015 impostorscore=0 spamscore=0 phishscore=0 mlxscore=0 lowpriorityscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2103310000 definitions=main-2104010082 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Introduce a mechanism to fire directed IPIs from a specified source CPU to a specified target CPU and measure the difference in time incurred on wakeup. Also, introduce a mechanism to queue a HR timer on a specified CPU and subsequently measure the time taken to wakeup the CPU. Finally define a simple debugfs interface to control the knobs to fire the IPI and Timer events on specified CPU and view their incurred idle wakeup latencies. Signed-off-by: Pratik Rajesh Sampat --- drivers/cpuidle/Makefile | 1 + drivers/cpuidle/test-cpuidle_latency.c | 157 +++++++++++++++++++++++++ lib/Kconfig.debug | 10 ++ 3 files changed, 168 insertions(+) create mode 100644 drivers/cpuidle/test-cpuidle_latency.c diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 26bbc5e74123..3b4ee06a9164 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o obj-$(CONFIG_DT_IDLE_STATES) += dt_idle_states.o obj-$(CONFIG_ARCH_HAS_CPU_RELAX) += poll_state.o obj-$(CONFIG_HALTPOLL_CPUIDLE) += cpuidle-haltpoll.o +obj-$(CONFIG_IDLE_LATENCY_SELFTEST) += test-cpuidle_latency.o ################################################################################## # ARM SoC drivers diff --git a/drivers/cpuidle/test-cpuidle_latency.c b/drivers/cpuidle/test-cpuidle_latency.c new file mode 100644 index 000000000000..f138011ac225 --- /dev/null +++ b/drivers/cpuidle/test-cpuidle_latency.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Module-based API test facility for cpuidle latency using IPIs and timers + */ + +#include +#include +#include + +/* + * IPI based wakeup latencies + * Measure time taken for a CPU to wakeup on a IPI sent from another CPU + * The latency measured also includes the latency of sending the IPI + */ +struct latency { + unsigned int src_cpu; + unsigned int dest_cpu; + ktime_t time_start; + ktime_t time_end; + u64 latency_ns; +} ipi_wakeup; + +static void measure_latency(void *info) +{ + struct latency *v; + ktime_t time_diff; + + v = (struct latency *)info; + v->time_end = ktime_get(); + time_diff = ktime_sub(v->time_end, v->time_start); + v->latency_ns = ktime_to_ns(time_diff); +} + +void run_smp_call_function_test(unsigned int cpu) +{ + ipi_wakeup.src_cpu = smp_processor_id(); + ipi_wakeup.dest_cpu = cpu; + ipi_wakeup.time_start = ktime_get(); + smp_call_function_single(cpu, measure_latency, &ipi_wakeup, 1); +} + +/* + * Timer based wakeup latencies + * Measure time taken for a CPU to wakeup on a timer being armed and fired + */ +struct timer_data { + unsigned int src_cpu; + u64 timeout; + ktime_t time_start; + ktime_t time_end; + struct hrtimer timer; + u64 timeout_diff_ns; +} timer_wakeup; + +static enum hrtimer_restart timer_called(struct hrtimer *hrtimer) +{ + struct timer_data *w; + ktime_t time_diff; + + w = container_of(hrtimer, struct timer_data, timer); + w->time_end = ktime_get(); + + time_diff = ktime_sub(w->time_end, w->time_start); + time_diff = ktime_sub(time_diff, ns_to_ktime(w->timeout)); + w->timeout_diff_ns = ktime_to_ns(time_diff); + return HRTIMER_NORESTART; +} + +static void run_timer_test(unsigned int ns) +{ + hrtimer_init(&timer_wakeup.timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + timer_wakeup.timer.function = timer_called; + timer_wakeup.src_cpu = smp_processor_id(); + timer_wakeup.timeout = ns; + timer_wakeup.time_start = ktime_get(); + + hrtimer_start(&timer_wakeup.timer, ns_to_ktime(ns), + HRTIMER_MODE_REL_PINNED); +} + +static struct dentry *dir; + +static int cpu_read_op(void *data, u64 *dest_cpu) +{ + *dest_cpu = ipi_wakeup.dest_cpu; + return 0; +} + +static int cpu_write_op(void *data, u64 value) +{ + run_smp_call_function_test(value); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(ipi_ops, cpu_read_op, cpu_write_op, "%llu\n"); + +static int timeout_read_op(void *data, u64 *timeout) +{ + *timeout = timer_wakeup.timeout; + return 0; +} + +static int timeout_write_op(void *data, u64 value) +{ + run_timer_test(value); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(timeout_ops, timeout_read_op, timeout_write_op, "%llu\n"); + +static int __init latency_init(void) +{ + struct dentry *temp; + + dir = debugfs_create_dir("latency_test", 0); + if (!dir) { + pr_alert("latency_test: failed to create /sys/kernel/debug/latency_test\n"); + return -1; + } + temp = debugfs_create_file("ipi_cpu_dest", + 0666, + dir, + NULL, + &ipi_ops); + if (!temp) { + pr_alert("latency_test: failed to create /sys/kernel/debug/ipi_cpu_dest\n"); + return -1; + } + debugfs_create_u64("ipi_latency_ns", 0444, dir, &ipi_wakeup.latency_ns); + debugfs_create_u32("ipi_cpu_src", 0444, dir, &ipi_wakeup.src_cpu); + + temp = debugfs_create_file("timeout_expected_ns", + 0666, + dir, + NULL, + &timeout_ops); + if (!temp) { + pr_alert("latency_test: failed to create /sys/kernel/debug/timeout_expected_ns\n"); + return -1; + } + debugfs_create_u64("timeout_diff_ns", 0444, dir, &timer_wakeup.timeout_diff_ns); + debugfs_create_u32("timeout_cpu_src", 0444, dir, &timer_wakeup.src_cpu); + pr_info("Latency Test module loaded\n"); + return 0; +} + +static void __exit latency_cleanup(void) +{ + pr_info("Cleaning up Latency Test module.\n"); + debugfs_remove_recursive(dir); +} + +module_init(latency_init); +module_exit(latency_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("Measuring idle latency for IPIs and Timers"); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2779c29d9981..60fa46a99a4f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1513,6 +1513,16 @@ config DEBUG_KOBJECT If you say Y here, some extra kobject debugging messages will be sent to the syslog. +config IDLE_LATENCY_SELFTEST + tristate "Cpuidle latency selftests" + depends on CPU_IDLE + help + This option provides a kernel module that runs tests using the IPI and + timers to measure latency. + + Say M if you want these self tests to build as a module. + Say N if you are unsure. + config DEBUG_KOBJECT_RELEASE bool "kobject release debugging" depends on DEBUG_OBJECTS_TIMERS From patchwork Thu Apr 1 11:45:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Pratik R. Sampat" X-Patchwork-Id: 12178675 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D483AC433ED for ; Thu, 1 Apr 2021 17:48:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A3282610A0 for ; Thu, 1 Apr 2021 17:48:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235746AbhDARsL (ORCPT ); Thu, 1 Apr 2021 13:48:11 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:10168 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236415AbhDARoo (ORCPT ); Thu, 1 Apr 2021 13:44:44 -0400 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.43/8.16.0.43) with SMTP id 131BXu5r129941; Thu, 1 Apr 2021 07:45:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=Vrdx2Ljxnx65oADxlH70GjkEAlD3nfLEnxBF6FzSihI=; b=cKDOlyFTig3hTgRk0bL9RGZESjbxViFws3ZLhqs0Pz62OoVMv2A6Q4YRE4pQhesbRFDB rT7PvLFyrIKxQLVO+7AZWt2azQ7zf4nLIlLcyNQhMM31ZNeBuFDzaX0kHcMRNV8AxKBm 5tVIkNEW1I8kN27nu0dvYKnfjH/jMNViAFskxwF5nwqwfJ3IBpdmtPKSAlp7bRAVaJme unBCQBPtIZfl9FI+4RQr9VonisXIlagHryy1kncWRCXVp0sBxosMtyXi194F+BXkgwEo jtDyxfDKltElJo518ol0okk+tkDgKnNk1Up4rZzVLFc/K2uNFfW1QHhsdVrfIFlOpzPC yQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 37nctr9fru-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 07:45:18 -0400 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.43/8.16.0.43) with SMTP id 131BYkLe132769; Thu, 1 Apr 2021 07:45:17 -0400 Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 37nctr9fqq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 07:45:17 -0400 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.0.43/8.16.0.43) with SMTP id 131BgSP1004727; Thu, 1 Apr 2021 11:45:15 GMT Received: from b06avi18878370.portsmouth.uk.ibm.com (b06avi18878370.portsmouth.uk.ibm.com [9.149.26.194]) by ppma03ams.nl.ibm.com with ESMTP id 37n28rrevc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 01 Apr 2021 11:45:15 +0000 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 131BiqNE31523094 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 1 Apr 2021 11:44:52 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5472DA4055; Thu, 1 Apr 2021 11:45:12 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 06E8FA4040; Thu, 1 Apr 2021 11:45:10 +0000 (GMT) Received: from pratiks-thinkpad.ibmuc.com (unknown [9.199.46.97]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP; Thu, 1 Apr 2021 11:45:09 +0000 (GMT) From: Pratik Rajesh Sampat To: rjw@rjwysocki.net, daniel.lezcano@linaro.org, shuah@kernel.org, dsmythies@telus.net, ego@linux.vnet.ibm.com, svaidy@linux.ibm.com, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, pratik.r.sampat@gmail.com, psampat@linux.ibm.com Subject: [RFC v2 2/2] selftest/cpuidle: Add support for cpuidle latency measurement Date: Thu, 1 Apr 2021 17:15:04 +0530 Message-Id: <20210401114504.13466-3-psampat@linux.ibm.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210401114504.13466-1-psampat@linux.ibm.com> References: <20210401114504.13466-1-psampat@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: SqfgRWDnCYofdECwmcH2iP3fJ3ZiXmyV X-Proofpoint-GUID: OCsql3py_A7OAEO-56jFYFOK05-qILjz X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.369,18.0.761 definitions=2021-04-01_04:2021-03-31,2021-04-01 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 spamscore=0 clxscore=1015 suspectscore=0 priorityscore=1501 phishscore=0 adultscore=0 mlxlogscore=999 bulkscore=0 malwarescore=0 mlxscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2103310000 definitions=main-2104010082 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org The cpuidle latency selftest provides support to systematically extract, analyse and present IPI and timer based wakeup latencies for each CPU and each idle state available on the system. The selftest leverages test-cpuidle_latency module's debugfs interface to interact and extract latency information from the kernel. The selftest inserts the module if already not inserted, disables all the idle states and enables them one by one testing the following: 1. Keeping source CPU constant, iterate through all the CPUS measuring IPI latency for baseline (CPU is busy with cat /dev/random > /dev/null workload) and then when the CPU is allowed to be at rest 2. Iterating through all the CPUs, sending expected timer durations to be equivalent to the residency of the deepest idle state enabled and extracting the difference in time between the time of wakeup and the expected timer duration The timer based test produces run to run variance on some intel based systems that sport a mechansim "C-state pre-wake" which can pre-wake a CPU from an idle state when timers are armed. For systems and architectures that don't have this mechansim can leverage timer tests with the -i option. To run this test specifically: $ make -C tools/testing/selftests TARGETS="cpuidle" run_tests There are a few optinal arguments too that the script can take [-h ] [-i ] [-m ] [-o ] [-v (run on all cpus)] Default Output location in: tools/testing/selftest/cpuidle/cpuidle.log Signed-off-by: Pratik Rajesh Sampat --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/cpuidle/Makefile | 6 + tools/testing/selftests/cpuidle/cpuidle.sh | 323 +++++++++++++++++++++ tools/testing/selftests/cpuidle/settings | 2 + 4 files changed, 332 insertions(+) create mode 100644 tools/testing/selftests/cpuidle/Makefile create mode 100755 tools/testing/selftests/cpuidle/cpuidle.sh create mode 100644 tools/testing/selftests/cpuidle/settings diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 6c575cf34a71..561eb67a4839 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -7,6 +7,7 @@ TARGETS += cgroup TARGETS += clone3 TARGETS += core TARGETS += cpufreq +TARGETS += cpuidle TARGETS += cpu-hotplug TARGETS += drivers/dma-buf TARGETS += efivarfs diff --git a/tools/testing/selftests/cpuidle/Makefile b/tools/testing/selftests/cpuidle/Makefile new file mode 100644 index 000000000000..cbe13feced34 --- /dev/null +++ b/tools/testing/selftests/cpuidle/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +all: + +TEST_PROGS := cpuidle.sh + +include ../lib.mk \ No newline at end of file diff --git a/tools/testing/selftests/cpuidle/cpuidle.sh b/tools/testing/selftests/cpuidle/cpuidle.sh new file mode 100755 index 000000000000..468112285900 --- /dev/null +++ b/tools/testing/selftests/cpuidle/cpuidle.sh @@ -0,0 +1,323 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +LOG=cpuidle.log +MODULE=/lib/modules/$(uname -r)/kernel/drivers/cpuidle/test-cpuidle_latency.ko + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +SMT=$(lscpu | grep "Thread(s) per core" | awk '{print $4}') +RUN_TIMER_TEST=0 + +helpme() +{ + printf "Usage: $0 [-h] [-todg args] + [-h ] + [-i ] + [-m ] + [-o ] + [-v ] + \n" + exit 2 +} + +parse_arguments() +{ + while getopts ht:m:o:vt:it: arg + do + case $arg in + h) # --help + helpme + ;; + i) # run timer tests + RUN_TIMER_TEST=1 + ;; + m) # --mod-file + MODULE=$OPTARG + ;; + o) # output log files + LOG=$OPTARG + ;; + v) # Verbose mode + SMT=1 + ;; + \?) + helpme + ;; + esac + done +} + +ins_mod() +{ + debugfs_file=/sys/kernel/debug/latency_test/ipi_latency_ns + # Check if the module is already loaded + if [ -f "$debugfs_file" ]; then + printf "Module already loaded\n\n" + return 0 + fi + # Try to load the module + if [ ! -f "$MODULE" ]; then + printf "$MODULE module does not exist. Exitting\n" + exit $ksft_skip + fi + printf "Inserting $MODULE module\n\n" + insmod $MODULE + if [ $? != 0 ]; then + printf "Insmod $MODULE failed\n" + exit $ksft_skip + fi +} + +compute_average() +{ + arr=("$@") + sum=0 + size=${#arr[@]} + if [ $size == 0 ]; then + avg=0 + return 1 + fi + for i in "${arr[@]}" + do + sum=$((sum + i)) + done + avg=$((sum/size)) +} + +# Disable all stop states +disable_idle() +{ + for ((cpu=0; cpu /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable + done + done +} + +# Perform operation on each CPU for the given state +# $1 - Operation: enable (0) / disable (1) +# $2 - State to enable +op_state() +{ + for ((cpu=0; cpu /sys/devices/system/cpu/cpu$cpu/cpuidle/state$2/disable + done +} + +cpuidle_enable_state() +{ + state=$1 + op_state 0 $state +} + +cpuidle_disable_state() +{ + state=$1 + op_state 1 $state +} + +cpu_is_online() +{ + cpu=$1 + if [ ! -f "/sys/devices/system/cpu/cpu$cpu/online" ]; then + echo 0 + return + fi + status=$(cat /sys/devices/system/cpu/cpu$cpu/online) + echo $status +} + +# Extract latency in microseconds and convert to nanoseconds +extract_latency() +{ + for ((state=0; state /dev/null & + task_pid=$! + # Wait for the workload to achieve 100% CPU usage + sleep 1 + fi + taskset 0x1 echo $dest_cpu > /sys/kernel/debug/latency_test/ipi_cpu_dest + ipi_latency=$(cat /sys/kernel/debug/latency_test/ipi_latency_ns) + src_cpu=$(cat /sys/kernel/debug/latency_test/ipi_cpu_src) + if [ "$1" = "baseline" ]; then + kill $task_pid + wait $task_pid 2>/dev/null + fi +} + +# Incrementally Enable idle states one by one and compute the latency +run_ipi_tests() +{ + extract_latency + disable_idle + declare -a avg_arr + echo -e "--IPI Latency Test---" | tee -a $LOG + + echo -e "--Baseline IPI Latency measurement: CPU Busy--" >> $LOG + printf "%s %10s %12s\n" "SRC_CPU" "DEST_CPU" "IPI_Latency(ns)" >> $LOG + for ((cpu=0; cpu> $LOG + avg_arr+=($ipi_latency) + done + compute_average "${avg_arr[@]}" + echo -e "Baseline Avg IPI latency(ns): $avg" | tee -a $LOG + + for ((state=0; state> $LOG + cpuidle_enable_state $state + printf "%s %10s %12s\n" "SRC_CPU" "DEST_CPU" "IPI_Latency(ns)" >> $LOG + for ((cpu=0; cpu> $LOG + avg_arr+=($ipi_latency) + done + compute_average "${avg_arr[@]}" + echo -e "Expected IPI latency(ns): ${latency_arr[$state]}" >> $LOG + echo -e "Observed Avg IPI latency(ns) - State $state: $avg" | tee -a $LOG + cpuidle_disable_state $state + done +} + +# Extract the residency in microseconds and convert to nanoseconds. +# Add 100 ns so that the timer stays for a little longer than the residency +extract_residency() +{ + for ((state=0; state /dev/null & + task_pid=$! + # Wait for the workload to achieve 100% CPU usage + sleep 1 + fi + taskset -c $dest_cpu echo $3 > /sys/kernel/debug/latency_test/timeout_expected_ns + # Wait for the result to populate + sleep 0.1 + timeout_diff=$(cat /sys/kernel/debug/latency_test/timeout_diff_ns) + src_cpu=$(cat /sys/kernel/debug/latency_test/timeout_cpu_src) + if [ "$1" = "baseline" ]; then + kill $task_pid + wait $task_pid 2>/dev/null + fi +} + +run_timeout_tests() +{ + extract_residency + disable_idle + declare -a avg_arr + echo -e "\n--Timeout Latency Test--" | tee -a $LOG + + echo -e "--Baseline Timeout Latency measurement: CPU Busy--" >> $LOG + printf "%s %10s %10s\n" "Wakeup_src" "Baseline_delay(ns)">> $LOG + for ((cpu=0; cpu> $LOG + avg_arr+=($timeout_diff) + done + compute_average "${avg_arr[@]}" + echo -e "Baseline Avg timeout diff(ns): $avg" | tee -a $LOG + + for ((state=0; state> $LOG + cpuidle_enable_state $state + printf "%s %10s %10s\n" "Wakeup_src" "Baseline_delay(ns)" "Delay(ns)" >> $LOG + for ((cpu=0; cpu> $LOG + avg_arr+=($timeout_diff) + done + compute_average "${avg_arr[@]}" + echo -e "Expected timeout(ns): ${residency_arr[$state]}" >> $LOG + echo -e "Observed Avg timeout diff(ns) - State $state: $avg" | tee -a $LOG + cpuidle_disable_state $state + done +} + +declare -a residency_arr +declare -a latency_arr + +parse_arguments $@ + +rm -f $LOG +touch $LOG +NUM_CPUS=$(nproc --all) +NUM_STATES=$(ls -1 /sys/devices/system/cpu/cpu0/cpuidle/ | wc -l) + +ins_mod $MODULE + +run_ipi_tests +if [ $RUN_TIMER_TEST == 1 ]; then + run_timeout_tests +fi + +printf "Removing $MODULE module\n" +printf "Full Output logged at: $LOG\n" +rmmod $MODULE diff --git a/tools/testing/selftests/cpuidle/settings b/tools/testing/selftests/cpuidle/settings new file mode 100644 index 000000000000..a26c38a70d77 --- /dev/null +++ b/tools/testing/selftests/cpuidle/settings @@ -0,0 +1,2 @@ +timeout=0 +