xref: /linux/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <poll.h>
11 #include <signal.h>
12 
13 #define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms"
14 #define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable"
15 #define WORKLOAD_SLOW_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_slow_hint_enable"
16 #define WORKLOAD_TYPE_INDEX_ATTRIBUTE  "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index"
17 
18 static const char * const workload_types[] = {
19 	"idle",
20 	"battery_life",
21 	"sustained",
22 	"bursty",
23 	NULL
24 };
25 
26 static int wlt_slow;
27 static char *wlt_enable_attr;
28 
29 #define WORKLOAD_TYPE_MAX_INDEX	3
30 
31 void workload_hint_exit(int signum)
32 {
33 	int fd;
34 
35 	/* Disable feature via sysfs knob */
36 
37 	fd = open(wlt_enable_attr, O_RDWR);
38 	if (fd < 0) {
39 		perror("Unable to open workload type feature enable file");
40 		exit(1);
41 	}
42 
43 	if (write(fd, "0\n", 2) < 0) {
44 		perror("Can't disable workload hints");
45 		exit(1);
46 	}
47 
48 	printf("Disabled workload type prediction\n");
49 
50 	close(fd);
51 }
52 
53 static void update_delay(char *delay_str)
54 {
55 	int fd;
56 
57 	printf("Setting notification delay in ms to %s\n", delay_str);
58 
59 	fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
60 	if (fd < 0) {
61 		perror("Unable to open workload notification delay");
62 		exit(1);
63 	}
64 
65 	if (write(fd, delay_str, strlen(delay_str)) < 0) {
66 		perror("Can't set delay");
67 		exit(1);
68 	}
69 
70 	close(fd);
71 }
72 
73 int main(int argc, char **argv)
74 {
75 	struct pollfd ufd;
76 	char index_str[4];
77 	int fd, ret, index;
78 	char delay_str[64];
79 	int delay = 0;
80 
81 	printf("Usage: workload_hint_test [notification delay in milli seconds][slow]\n");
82 
83 	if (argc > 1) {
84 		int i;
85 
86 		for (i = 1; i < argc; ++i) {
87 			if (!strcmp(argv[i], "slow")) {
88 				wlt_slow = 1;
89 				continue;
90 			}
91 
92 			ret = sscanf(argv[1], "%d", &delay);
93 			if (ret < 0) {
94 				printf("Invalid delay\n");
95 				exit(1);
96 			}
97 
98 			sprintf(delay_str, "%s\n", argv[1]);
99 			update_delay(delay_str);
100 		}
101 	}
102 
103 	if (signal(SIGINT, workload_hint_exit) == SIG_IGN)
104 		signal(SIGINT, SIG_IGN);
105 	if (signal(SIGHUP, workload_hint_exit) == SIG_IGN)
106 		signal(SIGHUP, SIG_IGN);
107 	if (signal(SIGTERM, workload_hint_exit) == SIG_IGN)
108 		signal(SIGTERM, SIG_IGN);
109 
110 	if (wlt_slow)
111 		wlt_enable_attr = WORKLOAD_SLOW_ENABLE_ATTRIBUTE;
112 	else
113 		wlt_enable_attr = WORKLOAD_ENABLE_ATTRIBUTE;
114 
115 	/* Enable feature via sysfs knob */
116 	fd = open(wlt_enable_attr, O_RDWR);
117 	if (fd < 0) {
118 		perror("Unable to open workload type feature enable file");
119 		exit(1);
120 	}
121 
122 	if (write(fd, "1\n", 2) < 0) {
123 		perror("Can't enable workload hints");
124 		exit(1);
125 	}
126 
127 	close(fd);
128 
129 	printf("Enabled workload type prediction\n");
130 
131 	while (1) {
132 		fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY);
133 		if (fd < 0) {
134 			perror("Unable to open workload type file");
135 			exit(1);
136 		}
137 
138 		if ((lseek(fd, 0L, SEEK_SET)) < 0) {
139 			fprintf(stderr, "Failed to set pointer to beginning\n");
140 			exit(1);
141 		}
142 
143 		if (read(fd, index_str, sizeof(index_str)) < 0) {
144 			fprintf(stderr, "Failed to read from:%s\n",
145 			WORKLOAD_TYPE_INDEX_ATTRIBUTE);
146 			exit(1);
147 		}
148 
149 		ufd.fd = fd;
150 		ufd.events = POLLPRI;
151 
152 		ret = poll(&ufd, 1, -1);
153 		if (ret < 0) {
154 			perror("poll error");
155 			exit(1);
156 		} else if (ret == 0) {
157 			printf("Poll Timeout\n");
158 		} else {
159 			if ((lseek(fd, 0L, SEEK_SET)) < 0) {
160 				fprintf(stderr, "Failed to set pointer to beginning\n");
161 				exit(1);
162 			}
163 
164 			if (read(fd, index_str, sizeof(index_str)) < 0)
165 				exit(0);
166 
167 			ret = sscanf(index_str, "%d", &index);
168 			if (ret < 0)
169 				break;
170 
171 			if (wlt_slow) {
172 				if (index & 0x10)
173 					printf("workload type slow:%s\n", "power");
174 				else
175 					printf("workload type slow:%s\n", "performance");
176 			}
177 
178 			index &= 0x0f;
179 			if (index > WORKLOAD_TYPE_MAX_INDEX)
180 				printf("Invalid workload type index\n");
181 			else
182 				printf("workload type:%s\n", workload_types[index]);
183 		}
184 
185 		close(fd);
186 	}
187 }
188