[PATCH i-g-t 4/5] tools/power: Introduce a small power/energy measurement tool

Ville Syrjala ville.syrjala at linux.intel.com
Mon Sep 16 20:18:40 UTC 2024


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

Provide a small tool for general power/energy measurements.

The tool operates as follow:
1. optionally sleep for a while to let the system settle
2. sample from number of rapl/hwmon/battery sources
3. sleep for a know amount of time
4. sample again from the same sources
5. calculate the results and report how much power/energy was used

igt_power provides the actual power/energy measurement stuff.

Sample output:
$ power -S 30 -s 30 -d /dev/dri/card0 -b 0 -r gpu -r pkg
/dev/dri/card0[gpu]: energy 17.944336 mJ, power 0.597746 mW, time 30.020000 s
battery[0]: energy 108000.000000 mJ, power 3597.585325 mW, time 30.020136 s
rapl[gpu]: energy 17.944336 mJ, power 0.597824 mW, time 30.016083 s
rapl[pkg]: energy 24139.099121 mJ, power 804.205461 mW, time 30.016085 s

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 tools/meson.build |   1 +
 tools/power.c     | 179 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 180 insertions(+)
 create mode 100644 tools/power.c

diff --git a/tools/meson.build b/tools/meson.build
index df26c4b95e3f..48c9a4b5089e 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -43,6 +43,7 @@ tools_progs = [
 	'intel_gvtg_test',
 	'dpcd_reg',
 	'lsgpu',
+	'power',
 ]
 tool_deps = igt_deps
 tool_deps += zlib
diff --git a/tools/power.c b/tools/power.c
new file mode 100644
index 000000000000..75c62ad39e61
--- /dev/null
+++ b/tools/power.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2024 Intel Corporation
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "drmtest.h"
+#include "igt_power.h"
+
+struct measurement {
+	int battery_index;
+	const char *rapl_domain;
+	const char *drm_device;
+	struct power_sample pre, post;
+	struct igt_power power;
+};
+
+static bool prepare(struct measurement *m)
+{
+	if (m->battery_index >= 0) {
+		if (igt_power_bat_open(&m->power, m->battery_index)) {
+			fprintf(stderr, "Unable to open battery %d\n", m->battery_index);
+			return false;
+		}
+	}
+
+	if (m->rapl_domain) {
+		int fd = -1;
+
+		if (m->drm_device) {
+			fd = open(m->drm_device, O_RDONLY);
+			if (fd < 0) {
+				fprintf(stderr, "Unable to open drm device %s\n", m->drm_device);
+				return false;
+			}
+		}
+
+		if (igt_power_open(fd, &m->power, m->rapl_domain)) {
+			if (m->drm_device)
+				fprintf(stderr, "Unable to open hwmon/rapl for %s\n", m->drm_device);
+			else
+				fprintf(stderr, "Unable to open rapl domain %s\n", m->rapl_domain);
+			close(fd);
+			return false;
+		}
+
+		close(fd);
+	}
+
+	return true;
+}
+
+static void sample_pre(struct measurement *m)
+{
+	igt_power_get_energy(&m->power, &m->pre);
+}
+
+static void sample_post(struct measurement *m)
+{
+	igt_power_get_energy(&m->power, &m->post);
+}
+
+static void report(struct measurement *m)
+{
+	if (m->battery_index >= 0)
+		printf("battery[%d]: energy %f mJ, power %f mW, time %f s\n",
+		       m->battery_index,
+		       igt_power_get_mJ(&m->power, &m->pre, &m->post),
+		       igt_power_get_mW(&m->power, &m->pre, &m->post),
+		       igt_power_get_s(&m->pre, &m->post));
+	else
+		printf("%s[%s]: energy %f mJ, power %f mW, time %f s\n",
+		       m->drm_device ?: "rapl", m->rapl_domain,
+		       igt_power_get_mJ(&m->power, &m->pre, &m->post),
+		       igt_power_get_mW(&m->power, &m->pre, &m->post),
+		       igt_power_get_s(&m->pre, &m->post));
+
+	igt_power_close(&m->power);
+}
+
+static void __attribute__((noreturn)) usage(const char *name)
+{
+	fprintf(stderr,
+		"Usage: %s [[-d <device>][-r <domain>][-b <battery>]...][-S <seconds>][-s <seconds>]\n"
+		"  -d,--drm <device>\tDRM device (eg. /dev/dri/card0)\n"
+		"  -r,--rapl <domain>\trapl domain (cpu,gpu,pkg,ram)\n"
+		"  -b,--battery <battery>\tbattery index\n"
+		"  -S,--settle <seconds>\tsettling duration\n"
+		"  -s,--sleep <seconds>\tmeasurement duration\n",
+		name);
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	struct measurement measurements[8];
+	int num_measurements = 0;
+	int measurement_duration = 0;
+	int settle_duration = 0;
+
+	for (;;) {
+		static const struct option long_options[] = {
+			{ .name = "drm", .has_arg = required_argument, },
+			{ .name = "rapl", .has_arg = required_argument, },
+			{ .name = "battery", .has_arg = required_argument, },
+			{ .name = "sleep", .has_arg = required_argument, },
+			{ .name = "settle", .has_arg = required_argument, },
+			{}
+		};
+
+		int opt = getopt_long(argc, argv, "d:r:b:S:s:", long_options, NULL);
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 'd':
+			if (num_measurements >= ARRAY_SIZE(measurements))
+				usage(argv[0]);
+			measurements[num_measurements].battery_index = -1;
+			measurements[num_measurements].rapl_domain = "gpu";
+			measurements[num_measurements].drm_device = optarg;
+			num_measurements++;
+			break;
+		case 'r':
+			if (num_measurements >= ARRAY_SIZE(measurements))
+				usage(argv[0]);
+			measurements[num_measurements].battery_index = -1;
+			measurements[num_measurements].rapl_domain = optarg;
+			measurements[num_measurements].drm_device = NULL;
+			num_measurements++;
+			break;
+		case 'b':
+			if (num_measurements >= ARRAY_SIZE(measurements))
+				usage(argv[0]);
+			measurements[num_measurements].battery_index = atoi(optarg);
+			measurements[num_measurements].rapl_domain = NULL;
+			measurements[num_measurements].drm_device = NULL;
+			num_measurements++;
+			break;
+		case 's':
+			measurement_duration = atoi(optarg);
+			break;
+		case 'S':
+			settle_duration = atoi(optarg);
+			break;
+		default:
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (num_measurements == 0)
+		usage(argv[0]);
+
+	for (int i = 0; i < num_measurements; i++) {
+		if (!prepare(&measurements[i]))
+			usage(argv[0]);
+	}
+
+	sleep(settle_duration);
+
+	for (int i = 0; i < num_measurements; i++)
+		sample_pre(&measurements[i]);
+
+	sleep(measurement_duration);
+
+	for (int i = 0; i < num_measurements; i++)
+		sample_post(&measurements[i]);
+
+	for (int i = 0; i < num_measurements; i++)
+		report(&measurements[i]);
+
+	return 0;
+}
-- 
2.44.2



More information about the igt-dev mailing list