diff options
Diffstat (limited to 'tools')
159 files changed, 20835 insertions, 1971 deletions
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c new file mode 100644 index 000000000000..11224eddcdc2 --- /dev/null +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * An implementation of key value pair (KVP) functionality for Linux. | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2010, Novell, Inc. | ||
6 | * Author : K. Y. Srinivasan <ksrinivasan@novell.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published | ||
10 | * by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
15 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
16 | * details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <sys/types.h> | ||
26 | #include <sys/socket.h> | ||
27 | #include <sys/poll.h> | ||
28 | #include <sys/utsname.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <stdio.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <unistd.h> | ||
33 | #include <string.h> | ||
34 | #include <errno.h> | ||
35 | #include <arpa/inet.h> | ||
36 | #include <linux/connector.h> | ||
37 | #include <linux/netlink.h> | ||
38 | #include <ifaddrs.h> | ||
39 | #include <netdb.h> | ||
40 | #include <syslog.h> | ||
41 | |||
42 | /* | ||
43 | * KYS: TODO. Need to register these in the kernel. | ||
44 | * | ||
45 | * The following definitions are shared with the in-kernel component; do not | ||
46 | * change any of this without making the corresponding changes in | ||
47 | * the KVP kernel component. | ||
48 | */ | ||
49 | #define CN_KVP_IDX 0x9 /* MSFT KVP functionality */ | ||
50 | #define CN_KVP_VAL 0x1 /* This supports queries from the kernel */ | ||
51 | #define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */ | ||
52 | |||
53 | /* | ||
54 | * KVP protocol: The user mode component first registers with the | ||
55 | * the kernel component. Subsequently, the kernel component requests, data | ||
56 | * for the specified keys. In response to this message the user mode component | ||
57 | * fills in the value corresponding to the specified key. We overload the | ||
58 | * sequence field in the cn_msg header to define our KVP message types. | ||
59 | * | ||
60 | * We use this infrastructure for also supporting queries from user mode | ||
61 | * application for state that may be maintained in the KVP kernel component. | ||
62 | * | ||
63 | * XXXKYS: Have a shared header file between the user and kernel (TODO) | ||
64 | */ | ||
65 | |||
66 | enum kvp_op { | ||
67 | KVP_REGISTER = 0, /* Register the user mode component*/ | ||
68 | KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/ | ||
69 | KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/ | ||
70 | KVP_USER_GET, /*User is requesting the value for the specified key*/ | ||
71 | KVP_USER_SET /*User is providing the value for the specified key*/ | ||
72 | }; | ||
73 | |||
74 | #define HV_KVP_EXCHANGE_MAX_KEY_SIZE 512 | ||
75 | #define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048 | ||
76 | |||
77 | struct hv_ku_msg { | ||
78 | __u32 kvp_index; | ||
79 | __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */ | ||
80 | __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */ | ||
81 | }; | ||
82 | |||
83 | enum key_index { | ||
84 | FullyQualifiedDomainName = 0, | ||
85 | IntegrationServicesVersion, /*This key is serviced in the kernel*/ | ||
86 | NetworkAddressIPv4, | ||
87 | NetworkAddressIPv6, | ||
88 | OSBuildNumber, | ||
89 | OSName, | ||
90 | OSMajorVersion, | ||
91 | OSMinorVersion, | ||
92 | OSVersion, | ||
93 | ProcessorArchitecture | ||
94 | }; | ||
95 | |||
96 | /* | ||
97 | * End of shared definitions. | ||
98 | */ | ||
99 | |||
100 | static char kvp_send_buffer[4096]; | ||
101 | static char kvp_recv_buffer[4096]; | ||
102 | static struct sockaddr_nl addr; | ||
103 | |||
104 | static char *os_name = ""; | ||
105 | static char *os_major = ""; | ||
106 | static char *os_minor = ""; | ||
107 | static char *processor_arch; | ||
108 | static char *os_build; | ||
109 | static char *lic_version; | ||
110 | static struct utsname uts_buf; | ||
111 | |||
112 | void kvp_get_os_info(void) | ||
113 | { | ||
114 | FILE *file; | ||
115 | char *p, buf[512]; | ||
116 | |||
117 | uname(&uts_buf); | ||
118 | os_build = uts_buf.release; | ||
119 | processor_arch = uts_buf.machine; | ||
120 | |||
121 | /* | ||
122 | * The current windows host (win7) expects the build | ||
123 | * string to be of the form: x.y.z | ||
124 | * Strip additional information we may have. | ||
125 | */ | ||
126 | p = strchr(os_build, '-'); | ||
127 | if (p) | ||
128 | *p = '\0'; | ||
129 | |||
130 | file = fopen("/etc/SuSE-release", "r"); | ||
131 | if (file != NULL) | ||
132 | goto kvp_osinfo_found; | ||
133 | file = fopen("/etc/redhat-release", "r"); | ||
134 | if (file != NULL) | ||
135 | goto kvp_osinfo_found; | ||
136 | /* | ||
137 | * Add code for other supported platforms. | ||
138 | */ | ||
139 | |||
140 | /* | ||
141 | * We don't have information about the os. | ||
142 | */ | ||
143 | os_name = uts_buf.sysname; | ||
144 | return; | ||
145 | |||
146 | kvp_osinfo_found: | ||
147 | /* up to three lines */ | ||
148 | p = fgets(buf, sizeof(buf), file); | ||
149 | if (p) { | ||
150 | p = strchr(buf, '\n'); | ||
151 | if (p) | ||
152 | *p = '\0'; | ||
153 | p = strdup(buf); | ||
154 | if (!p) | ||
155 | goto done; | ||
156 | os_name = p; | ||
157 | |||
158 | /* second line */ | ||
159 | p = fgets(buf, sizeof(buf), file); | ||
160 | if (p) { | ||
161 | p = strchr(buf, '\n'); | ||
162 | if (p) | ||
163 | *p = '\0'; | ||
164 | p = strdup(buf); | ||
165 | if (!p) | ||
166 | goto done; | ||
167 | os_major = p; | ||
168 | |||
169 | /* third line */ | ||
170 | p = fgets(buf, sizeof(buf), file); | ||
171 | if (p) { | ||
172 | p = strchr(buf, '\n'); | ||
173 | if (p) | ||
174 | *p = '\0'; | ||
175 | p = strdup(buf); | ||
176 | if (p) | ||
177 | os_minor = p; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | done: | ||
183 | fclose(file); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | static int | ||
188 | kvp_get_ip_address(int family, char *buffer, int length) | ||
189 | { | ||
190 | struct ifaddrs *ifap; | ||
191 | struct ifaddrs *curp; | ||
192 | int ipv4_len = strlen("255.255.255.255") + 1; | ||
193 | int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1; | ||
194 | int offset = 0; | ||
195 | const char *str; | ||
196 | char tmp[50]; | ||
197 | int error = 0; | ||
198 | |||
199 | /* | ||
200 | * On entry into this function, the buffer is capable of holding the | ||
201 | * maximum key value (2048 bytes). | ||
202 | */ | ||
203 | |||
204 | if (getifaddrs(&ifap)) { | ||
205 | strcpy(buffer, "getifaddrs failed\n"); | ||
206 | return 1; | ||
207 | } | ||
208 | |||
209 | curp = ifap; | ||
210 | while (curp != NULL) { | ||
211 | if ((curp->ifa_addr != NULL) && | ||
212 | (curp->ifa_addr->sa_family == family)) { | ||
213 | if (family == AF_INET) { | ||
214 | struct sockaddr_in *addr = | ||
215 | (struct sockaddr_in *) curp->ifa_addr; | ||
216 | |||
217 | str = inet_ntop(family, &addr->sin_addr, | ||
218 | tmp, 50); | ||
219 | if (str == NULL) { | ||
220 | strcpy(buffer, "inet_ntop failed\n"); | ||
221 | error = 1; | ||
222 | goto getaddr_done; | ||
223 | } | ||
224 | if (offset == 0) | ||
225 | strcpy(buffer, tmp); | ||
226 | else | ||
227 | strcat(buffer, tmp); | ||
228 | strcat(buffer, ";"); | ||
229 | |||
230 | offset += strlen(str) + 1; | ||
231 | if ((length - offset) < (ipv4_len + 1)) | ||
232 | goto getaddr_done; | ||
233 | |||
234 | } else { | ||
235 | |||
236 | /* | ||
237 | * We only support AF_INET and AF_INET6 | ||
238 | * and the list of addresses is separated by a ";". | ||
239 | */ | ||
240 | struct sockaddr_in6 *addr = | ||
241 | (struct sockaddr_in6 *) curp->ifa_addr; | ||
242 | |||
243 | str = inet_ntop(family, | ||
244 | &addr->sin6_addr.s6_addr, | ||
245 | tmp, 50); | ||
246 | if (str == NULL) { | ||
247 | strcpy(buffer, "inet_ntop failed\n"); | ||
248 | error = 1; | ||
249 | goto getaddr_done; | ||
250 | } | ||
251 | if (offset == 0) | ||
252 | strcpy(buffer, tmp); | ||
253 | else | ||
254 | strcat(buffer, tmp); | ||
255 | strcat(buffer, ";"); | ||
256 | offset += strlen(str) + 1; | ||
257 | if ((length - offset) < (ipv6_len + 1)) | ||
258 | goto getaddr_done; | ||
259 | |||
260 | } | ||
261 | |||
262 | } | ||
263 | curp = curp->ifa_next; | ||
264 | } | ||
265 | |||
266 | getaddr_done: | ||
267 | freeifaddrs(ifap); | ||
268 | return error; | ||
269 | } | ||
270 | |||
271 | |||
272 | static int | ||
273 | kvp_get_domain_name(char *buffer, int length) | ||
274 | { | ||
275 | struct addrinfo hints, *info ; | ||
276 | int error = 0; | ||
277 | |||
278 | gethostname(buffer, length); | ||
279 | memset(&hints, 0, sizeof(hints)); | ||
280 | hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */ | ||
281 | hints.ai_socktype = SOCK_STREAM; | ||
282 | hints.ai_flags = AI_CANONNAME; | ||
283 | |||
284 | error = getaddrinfo(buffer, NULL, &hints, &info); | ||
285 | if (error != 0) { | ||
286 | strcpy(buffer, "getaddrinfo failed\n"); | ||
287 | return error; | ||
288 | } | ||
289 | strcpy(buffer, info->ai_canonname); | ||
290 | freeaddrinfo(info); | ||
291 | return error; | ||
292 | } | ||
293 | |||
294 | static int | ||
295 | netlink_send(int fd, struct cn_msg *msg) | ||
296 | { | ||
297 | struct nlmsghdr *nlh; | ||
298 | unsigned int size; | ||
299 | struct msghdr message; | ||
300 | char buffer[64]; | ||
301 | struct iovec iov[2]; | ||
302 | |||
303 | size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len); | ||
304 | |||
305 | nlh = (struct nlmsghdr *)buffer; | ||
306 | nlh->nlmsg_seq = 0; | ||
307 | nlh->nlmsg_pid = getpid(); | ||
308 | nlh->nlmsg_type = NLMSG_DONE; | ||
309 | nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh)); | ||
310 | nlh->nlmsg_flags = 0; | ||
311 | |||
312 | iov[0].iov_base = nlh; | ||
313 | iov[0].iov_len = sizeof(*nlh); | ||
314 | |||
315 | iov[1].iov_base = msg; | ||
316 | iov[1].iov_len = size; | ||
317 | |||
318 | memset(&message, 0, sizeof(message)); | ||
319 | message.msg_name = &addr; | ||
320 | message.msg_namelen = sizeof(addr); | ||
321 | message.msg_iov = iov; | ||
322 | message.msg_iovlen = 2; | ||
323 | |||
324 | return sendmsg(fd, &message, 0); | ||
325 | } | ||
326 | |||
327 | int main(void) | ||
328 | { | ||
329 | int fd, len, sock_opt; | ||
330 | int error; | ||
331 | struct cn_msg *message; | ||
332 | struct pollfd pfd; | ||
333 | struct nlmsghdr *incoming_msg; | ||
334 | struct cn_msg *incoming_cn_msg; | ||
335 | struct hv_ku_msg *hv_msg; | ||
336 | char *p; | ||
337 | char *key_value; | ||
338 | char *key_name; | ||
339 | |||
340 | daemon(1, 0); | ||
341 | openlog("KVP", 0, LOG_USER); | ||
342 | syslog(LOG_INFO, "KVP starting; pid is:%d", getpid()); | ||
343 | /* | ||
344 | * Retrieve OS release information. | ||
345 | */ | ||
346 | kvp_get_os_info(); | ||
347 | |||
348 | fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); | ||
349 | if (fd < 0) { | ||
350 | syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); | ||
351 | exit(-1); | ||
352 | } | ||
353 | addr.nl_family = AF_NETLINK; | ||
354 | addr.nl_pad = 0; | ||
355 | addr.nl_pid = 0; | ||
356 | addr.nl_groups = CN_KVP_IDX; | ||
357 | |||
358 | |||
359 | error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); | ||
360 | if (error < 0) { | ||
361 | syslog(LOG_ERR, "bind failed; error:%d", error); | ||
362 | close(fd); | ||
363 | exit(-1); | ||
364 | } | ||
365 | sock_opt = addr.nl_groups; | ||
366 | setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); | ||
367 | /* | ||
368 | * Register ourselves with the kernel. | ||
369 | */ | ||
370 | message = (struct cn_msg *)kvp_send_buffer; | ||
371 | message->id.idx = CN_KVP_IDX; | ||
372 | message->id.val = CN_KVP_VAL; | ||
373 | message->seq = KVP_REGISTER; | ||
374 | message->ack = 0; | ||
375 | message->len = 0; | ||
376 | |||
377 | len = netlink_send(fd, message); | ||
378 | if (len < 0) { | ||
379 | syslog(LOG_ERR, "netlink_send failed; error:%d", len); | ||
380 | close(fd); | ||
381 | exit(-1); | ||
382 | } | ||
383 | |||
384 | pfd.fd = fd; | ||
385 | |||
386 | while (1) { | ||
387 | pfd.events = POLLIN; | ||
388 | pfd.revents = 0; | ||
389 | poll(&pfd, 1, -1); | ||
390 | |||
391 | len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0); | ||
392 | |||
393 | if (len < 0) { | ||
394 | syslog(LOG_ERR, "recv failed; error:%d", len); | ||
395 | close(fd); | ||
396 | return -1; | ||
397 | } | ||
398 | |||
399 | incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; | ||
400 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); | ||
401 | |||
402 | switch (incoming_cn_msg->seq) { | ||
403 | case KVP_REGISTER: | ||
404 | /* | ||
405 | * Driver is registering with us; stash away the version | ||
406 | * information. | ||
407 | */ | ||
408 | p = (char *)incoming_cn_msg->data; | ||
409 | lic_version = malloc(strlen(p) + 1); | ||
410 | if (lic_version) { | ||
411 | strcpy(lic_version, p); | ||
412 | syslog(LOG_INFO, "KVP LIC Version: %s", | ||
413 | lic_version); | ||
414 | } else { | ||
415 | syslog(LOG_ERR, "malloc failed"); | ||
416 | } | ||
417 | continue; | ||
418 | |||
419 | case KVP_KERNEL_GET: | ||
420 | break; | ||
421 | default: | ||
422 | continue; | ||
423 | } | ||
424 | |||
425 | hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data; | ||
426 | key_name = (char *)hv_msg->kvp_key; | ||
427 | key_value = (char *)hv_msg->kvp_value; | ||
428 | |||
429 | switch (hv_msg->kvp_index) { | ||
430 | case FullyQualifiedDomainName: | ||
431 | kvp_get_domain_name(key_value, | ||
432 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | ||
433 | strcpy(key_name, "FullyQualifiedDomainName"); | ||
434 | break; | ||
435 | case IntegrationServicesVersion: | ||
436 | strcpy(key_name, "IntegrationServicesVersion"); | ||
437 | strcpy(key_value, lic_version); | ||
438 | break; | ||
439 | case NetworkAddressIPv4: | ||
440 | kvp_get_ip_address(AF_INET, key_value, | ||
441 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | ||
442 | strcpy(key_name, "NetworkAddressIPv4"); | ||
443 | break; | ||
444 | case NetworkAddressIPv6: | ||
445 | kvp_get_ip_address(AF_INET6, key_value, | ||
446 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | ||
447 | strcpy(key_name, "NetworkAddressIPv6"); | ||
448 | break; | ||
449 | case OSBuildNumber: | ||
450 | strcpy(key_value, os_build); | ||
451 | strcpy(key_name, "OSBuildNumber"); | ||
452 | break; | ||
453 | case OSName: | ||
454 | strcpy(key_value, os_name); | ||
455 | strcpy(key_name, "OSName"); | ||
456 | break; | ||
457 | case OSMajorVersion: | ||
458 | strcpy(key_value, os_major); | ||
459 | strcpy(key_name, "OSMajorVersion"); | ||
460 | break; | ||
461 | case OSMinorVersion: | ||
462 | strcpy(key_value, os_minor); | ||
463 | strcpy(key_name, "OSMinorVersion"); | ||
464 | break; | ||
465 | case OSVersion: | ||
466 | strcpy(key_value, os_build); | ||
467 | strcpy(key_name, "OSVersion"); | ||
468 | break; | ||
469 | case ProcessorArchitecture: | ||
470 | strcpy(key_value, processor_arch); | ||
471 | strcpy(key_name, "ProcessorArchitecture"); | ||
472 | break; | ||
473 | default: | ||
474 | strcpy(key_value, "Unknown Key"); | ||
475 | /* | ||
476 | * We use a null key name to terminate enumeration. | ||
477 | */ | ||
478 | strcpy(key_name, ""); | ||
479 | break; | ||
480 | } | ||
481 | /* | ||
482 | * Send the value back to the kernel. The response is | ||
483 | * already in the receive buffer. Update the cn_msg header to | ||
484 | * reflect the key value that has been added to the message | ||
485 | */ | ||
486 | |||
487 | incoming_cn_msg->id.idx = CN_KVP_IDX; | ||
488 | incoming_cn_msg->id.val = CN_KVP_VAL; | ||
489 | incoming_cn_msg->seq = KVP_USER_SET; | ||
490 | incoming_cn_msg->ack = 0; | ||
491 | incoming_cn_msg->len = sizeof(struct hv_ku_msg); | ||
492 | |||
493 | len = netlink_send(fd, incoming_cn_msg); | ||
494 | if (len < 0) { | ||
495 | syslog(LOG_ERR, "net_link send failed; error:%d", len); | ||
496 | exit(-1); | ||
497 | } | ||
498 | } | ||
499 | |||
500 | } | ||
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 85c5f026930d..fe6762ed56bd 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
@@ -72,6 +72,19 @@ OPTIONS | |||
72 | CPUs are specified with -: 0-2. Default is to report samples on all | 72 | CPUs are specified with -: 0-2. Default is to report samples on all |
73 | CPUs. | 73 | CPUs. |
74 | 74 | ||
75 | --asm-raw:: | ||
76 | Show raw instruction encoding of assembly instructions. | ||
77 | |||
78 | --source:: | ||
79 | Interleave source code with assembly code. Enabled by default, | ||
80 | disable with --no-source. | ||
81 | |||
82 | --symfs=<directory>:: | ||
83 | Look for files with symbols relative to this directory. | ||
84 | |||
85 | -M:: | ||
86 | --disassembler-style=:: Set disassembler style for objdump. | ||
87 | |||
75 | SEE ALSO | 88 | SEE ALSO |
76 | -------- | 89 | -------- |
77 | linkperf:perf-record[1], linkperf:perf-report[1] | 90 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt index 5eaac6f26d51..cc22325ffd1b 100644 --- a/tools/perf/Documentation/perf-buildid-list.txt +++ b/tools/perf/Documentation/perf-buildid-list.txt | |||
@@ -16,6 +16,9 @@ This command displays the buildids found in a perf.data file, so that other | |||
16 | tools can be used to fetch packages with matching symbol tables for use by | 16 | tools can be used to fetch packages with matching symbol tables for use by |
17 | perf report. | 17 | perf report. |
18 | 18 | ||
19 | It can also be used to show the build id of the running kernel or in an ELF | ||
20 | file using -i/--input. | ||
21 | |||
19 | OPTIONS | 22 | OPTIONS |
20 | ------- | 23 | ------- |
21 | -H:: | 24 | -H:: |
@@ -27,6 +30,9 @@ OPTIONS | |||
27 | -f:: | 30 | -f:: |
28 | --force:: | 31 | --force:: |
29 | Don't do ownership validation. | 32 | Don't do ownership validation. |
33 | -k:: | ||
34 | --kernel:: | ||
35 | Show running kernel build id. | ||
30 | -v:: | 36 | -v:: |
31 | --verbose:: | 37 | --verbose:: |
32 | Be more verbose. | 38 | Be more verbose. |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 04253c07d19a..212f24d672e1 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -134,6 +134,24 @@ OPTIONS | |||
134 | CPUs are specified with -: 0-2. Default is to report samples on all | 134 | CPUs are specified with -: 0-2. Default is to report samples on all |
135 | CPUs. | 135 | CPUs. |
136 | 136 | ||
137 | -M:: | ||
138 | --disassembler-style=:: Set disassembler style for objdump. | ||
139 | |||
140 | --source:: | ||
141 | Interleave source code with assembly code. Enabled by default, | ||
142 | disable with --no-source. | ||
143 | |||
144 | --asm-raw:: | ||
145 | Show raw instruction encoding of assembly instructions. | ||
146 | |||
147 | --show-total-period:: Show a column with the sum of periods. | ||
148 | |||
149 | -I:: | ||
150 | --show-info:: | ||
151 | Display extended information about the perf.data file. This adds | ||
152 | information which may be very large and thus may clutter the display. | ||
153 | It currently includes: cpu and numa topology of the host system. | ||
154 | |||
137 | SEE ALSO | 155 | SEE ALSO |
138 | -------- | 156 | -------- |
139 | linkperf:perf-stat[1] | 157 | linkperf:perf-stat[1], linkperf:perf-annotate[1] |
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 46822d5fde1c..5b212b57f70b 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt | |||
@@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies) | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf sched' {record|latency|map|replay|trace} | 11 | 'perf sched' {record|latency|map|replay|script} |
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
@@ -20,8 +20,8 @@ There are five variants of perf sched: | |||
20 | 'perf sched latency' to report the per task scheduling latencies | 20 | 'perf sched latency' to report the per task scheduling latencies |
21 | and other scheduling properties of the workload. | 21 | and other scheduling properties of the workload. |
22 | 22 | ||
23 | 'perf sched trace' to see a detailed trace of the workload that | 23 | 'perf sched script' to see a detailed trace of the workload that |
24 | was recorded. | 24 | was recorded (aliased to 'perf script' for now). |
25 | 25 | ||
26 | 'perf sched replay' to simulate the workload that was recorded | 26 | 'perf sched replay' to simulate the workload that was recorded |
27 | via perf sched record. (this is done by starting up mockup threads | 27 | via perf sched record. (this is done by starting up mockup threads |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index db017867d9e8..dec87ecb530e 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -188,6 +188,13 @@ OPTIONS | |||
188 | CPUs are specified with -: 0-2. Default is to report samples on all | 188 | CPUs are specified with -: 0-2. Default is to report samples on all |
189 | CPUs. | 189 | CPUs. |
190 | 190 | ||
191 | -I:: | ||
192 | --show-info:: | ||
193 | Display extended information about the perf.data file. This adds | ||
194 | information which may be very large and thus may clutter the display. | ||
195 | It currently includes: cpu and numa topology of the host system. | ||
196 | It can only be used with the perf script report mode. | ||
197 | |||
191 | SEE ALSO | 198 | SEE ALSO |
192 | -------- | 199 | -------- |
193 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 200 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 918cc38ee6d1..8966b9ab2014 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -94,6 +94,22 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha | |||
94 | corresponding events, i.e., they always refer to events defined earlier on the command | 94 | corresponding events, i.e., they always refer to events defined earlier on the command |
95 | line. | 95 | line. |
96 | 96 | ||
97 | -o file:: | ||
98 | --output file:: | ||
99 | Print the output into the designated file. | ||
100 | |||
101 | --append:: | ||
102 | Append to the output file designated with the -o option. Ignored if -o is not specified. | ||
103 | |||
104 | --log-fd:: | ||
105 | |||
106 | Log output to fd, instead of stderr. Complementary to --output, and mutually exclusive | ||
107 | with it. --append may be used here. Examples: | ||
108 | 3>results perf stat --log-fd 3 -- $cmd | ||
109 | 3>>results perf stat --log-fd 3 --append -- $cmd | ||
110 | |||
111 | |||
112 | |||
97 | EXAMPLES | 113 | EXAMPLES |
98 | -------- | 114 | -------- |
99 | 115 | ||
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index f6eb1cdafb77..b1a5bbbfebef 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -106,6 +106,51 @@ Default is to monitor all CPUS. | |||
106 | --zero:: | 106 | --zero:: |
107 | Zero history across display updates. | 107 | Zero history across display updates. |
108 | 108 | ||
109 | -s:: | ||
110 | --sort:: | ||
111 | Sort by key(s): pid, comm, dso, symbol, parent | ||
112 | |||
113 | -n:: | ||
114 | --show-nr-samples:: | ||
115 | Show a column with the number of samples. | ||
116 | |||
117 | --show-total-period:: | ||
118 | Show a column with the sum of periods. | ||
119 | |||
120 | --dsos:: | ||
121 | Only consider symbols in these dsos. | ||
122 | |||
123 | --comms:: | ||
124 | Only consider symbols in these comms. | ||
125 | |||
126 | --symbols:: | ||
127 | Only consider these symbols. | ||
128 | |||
129 | -M:: | ||
130 | --disassembler-style=:: Set disassembler style for objdump. | ||
131 | |||
132 | --source:: | ||
133 | Interleave source code with assembly code. Enabled by default, | ||
134 | disable with --no-source. | ||
135 | |||
136 | --asm-raw:: | ||
137 | Show raw instruction encoding of assembly instructions. | ||
138 | |||
139 | -G [type,min,order]:: | ||
140 | --call-graph:: | ||
141 | Display call chains using type, min percent threshold and order. | ||
142 | type can be either: | ||
143 | - flat: single column, linear exposure of call chains. | ||
144 | - graph: use a graph tree, displaying absolute overhead rates. | ||
145 | - fractal: like graph, but displays relative rates. Each branch of | ||
146 | the tree is considered as a new profiled object. | ||
147 | |||
148 | order can be either: | ||
149 | - callee: callee based call graph. | ||
150 | - caller: inverted caller based call graph. | ||
151 | |||
152 | Default: fractal,0.5,callee. | ||
153 | |||
109 | INTERACTIVE PROMPTING KEYS | 154 | INTERACTIVE PROMPTING KEYS |
110 | -------------------------- | 155 | -------------------------- |
111 | 156 | ||
@@ -130,9 +175,6 @@ INTERACTIVE PROMPTING KEYS | |||
130 | [S]:: | 175 | [S]:: |
131 | Stop annotation, return to full profile display. | 176 | Stop annotation, return to full profile display. |
132 | 177 | ||
133 | [w]:: | ||
134 | Toggle between weighted sum and individual count[E]r profile. | ||
135 | |||
136 | [z]:: | 178 | [z]:: |
137 | Toggle event count zeroing across display updates. | 179 | Toggle event count zeroing across display updates. |
138 | 180 | ||
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example new file mode 100644 index 000000000000..d1448668f4d4 --- /dev/null +++ b/tools/perf/Documentation/perfconfig.example | |||
@@ -0,0 +1,20 @@ | |||
1 | [colors] | ||
2 | |||
3 | # These were the old defaults | ||
4 | top = red, lightgray | ||
5 | medium = green, lightgray | ||
6 | normal = black, lightgray | ||
7 | selected = lightgray, magenta | ||
8 | code = blue, lightgray | ||
9 | |||
10 | [tui] | ||
11 | |||
12 | # Defaults if linked with libslang | ||
13 | report = on | ||
14 | annotate = on | ||
15 | top = on | ||
16 | |||
17 | [buildid] | ||
18 | |||
19 | # Default, disable using /dev/null | ||
20 | dir = /root/.debug | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 56d62d3fb167..b98e3075646b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -30,6 +30,8 @@ endif | |||
30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
31 | # | 31 | # |
32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. | 32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. |
33 | # | ||
34 | # Define WERROR=0 to disable treating any warnings as errors. | ||
33 | 35 | ||
34 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 36 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
35 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 37 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
@@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64) | |||
63 | endif | 65 | endif |
64 | endif | 66 | endif |
65 | 67 | ||
68 | # Treat warnings as errors unless directed not to | ||
69 | ifneq ($(WERROR),0) | ||
70 | CFLAGS_WERROR := -Werror | ||
71 | endif | ||
72 | |||
66 | # | 73 | # |
67 | # Include saner warnings here, which can catch bugs: | 74 | # Include saner warnings here, which can catch bugs: |
68 | # | 75 | # |
@@ -95,7 +102,7 @@ ifndef PERF_DEBUG | |||
95 | CFLAGS_OPTIMIZE = -O6 | 102 | CFLAGS_OPTIMIZE = -O6 |
96 | endif | 103 | endif |
97 | 104 | ||
98 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 105 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
99 | EXTLIBS = -lpthread -lrt -lelf -lm | 106 | EXTLIBS = -lpthread -lrt -lelf -lm |
100 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | 107 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 |
101 | ALL_LDFLAGS = $(LDFLAGS) | 108 | ALL_LDFLAGS = $(LDFLAGS) |
@@ -181,9 +188,9 @@ strip-libs = $(filter-out -l%,$(1)) | |||
181 | 188 | ||
182 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) | 189 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) |
183 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 190 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
184 | --quiet build_ext \ | 191 | --quiet build_ext; \ |
185 | --build-lib='$(OUTPUT)python' \ | 192 | mkdir -p $(OUTPUT)python && \ |
186 | --build-temp='$(OUTPUT)python/temp' | 193 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
187 | # | 194 | # |
188 | # No Perl scripts right now: | 195 | # No Perl scripts right now: |
189 | # | 196 | # |
@@ -459,13 +466,13 @@ else | |||
459 | LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o | 466 | LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o |
460 | LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o | 467 | LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o |
461 | LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o | 468 | LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o |
462 | LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o | ||
463 | LIB_OBJS += $(OUTPUT)util/ui/helpline.o | 469 | LIB_OBJS += $(OUTPUT)util/ui/helpline.o |
464 | LIB_OBJS += $(OUTPUT)util/ui/progress.o | 470 | LIB_OBJS += $(OUTPUT)util/ui/progress.o |
465 | LIB_OBJS += $(OUTPUT)util/ui/util.o | 471 | LIB_OBJS += $(OUTPUT)util/ui/util.o |
466 | LIB_H += util/ui/browser.h | 472 | LIB_H += util/ui/browser.h |
467 | LIB_H += util/ui/browsers/map.h | 473 | LIB_H += util/ui/browsers/map.h |
468 | LIB_H += util/ui/helpline.h | 474 | LIB_H += util/ui/helpline.h |
475 | LIB_H += util/ui/keysyms.h | ||
469 | LIB_H += util/ui/libslang.h | 476 | LIB_H += util/ui/libslang.h |
470 | LIB_H += util/ui/progress.h | 477 | LIB_H += util/ui/progress.h |
471 | LIB_H += util/ui/util.h | 478 | LIB_H += util/ui/util.h |
@@ -509,9 +516,13 @@ else | |||
509 | 516 | ||
510 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 517 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) |
511 | 518 | ||
512 | python-clean := $(PYTHON_WORD) util/setup.py clean \ | 519 | # python extension build directories |
513 | --build-lib='$(OUTPUT)python' \ | 520 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
514 | --build-temp='$(OUTPUT)python/temp' | 521 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
522 | PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/ | ||
523 | export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | ||
524 | |||
525 | python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | ||
515 | 526 | ||
516 | ifdef NO_LIBPYTHON | 527 | ifdef NO_LIBPYTHON |
517 | $(call disable-python) | 528 | $(call disable-python) |
@@ -718,9 +729,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS | |||
718 | $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS | 729 | $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS |
719 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 730 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
720 | 731 | ||
721 | $(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS | ||
722 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | ||
723 | |||
724 | $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS | 732 | $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS |
725 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 733 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
726 | 734 | ||
@@ -868,6 +876,9 @@ install: all | |||
868 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' | 876 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' |
869 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 877 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
870 | 878 | ||
879 | install-python_ext: | ||
880 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | ||
881 | |||
871 | install-doc: | 882 | install-doc: |
872 | $(MAKE) -C Documentation install | 883 | $(MAKE) -C Documentation install |
873 | 884 | ||
@@ -895,7 +906,7 @@ quick-install-html: | |||
895 | ### Cleaning rules | 906 | ### Cleaning rules |
896 | 907 | ||
897 | clean: | 908 | clean: |
898 | $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} | 909 | $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) |
899 | $(RM) $(ALL_PROGRAMS) perf | 910 | $(RM) $(ALL_PROGRAMS) perf |
900 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* | 911 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* |
901 | $(MAKE) -C Documentation/ clean | 912 | $(MAKE) -C Documentation/ clean |
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index fff6450c8c99..e8d5c551c69c 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c | |||
@@ -8,7 +8,10 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <stdlib.h> | ||
12 | #ifndef __UCLIBC__ | ||
11 | #include <libio.h> | 13 | #include <libio.h> |
14 | #endif | ||
12 | #include <dwarf-regs.h> | 15 | #include <dwarf-regs.h> |
13 | 16 | ||
14 | struct pt_regs_dwarfnum { | 17 | struct pt_regs_dwarfnum { |
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index 15130b50dfe3..744e629797be 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile | |||
@@ -2,3 +2,4 @@ ifndef NO_DWARF | |||
2 | PERF_HAVE_DWARF_REGS := 1 | 2 | PERF_HAVE_DWARF_REGS := 1 |
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | 3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o |
4 | endif | 4 | endif |
5 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o | ||
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c new file mode 100644 index 000000000000..eba80c292945 --- /dev/null +++ b/tools/perf/arch/powerpc/util/header.c | |||
@@ -0,0 +1,36 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #include "../../util/header.h" | ||
8 | |||
9 | #define __stringify_1(x) #x | ||
10 | #define __stringify(x) __stringify_1(x) | ||
11 | |||
12 | #define mfspr(rn) ({unsigned long rval; \ | ||
13 | asm volatile("mfspr %0," __stringify(rn) \ | ||
14 | : "=r" (rval)); rval; }) | ||
15 | |||
16 | #define SPRN_PVR 0x11F /* Processor Version Register */ | ||
17 | #define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ | ||
18 | #define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ | ||
19 | |||
20 | int | ||
21 | get_cpuid(char *buffer, size_t sz) | ||
22 | { | ||
23 | unsigned long pvr; | ||
24 | int nb; | ||
25 | |||
26 | pvr = mfspr(SPRN_PVR); | ||
27 | |||
28 | nb = snprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr)); | ||
29 | |||
30 | /* look for end marker to ensure the entire data fit */ | ||
31 | if (strchr(buffer, '$')) { | ||
32 | buffer[nb-1] = '\0'; | ||
33 | return 0; | ||
34 | } | ||
35 | return -1; | ||
36 | } | ||
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 15130b50dfe3..744e629797be 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile | |||
@@ -2,3 +2,4 @@ ifndef NO_DWARF | |||
2 | PERF_HAVE_DWARF_REGS := 1 | 2 | PERF_HAVE_DWARF_REGS := 1 |
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | 3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o |
4 | endif | 4 | endif |
5 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o | ||
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c new file mode 100644 index 000000000000..f94006068d2b --- /dev/null +++ b/tools/perf/arch/x86/util/header.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #include "../../util/header.h" | ||
8 | |||
9 | static inline void | ||
10 | cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c, | ||
11 | unsigned int *d) | ||
12 | { | ||
13 | __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t" | ||
14 | "movl %%ebx, %%esi\n\t.byte 0x5b" | ||
15 | : "=a" (*a), | ||
16 | "=S" (*b), | ||
17 | "=c" (*c), | ||
18 | "=d" (*d) | ||
19 | : "a" (op)); | ||
20 | } | ||
21 | |||
22 | int | ||
23 | get_cpuid(char *buffer, size_t sz) | ||
24 | { | ||
25 | unsigned int a, b, c, d, lvl; | ||
26 | int family = -1, model = -1, step = -1; | ||
27 | int nb; | ||
28 | char vendor[16]; | ||
29 | |||
30 | cpuid(0, &lvl, &b, &c, &d); | ||
31 | strncpy(&vendor[0], (char *)(&b), 4); | ||
32 | strncpy(&vendor[4], (char *)(&d), 4); | ||
33 | strncpy(&vendor[8], (char *)(&c), 4); | ||
34 | vendor[12] = '\0'; | ||
35 | |||
36 | if (lvl >= 1) { | ||
37 | cpuid(1, &a, &b, &c, &d); | ||
38 | |||
39 | family = (a >> 8) & 0xf; /* bits 11 - 8 */ | ||
40 | model = (a >> 4) & 0xf; /* Bits 7 - 4 */ | ||
41 | step = a & 0xf; | ||
42 | |||
43 | /* extended family */ | ||
44 | if (family == 0xf) | ||
45 | family += (a >> 20) & 0xff; | ||
46 | |||
47 | /* extended model */ | ||
48 | if (family >= 0x6) | ||
49 | model += ((a >> 16) & 0xf) << 4; | ||
50 | } | ||
51 | nb = snprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); | ||
52 | |||
53 | /* look for end marker to ensure the entire data fit */ | ||
54 | if (strchr(buffer, '$')) { | ||
55 | buffer[nb-1] = '\0'; | ||
56 | return 0; | ||
57 | } | ||
58 | return -1; | ||
59 | } | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 555aefd7fe01..46b4c24f338e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -114,10 +114,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) | |||
114 | print_line, full_paths, 0, 0); | 114 | print_line, full_paths, 0, 0); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void hists__find_annotations(struct hists *self, int evidx) | 117 | static void hists__find_annotations(struct hists *self, int evidx, |
118 | int nr_events) | ||
118 | { | 119 | { |
119 | struct rb_node *nd = rb_first(&self->entries), *next; | 120 | struct rb_node *nd = rb_first(&self->entries), *next; |
120 | int key = KEY_RIGHT; | 121 | int key = K_RIGHT; |
121 | 122 | ||
122 | while (nd) { | 123 | while (nd) { |
123 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | 124 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
@@ -129,7 +130,7 @@ static void hists__find_annotations(struct hists *self, int evidx) | |||
129 | notes = symbol__annotation(he->ms.sym); | 130 | notes = symbol__annotation(he->ms.sym); |
130 | if (notes->src == NULL) { | 131 | if (notes->src == NULL) { |
131 | find_next: | 132 | find_next: |
132 | if (key == KEY_LEFT) | 133 | if (key == K_LEFT) |
133 | nd = rb_prev(nd); | 134 | nd = rb_prev(nd); |
134 | else | 135 | else |
135 | nd = rb_next(nd); | 136 | nd = rb_next(nd); |
@@ -137,12 +138,13 @@ find_next: | |||
137 | } | 138 | } |
138 | 139 | ||
139 | if (use_browser > 0) { | 140 | if (use_browser > 0) { |
140 | key = hist_entry__tui_annotate(he, evidx); | 141 | key = hist_entry__tui_annotate(he, evidx, nr_events, |
142 | NULL, NULL, 0); | ||
141 | switch (key) { | 143 | switch (key) { |
142 | case KEY_RIGHT: | 144 | case K_RIGHT: |
143 | next = rb_next(nd); | 145 | next = rb_next(nd); |
144 | break; | 146 | break; |
145 | case KEY_LEFT: | 147 | case K_LEFT: |
146 | next = rb_prev(nd); | 148 | next = rb_prev(nd); |
147 | break; | 149 | break; |
148 | default: | 150 | default: |
@@ -215,7 +217,8 @@ static int __cmd_annotate(void) | |||
215 | total_nr_samples += nr_samples; | 217 | total_nr_samples += nr_samples; |
216 | hists__collapse_resort(hists); | 218 | hists__collapse_resort(hists); |
217 | hists__output_resort(hists); | 219 | hists__output_resort(hists); |
218 | hists__find_annotations(hists, pos->idx); | 220 | hists__find_annotations(hists, pos->idx, |
221 | session->evlist->nr_entries); | ||
219 | } | 222 | } |
220 | } | 223 | } |
221 | 224 | ||
@@ -267,6 +270,14 @@ static const struct option options[] = { | |||
267 | OPT_BOOLEAN('P', "full-paths", &full_paths, | 270 | OPT_BOOLEAN('P', "full-paths", &full_paths, |
268 | "Don't shorten the displayed pathnames"), | 271 | "Don't shorten the displayed pathnames"), |
269 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 272 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
273 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
274 | "Look for files with symbols relative to this directory"), | ||
275 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | ||
276 | "Interleave source code with assembly code (default)"), | ||
277 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | ||
278 | "Display raw encoding of assembly instructions (default)"), | ||
279 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | ||
280 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | ||
270 | OPT_END() | 281 | OPT_END() |
271 | }; | 282 | }; |
272 | 283 | ||
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 5af32ae9031e..cb690a65bf02 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * builtin-buildid-list.c | 2 | * builtin-buildid-list.c |
3 | * | 3 | * |
4 | * Builtin buildid-list command: list buildids in perf.data | 4 | * Builtin buildid-list command: list buildids in perf.data, in the running |
5 | * kernel and in ELF files. | ||
5 | * | 6 | * |
6 | * Copyright (C) 2009, Red Hat Inc. | 7 | * Copyright (C) 2009, Red Hat Inc. |
7 | * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> | 8 | * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> |
@@ -15,8 +16,11 @@ | |||
15 | #include "util/session.h" | 16 | #include "util/session.h" |
16 | #include "util/symbol.h" | 17 | #include "util/symbol.h" |
17 | 18 | ||
19 | #include <libelf.h> | ||
20 | |||
18 | static char const *input_name = "perf.data"; | 21 | static char const *input_name = "perf.data"; |
19 | static bool force; | 22 | static bool force; |
23 | static bool show_kernel; | ||
20 | static bool with_hits; | 24 | static bool with_hits; |
21 | 25 | ||
22 | static const char * const buildid_list_usage[] = { | 26 | static const char * const buildid_list_usage[] = { |
@@ -29,12 +33,13 @@ static const struct option options[] = { | |||
29 | OPT_STRING('i', "input", &input_name, "file", | 33 | OPT_STRING('i', "input", &input_name, "file", |
30 | "input file name"), | 34 | "input file name"), |
31 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 35 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), |
36 | OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), | ||
32 | OPT_INCR('v', "verbose", &verbose, | 37 | OPT_INCR('v', "verbose", &verbose, |
33 | "be more verbose"), | 38 | "be more verbose"), |
34 | OPT_END() | 39 | OPT_END() |
35 | }; | 40 | }; |
36 | 41 | ||
37 | static int __cmd_buildid_list(void) | 42 | static int perf_session__list_build_ids(void) |
38 | { | 43 | { |
39 | struct perf_session *session; | 44 | struct perf_session *session; |
40 | 45 | ||
@@ -52,6 +57,49 @@ static int __cmd_buildid_list(void) | |||
52 | return 0; | 57 | return 0; |
53 | } | 58 | } |
54 | 59 | ||
60 | static int sysfs__fprintf_build_id(FILE *fp) | ||
61 | { | ||
62 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | ||
63 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
64 | |||
65 | if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, | ||
66 | sizeof(kallsyms_build_id)) != 0) | ||
67 | return -1; | ||
68 | |||
69 | build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id), | ||
70 | sbuild_id); | ||
71 | fprintf(fp, "%s\n", sbuild_id); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int filename__fprintf_build_id(const char *name, FILE *fp) | ||
76 | { | ||
77 | u8 build_id[BUILD_ID_SIZE]; | ||
78 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
79 | |||
80 | if (filename__read_build_id(name, build_id, | ||
81 | sizeof(build_id)) != sizeof(build_id)) | ||
82 | return 0; | ||
83 | |||
84 | build_id__sprintf(build_id, sizeof(build_id), sbuild_id); | ||
85 | return fprintf(fp, "%s\n", sbuild_id); | ||
86 | } | ||
87 | |||
88 | static int __cmd_buildid_list(void) | ||
89 | { | ||
90 | if (show_kernel) | ||
91 | return sysfs__fprintf_build_id(stdout); | ||
92 | |||
93 | elf_version(EV_CURRENT); | ||
94 | /* | ||
95 | * See if this is an ELF file first: | ||
96 | */ | ||
97 | if (filename__fprintf_build_id(input_name, stdout)) | ||
98 | return 0; | ||
99 | |||
100 | return perf_session__list_build_ids(); | ||
101 | } | ||
102 | |||
55 | int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) | 103 | int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) |
56 | { | 104 | { |
57 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); | 105 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e8219990f8b8..b39f3a1ee7dc 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -162,7 +162,7 @@ static int __cmd_diff(void) | |||
162 | 162 | ||
163 | hists__match(&session[0]->hists, &session[1]->hists); | 163 | hists__match(&session[0]->hists, &session[1]->hists); |
164 | hists__fprintf(&session[1]->hists, &session[0]->hists, | 164 | hists__fprintf(&session[1]->hists, &session[0]->hists, |
165 | show_displacement, stdout); | 165 | show_displacement, true, 0, 0, stdout); |
166 | out_delete: | 166 | out_delete: |
167 | for (i = 0; i < 2; ++i) | 167 | for (i = 0; i < 2; ++i) |
168 | perf_session__delete(session[i]); | 168 | perf_session__delete(session[i]); |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 9ac05aafd9b2..899080ace267 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -942,10 +942,10 @@ static const char *record_args[] = { | |||
942 | "-f", | 942 | "-f", |
943 | "-m", "1024", | 943 | "-m", "1024", |
944 | "-c", "1", | 944 | "-c", "1", |
945 | "-e", "lock:lock_acquire:r", | 945 | "-e", "lock:lock_acquire", |
946 | "-e", "lock:lock_acquired:r", | 946 | "-e", "lock:lock_acquired", |
947 | "-e", "lock:lock_contended:r", | 947 | "-e", "lock:lock_contended", |
948 | "-e", "lock:lock_release:r", | 948 | "-e", "lock:lock_release", |
949 | }; | 949 | }; |
950 | 950 | ||
951 | static int __cmd_record(int argc, const char **argv) | 951 | static int __cmd_record(int argc, const char **argv) |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 5f2a5c7046df..710ae3d0a489 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used, | |||
134 | { | 134 | { |
135 | int ret = 0; | 135 | int ret = 0; |
136 | 136 | ||
137 | if (str) | 137 | if (!str) |
138 | ret = parse_line_range_desc(str, ¶ms.line_range); | 138 | return 0; |
139 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 139 | |
140 | if (params.show_lines) { | ||
141 | pr_warning("Warning: more than one --line options are" | ||
142 | " detected. Only the first one is valid.\n"); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
140 | params.show_lines = true; | 146 | params.show_lines = true; |
147 | ret = parse_line_range_desc(str, ¶ms.line_range); | ||
148 | INIT_LIST_HEAD(¶ms.line_range.line_list); | ||
141 | 149 | ||
142 | return ret; | 150 | return ret; |
143 | } | 151 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 80dc5b790e47..6ab58cc99d53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #include <sched.h> | 30 | #include <sched.h> |
31 | #include <sys/mman.h> | 31 | #include <sys/mman.h> |
32 | 32 | ||
33 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
34 | |||
35 | enum write_mode_t { | 33 | enum write_mode_t { |
36 | WRITE_FORCE, | 34 | WRITE_FORCE, |
37 | WRITE_APPEND | 35 | WRITE_APPEND |
@@ -47,7 +45,7 @@ static int freq = 1000; | |||
47 | static int output; | 45 | static int output; |
48 | static int pipe_output = 0; | 46 | static int pipe_output = 0; |
49 | static const char *output_name = NULL; | 47 | static const char *output_name = NULL; |
50 | static int group = 0; | 48 | static bool group = false; |
51 | static int realtime_prio = 0; | 49 | static int realtime_prio = 0; |
52 | static bool nodelay = false; | 50 | static bool nodelay = false; |
53 | static bool raw_samples = false; | 51 | static bool raw_samples = false; |
@@ -75,6 +73,7 @@ static off_t post_processing_offset; | |||
75 | 73 | ||
76 | static struct perf_session *session; | 74 | static struct perf_session *session; |
77 | static const char *cpu_list; | 75 | static const char *cpu_list; |
76 | static const char *progname; | ||
78 | 77 | ||
79 | static void advance_output(size_t size) | 78 | static void advance_output(size_t size) |
80 | { | 79 | { |
@@ -139,17 +138,29 @@ static void mmap_read(struct perf_mmap *md) | |||
139 | 138 | ||
140 | static volatile int done = 0; | 139 | static volatile int done = 0; |
141 | static volatile int signr = -1; | 140 | static volatile int signr = -1; |
141 | static volatile int child_finished = 0; | ||
142 | 142 | ||
143 | static void sig_handler(int sig) | 143 | static void sig_handler(int sig) |
144 | { | 144 | { |
145 | if (sig == SIGCHLD) | ||
146 | child_finished = 1; | ||
147 | |||
145 | done = 1; | 148 | done = 1; |
146 | signr = sig; | 149 | signr = sig; |
147 | } | 150 | } |
148 | 151 | ||
149 | static void sig_atexit(void) | 152 | static void sig_atexit(void) |
150 | { | 153 | { |
151 | if (child_pid > 0) | 154 | int status; |
152 | kill(child_pid, SIGTERM); | 155 | |
156 | if (child_pid > 0) { | ||
157 | if (!child_finished) | ||
158 | kill(child_pid, SIGTERM); | ||
159 | |||
160 | wait(&status); | ||
161 | if (WIFSIGNALED(status)) | ||
162 | psignal(WTERMSIG(status), progname); | ||
163 | } | ||
153 | 164 | ||
154 | if (signr == -1 || signr == SIGUSR1) | 165 | if (signr == -1 || signr == SIGUSR1) |
155 | return; | 166 | return; |
@@ -163,6 +174,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | |||
163 | struct perf_event_attr *attr = &evsel->attr; | 174 | struct perf_event_attr *attr = &evsel->attr; |
164 | int track = !evsel->idx; /* only the first counter needs these */ | 175 | int track = !evsel->idx; /* only the first counter needs these */ |
165 | 176 | ||
177 | attr->disabled = 1; | ||
166 | attr->inherit = !no_inherit; | 178 | attr->inherit = !no_inherit; |
167 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 179 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
168 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 180 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
@@ -250,13 +262,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
250 | 262 | ||
251 | static void open_counters(struct perf_evlist *evlist) | 263 | static void open_counters(struct perf_evlist *evlist) |
252 | { | 264 | { |
253 | struct perf_evsel *pos; | 265 | struct perf_evsel *pos, *first; |
254 | 266 | ||
255 | if (evlist->cpus->map[0] < 0) | 267 | if (evlist->cpus->map[0] < 0) |
256 | no_inherit = true; | 268 | no_inherit = true; |
257 | 269 | ||
270 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
271 | |||
258 | list_for_each_entry(pos, &evlist->entries, node) { | 272 | list_for_each_entry(pos, &evlist->entries, node) { |
259 | struct perf_event_attr *attr = &pos->attr; | 273 | struct perf_event_attr *attr = &pos->attr; |
274 | struct xyarray *group_fd = NULL; | ||
260 | /* | 275 | /* |
261 | * Check if parse_single_tracepoint_event has already asked for | 276 | * Check if parse_single_tracepoint_event has already asked for |
262 | * PERF_SAMPLE_TIME. | 277 | * PERF_SAMPLE_TIME. |
@@ -271,15 +286,19 @@ static void open_counters(struct perf_evlist *evlist) | |||
271 | */ | 286 | */ |
272 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; | 287 | bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; |
273 | 288 | ||
289 | if (group && pos != first) | ||
290 | group_fd = first->fd; | ||
291 | |||
274 | config_attr(pos, evlist); | 292 | config_attr(pos, evlist); |
275 | retry_sample_id: | 293 | retry_sample_id: |
276 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 294 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; |
277 | try_again: | 295 | try_again: |
278 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) { | 296 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, |
297 | group_fd) < 0) { | ||
279 | int err = errno; | 298 | int err = errno; |
280 | 299 | ||
281 | if (err == EPERM || err == EACCES) { | 300 | if (err == EPERM || err == EACCES) { |
282 | ui__warning_paranoid(); | 301 | ui__error_paranoid(); |
283 | exit(EXIT_FAILURE); | 302 | exit(EXIT_FAILURE); |
284 | } else if (err == ENODEV && cpu_list) { | 303 | } else if (err == ENODEV && cpu_list) { |
285 | die("No such device - did you specify" | 304 | die("No such device - did you specify" |
@@ -438,7 +457,6 @@ static void mmap_read_all(void) | |||
438 | 457 | ||
439 | static int __cmd_record(int argc, const char **argv) | 458 | static int __cmd_record(int argc, const char **argv) |
440 | { | 459 | { |
441 | int i; | ||
442 | struct stat st; | 460 | struct stat st; |
443 | int flags; | 461 | int flags; |
444 | int err; | 462 | int err; |
@@ -448,6 +466,8 @@ static int __cmd_record(int argc, const char **argv) | |||
448 | char buf; | 466 | char buf; |
449 | struct machine *machine; | 467 | struct machine *machine; |
450 | 468 | ||
469 | progname = argv[0]; | ||
470 | |||
451 | page_size = sysconf(_SC_PAGE_SIZE); | 471 | page_size = sysconf(_SC_PAGE_SIZE); |
452 | 472 | ||
453 | atexit(sig_atexit); | 473 | atexit(sig_atexit); |
@@ -516,6 +536,19 @@ static int __cmd_record(int argc, const char **argv) | |||
516 | if (have_tracepoints(&evsel_list->entries)) | 536 | if (have_tracepoints(&evsel_list->entries)) |
517 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); | 537 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); |
518 | 538 | ||
539 | perf_header__set_feat(&session->header, HEADER_HOSTNAME); | ||
540 | perf_header__set_feat(&session->header, HEADER_OSRELEASE); | ||
541 | perf_header__set_feat(&session->header, HEADER_ARCH); | ||
542 | perf_header__set_feat(&session->header, HEADER_CPUDESC); | ||
543 | perf_header__set_feat(&session->header, HEADER_NRCPUS); | ||
544 | perf_header__set_feat(&session->header, HEADER_EVENT_DESC); | ||
545 | perf_header__set_feat(&session->header, HEADER_CMDLINE); | ||
546 | perf_header__set_feat(&session->header, HEADER_VERSION); | ||
547 | perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); | ||
548 | perf_header__set_feat(&session->header, HEADER_TOTAL_MEM); | ||
549 | perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY); | ||
550 | perf_header__set_feat(&session->header, HEADER_CPUID); | ||
551 | |||
519 | /* 512 kiB: default amount of unprivileged mlocked memory */ | 552 | /* 512 kiB: default amount of unprivileged mlocked memory */ |
520 | if (mmap_pages == UINT_MAX) | 553 | if (mmap_pages == UINT_MAX) |
521 | mmap_pages = (512 * 1024) / page_size; | 554 | mmap_pages = (512 * 1024) / page_size; |
@@ -674,6 +707,8 @@ static int __cmd_record(int argc, const char **argv) | |||
674 | } | 707 | } |
675 | } | 708 | } |
676 | 709 | ||
710 | perf_evlist__enable(evsel_list); | ||
711 | |||
677 | /* | 712 | /* |
678 | * Let the child rip | 713 | * Let the child rip |
679 | */ | 714 | */ |
@@ -682,7 +717,6 @@ static int __cmd_record(int argc, const char **argv) | |||
682 | 717 | ||
683 | for (;;) { | 718 | for (;;) { |
684 | int hits = samples; | 719 | int hits = samples; |
685 | int thread; | ||
686 | 720 | ||
687 | mmap_read_all(); | 721 | mmap_read_all(); |
688 | 722 | ||
@@ -693,19 +727,8 @@ static int __cmd_record(int argc, const char **argv) | |||
693 | waking++; | 727 | waking++; |
694 | } | 728 | } |
695 | 729 | ||
696 | if (done) { | 730 | if (done) |
697 | for (i = 0; i < evsel_list->cpus->nr; i++) { | 731 | perf_evlist__disable(evsel_list); |
698 | struct perf_evsel *pos; | ||
699 | |||
700 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
701 | for (thread = 0; | ||
702 | thread < evsel_list->threads->nr; | ||
703 | thread++) | ||
704 | ioctl(FD(pos, i, thread), | ||
705 | PERF_EVENT_IOC_DISABLE); | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | } | 732 | } |
710 | 733 | ||
711 | if (quiet || signr == SIGUSR1) | 734 | if (quiet || signr == SIGUSR1) |
@@ -768,6 +791,8 @@ const struct option record_options[] = { | |||
768 | "child tasks do not inherit counters"), | 791 | "child tasks do not inherit counters"), |
769 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), | 792 | OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), |
770 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), | 793 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
794 | OPT_BOOLEAN(0, "group", &group, | ||
795 | "put the counters into a counter group"), | ||
771 | OPT_BOOLEAN('g', "call-graph", &call_graph, | 796 | OPT_BOOLEAN('g', "call-graph", &call_graph, |
772 | "do call-graph (stack chain/backtrace) recording"), | 797 | "do call-graph (stack chain/backtrace) recording"), |
773 | OPT_INCR('v', "verbose", &verbose, | 798 | OPT_INCR('v', "verbose", &verbose, |
@@ -795,6 +820,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
795 | int err = -ENOMEM; | 820 | int err = -ENOMEM; |
796 | struct perf_evsel *pos; | 821 | struct perf_evsel *pos; |
797 | 822 | ||
823 | perf_header__set_cmdline(argc, argv); | ||
824 | |||
798 | evsel_list = perf_evlist__new(NULL, NULL); | 825 | evsel_list = perf_evlist__new(NULL, NULL); |
799 | if (evsel_list == NULL) | 826 | if (evsel_list == NULL) |
800 | return -ENOMEM; | 827 | return -ENOMEM; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f854efda7686..4d7c8340c326 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -40,6 +40,7 @@ static char const *input_name = "perf.data"; | |||
40 | static bool force, use_tui, use_stdio; | 40 | static bool force, use_tui, use_stdio; |
41 | static bool hide_unresolved; | 41 | static bool hide_unresolved; |
42 | static bool dont_use_callchains; | 42 | static bool dont_use_callchains; |
43 | static bool show_full_info; | ||
43 | 44 | ||
44 | static bool show_threads; | 45 | static bool show_threads; |
45 | static struct perf_read_values show_threads_values; | 46 | static struct perf_read_values show_threads_values; |
@@ -162,23 +163,22 @@ static int perf_session__setup_sample_type(struct perf_session *self) | |||
162 | { | 163 | { |
163 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 164 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
164 | if (sort__has_parent) { | 165 | if (sort__has_parent) { |
165 | fprintf(stderr, "selected --sort parent, but no" | 166 | ui__warning("Selected --sort parent, but no " |
166 | " callchain data. Did you call" | 167 | "callchain data. Did you call " |
167 | " perf record without -g?\n"); | 168 | "'perf record' without -g?\n"); |
168 | return -EINVAL; | 169 | return -EINVAL; |
169 | } | 170 | } |
170 | if (symbol_conf.use_callchain) { | 171 | if (symbol_conf.use_callchain) { |
171 | fprintf(stderr, "selected -g but no callchain data." | 172 | ui__warning("Selected -g but no callchain data. Did " |
172 | " Did you call perf record without" | 173 | "you call 'perf record' without -g?\n"); |
173 | " -g?\n"); | ||
174 | return -1; | 174 | return -1; |
175 | } | 175 | } |
176 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && | 176 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && |
177 | !symbol_conf.use_callchain) { | 177 | !symbol_conf.use_callchain) { |
178 | symbol_conf.use_callchain = true; | 178 | symbol_conf.use_callchain = true; |
179 | if (callchain_register_param(&callchain_param) < 0) { | 179 | if (callchain_register_param(&callchain_param) < 0) { |
180 | fprintf(stderr, "Can't register callchain" | 180 | ui__warning("Can't register callchain " |
181 | " params\n"); | 181 | "params.\n"); |
182 | return -EINVAL; | 182 | return -EINVAL; |
183 | } | 183 | } |
184 | } | 184 | } |
@@ -230,13 +230,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
230 | 230 | ||
231 | list_for_each_entry(pos, &evlist->entries, node) { | 231 | list_for_each_entry(pos, &evlist->entries, node) { |
232 | struct hists *hists = &pos->hists; | 232 | struct hists *hists = &pos->hists; |
233 | const char *evname = NULL; | 233 | const char *evname = event_name(pos); |
234 | |||
235 | if (rb_first(&hists->entries) != rb_last(&hists->entries)) | ||
236 | evname = event_name(pos); | ||
237 | 234 | ||
238 | hists__fprintf_nr_sample_events(hists, evname, stdout); | 235 | hists__fprintf_nr_sample_events(hists, evname, stdout); |
239 | hists__fprintf(hists, NULL, false, stdout); | 236 | hists__fprintf(hists, NULL, false, true, 0, 0, stdout); |
240 | fprintf(stdout, "\n\n"); | 237 | fprintf(stdout, "\n\n"); |
241 | } | 238 | } |
242 | 239 | ||
@@ -277,6 +274,9 @@ static int __cmd_report(void) | |||
277 | goto out_delete; | 274 | goto out_delete; |
278 | } | 275 | } |
279 | 276 | ||
277 | if (use_browser <= 0) | ||
278 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
279 | |||
280 | if (show_threads) | 280 | if (show_threads) |
281 | perf_read_values_init(&show_threads_values); | 281 | perf_read_values_init(&show_threads_values); |
282 | 282 | ||
@@ -331,9 +331,10 @@ static int __cmd_report(void) | |||
331 | goto out_delete; | 331 | goto out_delete; |
332 | } | 332 | } |
333 | 333 | ||
334 | if (use_browser > 0) | 334 | if (use_browser > 0) { |
335 | perf_evlist__tui_browse_hists(session->evlist, help); | 335 | perf_evlist__tui_browse_hists(session->evlist, help, |
336 | else | 336 | NULL, NULL, 0); |
337 | } else | ||
337 | perf_evlist__tty_browse_hists(session->evlist, help); | 338 | perf_evlist__tty_browse_hists(session->evlist, help); |
338 | 339 | ||
339 | out_delete: | 340 | out_delete: |
@@ -488,6 +489,16 @@ static const struct option options[] = { | |||
488 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 489 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
489 | "Look for files with symbols relative to this directory"), | 490 | "Look for files with symbols relative to this directory"), |
490 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 491 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
492 | OPT_BOOLEAN('I', "show-info", &show_full_info, | ||
493 | "Display extended information about perf.data file"), | ||
494 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | ||
495 | "Interleave source code with assembly code (default)"), | ||
496 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | ||
497 | "Display raw encoding of assembly instructions (default)"), | ||
498 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | ||
499 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | ||
500 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | ||
501 | "Show a column with the sum of periods"), | ||
491 | OPT_END() | 502 | OPT_END() |
492 | }; | 503 | }; |
493 | 504 | ||
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index dcfe8873c9a1..5177964943e7 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = { | |||
1637 | .ordered_samples = true, | 1637 | .ordered_samples = true, |
1638 | }; | 1638 | }; |
1639 | 1639 | ||
1640 | static int read_events(void) | 1640 | static void read_events(bool destroy, struct perf_session **psession) |
1641 | { | 1641 | { |
1642 | int err = -EINVAL; | 1642 | int err = -EINVAL; |
1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
1644 | 0, false, &event_ops); | 1644 | 0, false, &event_ops); |
1645 | if (session == NULL) | 1645 | if (session == NULL) |
1646 | return -ENOMEM; | 1646 | die("No Memory"); |
1647 | 1647 | ||
1648 | if (perf_session__has_traces(session, "record -R")) { | 1648 | if (perf_session__has_traces(session, "record -R")) { |
1649 | err = perf_session__process_events(session, &event_ops); | 1649 | err = perf_session__process_events(session, &event_ops); |
1650 | if (err) | ||
1651 | die("Failed to process events, error %d", err); | ||
1652 | |||
1650 | nr_events = session->hists.stats.nr_events[0]; | 1653 | nr_events = session->hists.stats.nr_events[0]; |
1651 | nr_lost_events = session->hists.stats.total_lost; | 1654 | nr_lost_events = session->hists.stats.total_lost; |
1652 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; | 1655 | nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; |
1653 | } | 1656 | } |
1654 | 1657 | ||
1655 | perf_session__delete(session); | 1658 | if (destroy) |
1656 | return err; | 1659 | perf_session__delete(session); |
1660 | |||
1661 | if (psession) | ||
1662 | *psession = session; | ||
1657 | } | 1663 | } |
1658 | 1664 | ||
1659 | static void print_bad_events(void) | 1665 | static void print_bad_events(void) |
@@ -1689,9 +1695,10 @@ static void print_bad_events(void) | |||
1689 | static void __cmd_lat(void) | 1695 | static void __cmd_lat(void) |
1690 | { | 1696 | { |
1691 | struct rb_node *next; | 1697 | struct rb_node *next; |
1698 | struct perf_session *session; | ||
1692 | 1699 | ||
1693 | setup_pager(); | 1700 | setup_pager(); |
1694 | read_events(); | 1701 | read_events(false, &session); |
1695 | sort_lat(); | 1702 | sort_lat(); |
1696 | 1703 | ||
1697 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); | 1704 | printf("\n ---------------------------------------------------------------------------------------------------------------\n"); |
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void) | |||
1717 | print_bad_events(); | 1724 | print_bad_events(); |
1718 | printf("\n"); | 1725 | printf("\n"); |
1719 | 1726 | ||
1727 | perf_session__delete(session); | ||
1720 | } | 1728 | } |
1721 | 1729 | ||
1722 | static struct trace_sched_handler map_ops = { | 1730 | static struct trace_sched_handler map_ops = { |
@@ -1731,7 +1739,7 @@ static void __cmd_map(void) | |||
1731 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1739 | max_cpu = sysconf(_SC_NPROCESSORS_CONF); |
1732 | 1740 | ||
1733 | setup_pager(); | 1741 | setup_pager(); |
1734 | read_events(); | 1742 | read_events(true, NULL); |
1735 | print_bad_events(); | 1743 | print_bad_events(); |
1736 | } | 1744 | } |
1737 | 1745 | ||
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void) | |||
1744 | 1752 | ||
1745 | test_calibrations(); | 1753 | test_calibrations(); |
1746 | 1754 | ||
1747 | read_events(); | 1755 | read_events(true, NULL); |
1748 | 1756 | ||
1749 | printf("nr_run_events: %ld\n", nr_run_events); | 1757 | printf("nr_run_events: %ld\n", nr_run_events); |
1750 | printf("nr_sleep_events: %ld\n", nr_sleep_events); | 1758 | printf("nr_sleep_events: %ld\n", nr_sleep_events); |
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void) | |||
1769 | 1777 | ||
1770 | 1778 | ||
1771 | static const char * const sched_usage[] = { | 1779 | static const char * const sched_usage[] = { |
1772 | "perf sched [<options>] {record|latency|map|replay|trace}", | 1780 | "perf sched [<options>] {record|latency|map|replay|script}", |
1773 | NULL | 1781 | NULL |
1774 | }; | 1782 | }; |
1775 | 1783 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 09024ec2ab2e..2f62a2952269 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -22,6 +22,7 @@ static u64 last_timestamp; | |||
22 | static u64 nr_unordered; | 22 | static u64 nr_unordered; |
23 | extern const struct option record_options[]; | 23 | extern const struct option record_options[]; |
24 | static bool no_callchain; | 24 | static bool no_callchain; |
25 | static bool show_full_info; | ||
25 | static const char *cpu_list; | 26 | static const char *cpu_list; |
26 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 27 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
27 | 28 | ||
@@ -1083,7 +1084,8 @@ static const struct option options[] = { | |||
1083 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", | 1084 | "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", |
1084 | parse_output_fields), | 1085 | parse_output_fields), |
1085 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 1086 | OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
1086 | 1087 | OPT_BOOLEAN('I', "show-info", &show_full_info, | |
1088 | "display extended information from perf.data file"), | ||
1087 | OPT_END() | 1089 | OPT_END() |
1088 | }; | 1090 | }; |
1089 | 1091 | ||
@@ -1268,6 +1270,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1268 | return -1; | 1270 | return -1; |
1269 | } | 1271 | } |
1270 | 1272 | ||
1273 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
1274 | |||
1271 | if (!no_callchain) | 1275 | if (!no_callchain) |
1272 | symbol_conf.use_callchain = true; | 1276 | symbol_conf.use_callchain = true; |
1273 | else | 1277 | else |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1ad04ce29c34..7d98676808d8 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -193,6 +193,10 @@ static int big_num_opt = -1; | |||
193 | static const char *cpu_list; | 193 | static const char *cpu_list; |
194 | static const char *csv_sep = NULL; | 194 | static const char *csv_sep = NULL; |
195 | static bool csv_output = false; | 195 | static bool csv_output = false; |
196 | static bool group = false; | ||
197 | static const char *output_name = NULL; | ||
198 | static FILE *output = NULL; | ||
199 | static int output_fd; | ||
196 | 200 | ||
197 | static volatile int done = 0; | 201 | static volatile int done = 0; |
198 | 202 | ||
@@ -250,8 +254,13 @@ static double avg_stats(struct stats *stats) | |||
250 | */ | 254 | */ |
251 | static double stddev_stats(struct stats *stats) | 255 | static double stddev_stats(struct stats *stats) |
252 | { | 256 | { |
253 | double variance = stats->M2 / (stats->n - 1); | 257 | double variance, variance_mean; |
254 | double variance_mean = variance / stats->n; | 258 | |
259 | if (!stats->n) | ||
260 | return 0.0; | ||
261 | |||
262 | variance = stats->M2 / (stats->n - 1); | ||
263 | variance_mean = variance / stats->n; | ||
255 | 264 | ||
256 | return sqrt(variance_mean); | 265 | return sqrt(variance_mean); |
257 | } | 266 | } |
@@ -269,9 +278,14 @@ struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; | |||
269 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; | 278 | struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; |
270 | struct stats walltime_nsecs_stats; | 279 | struct stats walltime_nsecs_stats; |
271 | 280 | ||
272 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 281 | static int create_perf_stat_counter(struct perf_evsel *evsel, |
282 | struct perf_evsel *first) | ||
273 | { | 283 | { |
274 | struct perf_event_attr *attr = &evsel->attr; | 284 | struct perf_event_attr *attr = &evsel->attr; |
285 | struct xyarray *group_fd = NULL; | ||
286 | |||
287 | if (group && evsel != first) | ||
288 | group_fd = first->fd; | ||
275 | 289 | ||
276 | if (scale) | 290 | if (scale) |
277 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 291 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
@@ -280,14 +294,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) | |||
280 | attr->inherit = !no_inherit; | 294 | attr->inherit = !no_inherit; |
281 | 295 | ||
282 | if (system_wide) | 296 | if (system_wide) |
283 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); | 297 | return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, |
284 | 298 | group, group_fd); | |
285 | if (target_pid == -1 && target_tid == -1) { | 299 | if (target_pid == -1 && target_tid == -1) { |
286 | attr->disabled = 1; | 300 | attr->disabled = 1; |
287 | attr->enable_on_exec = 1; | 301 | attr->enable_on_exec = 1; |
288 | } | 302 | } |
289 | 303 | ||
290 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); | 304 | return perf_evsel__open_per_thread(evsel, evsel_list->threads, |
305 | group, group_fd); | ||
291 | } | 306 | } |
292 | 307 | ||
293 | /* | 308 | /* |
@@ -351,7 +366,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
351 | update_stats(&ps->res_stats[i], count[i]); | 366 | update_stats(&ps->res_stats[i], count[i]); |
352 | 367 | ||
353 | if (verbose) { | 368 | if (verbose) { |
354 | fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", | 369 | fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", |
355 | event_name(counter), count[0], count[1], count[2]); | 370 | event_name(counter), count[0], count[1], count[2]); |
356 | } | 371 | } |
357 | 372 | ||
@@ -387,7 +402,7 @@ static int read_counter(struct perf_evsel *counter) | |||
387 | static int run_perf_stat(int argc __used, const char **argv) | 402 | static int run_perf_stat(int argc __used, const char **argv) |
388 | { | 403 | { |
389 | unsigned long long t0, t1; | 404 | unsigned long long t0, t1; |
390 | struct perf_evsel *counter; | 405 | struct perf_evsel *counter, *first; |
391 | int status = 0; | 406 | int status = 0; |
392 | int child_ready_pipe[2], go_pipe[2]; | 407 | int child_ready_pipe[2], go_pipe[2]; |
393 | const bool forks = (argc > 0); | 408 | const bool forks = (argc > 0); |
@@ -444,8 +459,10 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
444 | close(child_ready_pipe[0]); | 459 | close(child_ready_pipe[0]); |
445 | } | 460 | } |
446 | 461 | ||
462 | first = list_entry(evsel_list->entries.next, struct perf_evsel, node); | ||
463 | |||
447 | list_for_each_entry(counter, &evsel_list->entries, node) { | 464 | list_for_each_entry(counter, &evsel_list->entries, node) { |
448 | if (create_perf_stat_counter(counter) < 0) { | 465 | if (create_perf_stat_counter(counter, first) < 0) { |
449 | if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { | 466 | if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) { |
450 | if (verbose) | 467 | if (verbose) |
451 | ui__warning("%s event is not supported by the kernel.\n", | 468 | ui__warning("%s event is not supported by the kernel.\n", |
@@ -486,6 +503,8 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
486 | if (forks) { | 503 | if (forks) { |
487 | close(go_pipe[1]); | 504 | close(go_pipe[1]); |
488 | wait(&status); | 505 | wait(&status); |
506 | if (WIFSIGNALED(status)) | ||
507 | psignal(WTERMSIG(status), argv[0]); | ||
489 | } else { | 508 | } else { |
490 | while(!done) sleep(1); | 509 | while(!done) sleep(1); |
491 | } | 510 | } |
@@ -518,9 +537,9 @@ static void print_noise_pct(double total, double avg) | |||
518 | pct = 100.0*total/avg; | 537 | pct = 100.0*total/avg; |
519 | 538 | ||
520 | if (csv_output) | 539 | if (csv_output) |
521 | fprintf(stderr, "%s%.2f%%", csv_sep, pct); | 540 | fprintf(output, "%s%.2f%%", csv_sep, pct); |
522 | else | 541 | else if (pct) |
523 | fprintf(stderr, " ( +-%6.2f%% )", pct); | 542 | fprintf(output, " ( +-%6.2f%% )", pct); |
524 | } | 543 | } |
525 | 544 | ||
526 | static void print_noise(struct perf_evsel *evsel, double avg) | 545 | static void print_noise(struct perf_evsel *evsel, double avg) |
@@ -545,16 +564,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
545 | csv_output ? 0 : -4, | 564 | csv_output ? 0 : -4, |
546 | evsel_list->cpus->map[cpu], csv_sep); | 565 | evsel_list->cpus->map[cpu], csv_sep); |
547 | 566 | ||
548 | fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); | 567 | fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel)); |
549 | 568 | ||
550 | if (evsel->cgrp) | 569 | if (evsel->cgrp) |
551 | fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); | 570 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
552 | 571 | ||
553 | if (csv_output) | 572 | if (csv_output) |
554 | return; | 573 | return; |
555 | 574 | ||
556 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) | 575 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) |
557 | fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); | 576 | fprintf(output, " # %8.3f CPUs utilized ", |
577 | avg / avg_stats(&walltime_nsecs_stats)); | ||
558 | } | 578 | } |
559 | 579 | ||
560 | static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) | 580 | static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -575,9 +595,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us | |||
575 | else if (ratio > 10.0) | 595 | else if (ratio > 10.0) |
576 | color = PERF_COLOR_YELLOW; | 596 | color = PERF_COLOR_YELLOW; |
577 | 597 | ||
578 | fprintf(stderr, " # "); | 598 | fprintf(output, " # "); |
579 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 599 | color_fprintf(output, color, "%6.2f%%", ratio); |
580 | fprintf(stderr, " frontend cycles idle "); | 600 | fprintf(output, " frontend cycles idle "); |
581 | } | 601 | } |
582 | 602 | ||
583 | static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) | 603 | static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -598,9 +618,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use | |||
598 | else if (ratio > 20.0) | 618 | else if (ratio > 20.0) |
599 | color = PERF_COLOR_YELLOW; | 619 | color = PERF_COLOR_YELLOW; |
600 | 620 | ||
601 | fprintf(stderr, " # "); | 621 | fprintf(output, " # "); |
602 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 622 | color_fprintf(output, color, "%6.2f%%", ratio); |
603 | fprintf(stderr, " backend cycles idle "); | 623 | fprintf(output, " backend cycles idle "); |
604 | } | 624 | } |
605 | 625 | ||
606 | static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 626 | static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -621,9 +641,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double | |||
621 | else if (ratio > 5.0) | 641 | else if (ratio > 5.0) |
622 | color = PERF_COLOR_YELLOW; | 642 | color = PERF_COLOR_YELLOW; |
623 | 643 | ||
624 | fprintf(stderr, " # "); | 644 | fprintf(output, " # "); |
625 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 645 | color_fprintf(output, color, "%6.2f%%", ratio); |
626 | fprintf(stderr, " of all branches "); | 646 | fprintf(output, " of all branches "); |
627 | } | 647 | } |
628 | 648 | ||
629 | static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 649 | static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -644,9 +664,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou | |||
644 | else if (ratio > 5.0) | 664 | else if (ratio > 5.0) |
645 | color = PERF_COLOR_YELLOW; | 665 | color = PERF_COLOR_YELLOW; |
646 | 666 | ||
647 | fprintf(stderr, " # "); | 667 | fprintf(output, " # "); |
648 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 668 | color_fprintf(output, color, "%6.2f%%", ratio); |
649 | fprintf(stderr, " of all L1-dcache hits "); | 669 | fprintf(output, " of all L1-dcache hits "); |
650 | } | 670 | } |
651 | 671 | ||
652 | static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 672 | static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -667,9 +687,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou | |||
667 | else if (ratio > 5.0) | 687 | else if (ratio > 5.0) |
668 | color = PERF_COLOR_YELLOW; | 688 | color = PERF_COLOR_YELLOW; |
669 | 689 | ||
670 | fprintf(stderr, " # "); | 690 | fprintf(output, " # "); |
671 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 691 | color_fprintf(output, color, "%6.2f%%", ratio); |
672 | fprintf(stderr, " of all L1-icache hits "); | 692 | fprintf(output, " of all L1-icache hits "); |
673 | } | 693 | } |
674 | 694 | ||
675 | static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 695 | static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -690,9 +710,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do | |||
690 | else if (ratio > 5.0) | 710 | else if (ratio > 5.0) |
691 | color = PERF_COLOR_YELLOW; | 711 | color = PERF_COLOR_YELLOW; |
692 | 712 | ||
693 | fprintf(stderr, " # "); | 713 | fprintf(output, " # "); |
694 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 714 | color_fprintf(output, color, "%6.2f%%", ratio); |
695 | fprintf(stderr, " of all dTLB cache hits "); | 715 | fprintf(output, " of all dTLB cache hits "); |
696 | } | 716 | } |
697 | 717 | ||
698 | static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 718 | static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -713,9 +733,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do | |||
713 | else if (ratio > 5.0) | 733 | else if (ratio > 5.0) |
714 | color = PERF_COLOR_YELLOW; | 734 | color = PERF_COLOR_YELLOW; |
715 | 735 | ||
716 | fprintf(stderr, " # "); | 736 | fprintf(output, " # "); |
717 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 737 | color_fprintf(output, color, "%6.2f%%", ratio); |
718 | fprintf(stderr, " of all iTLB cache hits "); | 738 | fprintf(output, " of all iTLB cache hits "); |
719 | } | 739 | } |
720 | 740 | ||
721 | static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 741 | static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -736,9 +756,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub | |||
736 | else if (ratio > 5.0) | 756 | else if (ratio > 5.0) |
737 | color = PERF_COLOR_YELLOW; | 757 | color = PERF_COLOR_YELLOW; |
738 | 758 | ||
739 | fprintf(stderr, " # "); | 759 | fprintf(output, " # "); |
740 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 760 | color_fprintf(output, color, "%6.2f%%", ratio); |
741 | fprintf(stderr, " of all LL-cache hits "); | 761 | fprintf(output, " of all LL-cache hits "); |
742 | } | 762 | } |
743 | 763 | ||
744 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | 764 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) |
@@ -761,10 +781,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
761 | else | 781 | else |
762 | cpu = 0; | 782 | cpu = 0; |
763 | 783 | ||
764 | fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); | 784 | fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel)); |
765 | 785 | ||
766 | if (evsel->cgrp) | 786 | if (evsel->cgrp) |
767 | fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); | 787 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
768 | 788 | ||
769 | if (csv_output) | 789 | if (csv_output) |
770 | return; | 790 | return; |
@@ -775,14 +795,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
775 | if (total) | 795 | if (total) |
776 | ratio = avg / total; | 796 | ratio = avg / total; |
777 | 797 | ||
778 | fprintf(stderr, " # %5.2f insns per cycle ", ratio); | 798 | fprintf(output, " # %5.2f insns per cycle ", ratio); |
779 | 799 | ||
780 | total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); | 800 | total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); |
781 | total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); | 801 | total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); |
782 | 802 | ||
783 | if (total && avg) { | 803 | if (total && avg) { |
784 | ratio = total / avg; | 804 | ratio = total / avg; |
785 | fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); | 805 | fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); |
786 | } | 806 | } |
787 | 807 | ||
788 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && | 808 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && |
@@ -830,7 +850,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
830 | if (total) | 850 | if (total) |
831 | ratio = avg * 100 / total; | 851 | ratio = avg * 100 / total; |
832 | 852 | ||
833 | fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); | 853 | fprintf(output, " # %8.3f %% of all cache refs ", ratio); |
834 | 854 | ||
835 | } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { | 855 | } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { |
836 | print_stalled_cycles_frontend(cpu, evsel, avg); | 856 | print_stalled_cycles_frontend(cpu, evsel, avg); |
@@ -842,16 +862,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
842 | if (total) | 862 | if (total) |
843 | ratio = 1.0 * avg / total; | 863 | ratio = 1.0 * avg / total; |
844 | 864 | ||
845 | fprintf(stderr, " # %8.3f GHz ", ratio); | 865 | fprintf(output, " # %8.3f GHz ", ratio); |
846 | } else if (runtime_nsecs_stats[cpu].n != 0) { | 866 | } else if (runtime_nsecs_stats[cpu].n != 0) { |
847 | total = avg_stats(&runtime_nsecs_stats[cpu]); | 867 | total = avg_stats(&runtime_nsecs_stats[cpu]); |
848 | 868 | ||
849 | if (total) | 869 | if (total) |
850 | ratio = 1000.0 * avg / total; | 870 | ratio = 1000.0 * avg / total; |
851 | 871 | ||
852 | fprintf(stderr, " # %8.3f M/sec ", ratio); | 872 | fprintf(output, " # %8.3f M/sec ", ratio); |
853 | } else { | 873 | } else { |
854 | fprintf(stderr, " "); | 874 | fprintf(output, " "); |
855 | } | 875 | } |
856 | } | 876 | } |
857 | 877 | ||
@@ -866,7 +886,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
866 | int scaled = counter->counts->scaled; | 886 | int scaled = counter->counts->scaled; |
867 | 887 | ||
868 | if (scaled == -1) { | 888 | if (scaled == -1) { |
869 | fprintf(stderr, "%*s%s%*s", | 889 | fprintf(output, "%*s%s%*s", |
870 | csv_output ? 0 : 18, | 890 | csv_output ? 0 : 18, |
871 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 891 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
872 | csv_sep, | 892 | csv_sep, |
@@ -874,9 +894,9 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
874 | event_name(counter)); | 894 | event_name(counter)); |
875 | 895 | ||
876 | if (counter->cgrp) | 896 | if (counter->cgrp) |
877 | fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); | 897 | fprintf(output, "%s%s", csv_sep, counter->cgrp->name); |
878 | 898 | ||
879 | fputc('\n', stderr); | 899 | fputc('\n', output); |
880 | return; | 900 | return; |
881 | } | 901 | } |
882 | 902 | ||
@@ -888,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
888 | print_noise(counter, avg); | 908 | print_noise(counter, avg); |
889 | 909 | ||
890 | if (csv_output) { | 910 | if (csv_output) { |
891 | fputc('\n', stderr); | 911 | fputc('\n', output); |
892 | return; | 912 | return; |
893 | } | 913 | } |
894 | 914 | ||
@@ -898,9 +918,9 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
898 | avg_enabled = avg_stats(&ps->res_stats[1]); | 918 | avg_enabled = avg_stats(&ps->res_stats[1]); |
899 | avg_running = avg_stats(&ps->res_stats[2]); | 919 | avg_running = avg_stats(&ps->res_stats[2]); |
900 | 920 | ||
901 | fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); | 921 | fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled); |
902 | } | 922 | } |
903 | fprintf(stderr, "\n"); | 923 | fprintf(output, "\n"); |
904 | } | 924 | } |
905 | 925 | ||
906 | /* | 926 | /* |
@@ -917,7 +937,7 @@ static void print_counter(struct perf_evsel *counter) | |||
917 | ena = counter->counts->cpu[cpu].ena; | 937 | ena = counter->counts->cpu[cpu].ena; |
918 | run = counter->counts->cpu[cpu].run; | 938 | run = counter->counts->cpu[cpu].run; |
919 | if (run == 0 || ena == 0) { | 939 | if (run == 0 || ena == 0) { |
920 | fprintf(stderr, "CPU%*d%s%*s%s%*s", | 940 | fprintf(output, "CPU%*d%s%*s%s%*s", |
921 | csv_output ? 0 : -4, | 941 | csv_output ? 0 : -4, |
922 | evsel_list->cpus->map[cpu], csv_sep, | 942 | evsel_list->cpus->map[cpu], csv_sep, |
923 | csv_output ? 0 : 18, | 943 | csv_output ? 0 : 18, |
@@ -927,9 +947,10 @@ static void print_counter(struct perf_evsel *counter) | |||
927 | event_name(counter)); | 947 | event_name(counter)); |
928 | 948 | ||
929 | if (counter->cgrp) | 949 | if (counter->cgrp) |
930 | fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); | 950 | fprintf(output, "%s%s", |
951 | csv_sep, counter->cgrp->name); | ||
931 | 952 | ||
932 | fputc('\n', stderr); | 953 | fputc('\n', output); |
933 | continue; | 954 | continue; |
934 | } | 955 | } |
935 | 956 | ||
@@ -942,9 +963,10 @@ static void print_counter(struct perf_evsel *counter) | |||
942 | print_noise(counter, 1.0); | 963 | print_noise(counter, 1.0); |
943 | 964 | ||
944 | if (run != ena) | 965 | if (run != ena) |
945 | fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); | 966 | fprintf(output, " (%.2f%%)", |
967 | 100.0 * run / ena); | ||
946 | } | 968 | } |
947 | fputc('\n', stderr); | 969 | fputc('\n', output); |
948 | } | 970 | } |
949 | } | 971 | } |
950 | 972 | ||
@@ -956,21 +978,21 @@ static void print_stat(int argc, const char **argv) | |||
956 | fflush(stdout); | 978 | fflush(stdout); |
957 | 979 | ||
958 | if (!csv_output) { | 980 | if (!csv_output) { |
959 | fprintf(stderr, "\n"); | 981 | fprintf(output, "\n"); |
960 | fprintf(stderr, " Performance counter stats for "); | 982 | fprintf(output, " Performance counter stats for "); |
961 | if(target_pid == -1 && target_tid == -1) { | 983 | if(target_pid == -1 && target_tid == -1) { |
962 | fprintf(stderr, "\'%s", argv[0]); | 984 | fprintf(output, "\'%s", argv[0]); |
963 | for (i = 1; i < argc; i++) | 985 | for (i = 1; i < argc; i++) |
964 | fprintf(stderr, " %s", argv[i]); | 986 | fprintf(output, " %s", argv[i]); |
965 | } else if (target_pid != -1) | 987 | } else if (target_pid != -1) |
966 | fprintf(stderr, "process id \'%d", target_pid); | 988 | fprintf(output, "process id \'%d", target_pid); |
967 | else | 989 | else |
968 | fprintf(stderr, "thread id \'%d", target_tid); | 990 | fprintf(output, "thread id \'%d", target_tid); |
969 | 991 | ||
970 | fprintf(stderr, "\'"); | 992 | fprintf(output, "\'"); |
971 | if (run_count > 1) | 993 | if (run_count > 1) |
972 | fprintf(stderr, " (%d runs)", run_count); | 994 | fprintf(output, " (%d runs)", run_count); |
973 | fprintf(stderr, ":\n\n"); | 995 | fprintf(output, ":\n\n"); |
974 | } | 996 | } |
975 | 997 | ||
976 | if (no_aggr) { | 998 | if (no_aggr) { |
@@ -983,15 +1005,15 @@ static void print_stat(int argc, const char **argv) | |||
983 | 1005 | ||
984 | if (!csv_output) { | 1006 | if (!csv_output) { |
985 | if (!null_run) | 1007 | if (!null_run) |
986 | fprintf(stderr, "\n"); | 1008 | fprintf(output, "\n"); |
987 | fprintf(stderr, " %17.9f seconds time elapsed", | 1009 | fprintf(output, " %17.9f seconds time elapsed", |
988 | avg_stats(&walltime_nsecs_stats)/1e9); | 1010 | avg_stats(&walltime_nsecs_stats)/1e9); |
989 | if (run_count > 1) { | 1011 | if (run_count > 1) { |
990 | fprintf(stderr, " "); | 1012 | fprintf(output, " "); |
991 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), | 1013 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), |
992 | avg_stats(&walltime_nsecs_stats)); | 1014 | avg_stats(&walltime_nsecs_stats)); |
993 | } | 1015 | } |
994 | fprintf(stderr, "\n\n"); | 1016 | fprintf(output, "\n\n"); |
995 | } | 1017 | } |
996 | } | 1018 | } |
997 | 1019 | ||
@@ -1029,6 +1051,8 @@ static int stat__set_big_num(const struct option *opt __used, | |||
1029 | return 0; | 1051 | return 0; |
1030 | } | 1052 | } |
1031 | 1053 | ||
1054 | static bool append_file; | ||
1055 | |||
1032 | static const struct option options[] = { | 1056 | static const struct option options[] = { |
1033 | OPT_CALLBACK('e', "event", &evsel_list, "event", | 1057 | OPT_CALLBACK('e', "event", &evsel_list, "event", |
1034 | "event selector. use 'perf list' to list available events", | 1058 | "event selector. use 'perf list' to list available events", |
@@ -1043,6 +1067,8 @@ static const struct option options[] = { | |||
1043 | "stat events on existing thread id"), | 1067 | "stat events on existing thread id"), |
1044 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1068 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1045 | "system-wide collection from all CPUs"), | 1069 | "system-wide collection from all CPUs"), |
1070 | OPT_BOOLEAN('g', "group", &group, | ||
1071 | "put the counters into a counter group"), | ||
1046 | OPT_BOOLEAN('c', "scale", &scale, | 1072 | OPT_BOOLEAN('c', "scale", &scale, |
1047 | "scale/normalize counters"), | 1073 | "scale/normalize counters"), |
1048 | OPT_INCR('v', "verbose", &verbose, | 1074 | OPT_INCR('v', "verbose", &verbose, |
@@ -1067,6 +1093,11 @@ static const struct option options[] = { | |||
1067 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | 1093 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", |
1068 | "monitor event in cgroup name only", | 1094 | "monitor event in cgroup name only", |
1069 | parse_cgroups), | 1095 | parse_cgroups), |
1096 | OPT_STRING('o', "output", &output_name, "file", | ||
1097 | "output file name"), | ||
1098 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
1099 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
1100 | "log output to fd, instead of stderr"), | ||
1070 | OPT_END() | 1101 | OPT_END() |
1071 | }; | 1102 | }; |
1072 | 1103 | ||
@@ -1138,6 +1169,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1138 | { | 1169 | { |
1139 | struct perf_evsel *pos; | 1170 | struct perf_evsel *pos; |
1140 | int status = -ENOMEM; | 1171 | int status = -ENOMEM; |
1172 | const char *mode; | ||
1141 | 1173 | ||
1142 | setlocale(LC_ALL, ""); | 1174 | setlocale(LC_ALL, ""); |
1143 | 1175 | ||
@@ -1148,16 +1180,46 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1148 | argc = parse_options(argc, argv, options, stat_usage, | 1180 | argc = parse_options(argc, argv, options, stat_usage, |
1149 | PARSE_OPT_STOP_AT_NON_OPTION); | 1181 | PARSE_OPT_STOP_AT_NON_OPTION); |
1150 | 1182 | ||
1151 | if (csv_sep) | 1183 | output = stderr; |
1184 | if (output_name && strcmp(output_name, "-")) | ||
1185 | output = NULL; | ||
1186 | |||
1187 | if (output_name && output_fd) { | ||
1188 | fprintf(stderr, "cannot use both --output and --log-fd\n"); | ||
1189 | usage_with_options(stat_usage, options); | ||
1190 | } | ||
1191 | if (!output) { | ||
1192 | struct timespec tm; | ||
1193 | mode = append_file ? "a" : "w"; | ||
1194 | |||
1195 | output = fopen(output_name, mode); | ||
1196 | if (!output) { | ||
1197 | perror("failed to create output file"); | ||
1198 | exit(-1); | ||
1199 | } | ||
1200 | clock_gettime(CLOCK_REALTIME, &tm); | ||
1201 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); | ||
1202 | } else if (output_fd != 2) { | ||
1203 | mode = append_file ? "a" : "w"; | ||
1204 | output = fdopen(output_fd, mode); | ||
1205 | if (!output) { | ||
1206 | perror("Failed opening logfd"); | ||
1207 | return -errno; | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | if (csv_sep) { | ||
1152 | csv_output = true; | 1212 | csv_output = true; |
1153 | else | 1213 | if (!strcmp(csv_sep, "\\t")) |
1214 | csv_sep = "\t"; | ||
1215 | } else | ||
1154 | csv_sep = DEFAULT_SEPARATOR; | 1216 | csv_sep = DEFAULT_SEPARATOR; |
1155 | 1217 | ||
1156 | /* | 1218 | /* |
1157 | * let the spreadsheet do the pretty-printing | 1219 | * let the spreadsheet do the pretty-printing |
1158 | */ | 1220 | */ |
1159 | if (csv_output) { | 1221 | if (csv_output) { |
1160 | /* User explicitely passed -B? */ | 1222 | /* User explicitly passed -B? */ |
1161 | if (big_num_opt == 1) { | 1223 | if (big_num_opt == 1) { |
1162 | fprintf(stderr, "-B option not supported with -x\n"); | 1224 | fprintf(stderr, "-B option not supported with -x\n"); |
1163 | usage_with_options(stat_usage, options); | 1225 | usage_with_options(stat_usage, options); |
@@ -1223,7 +1285,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1223 | status = 0; | 1285 | status = 0; |
1224 | for (run_idx = 0; run_idx < run_count; run_idx++) { | 1286 | for (run_idx = 0; run_idx < run_count; run_idx++) { |
1225 | if (run_count != 1 && verbose) | 1287 | if (run_count != 1 && verbose) |
1226 | fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); | 1288 | fprintf(output, "[ perf stat: executing run #%d ... ]\n", |
1289 | run_idx + 1); | ||
1227 | 1290 | ||
1228 | if (sync_run) | 1291 | if (sync_run) |
1229 | sync(); | 1292 | sync(); |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 55f4c76f2821..831d1baeac37 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -291,7 +291,7 @@ static int test__open_syscall_event(void) | |||
291 | goto out_thread_map_delete; | 291 | goto out_thread_map_delete; |
292 | } | 292 | } |
293 | 293 | ||
294 | if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { | 294 | if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) { |
295 | pr_debug("failed to open counter: %s, " | 295 | pr_debug("failed to open counter: %s, " |
296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 296 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
297 | strerror(errno)); | 297 | strerror(errno)); |
@@ -366,7 +366,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
366 | goto out_thread_map_delete; | 366 | goto out_thread_map_delete; |
367 | } | 367 | } |
368 | 368 | ||
369 | if (perf_evsel__open(evsel, cpus, threads, false) < 0) { | 369 | if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) { |
370 | pr_debug("failed to open counter: %s, " | 370 | pr_debug("failed to open counter: %s, " |
371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 371 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
372 | strerror(errno)); | 372 | strerror(errno)); |
@@ -531,7 +531,7 @@ static int test__basic_mmap(void) | |||
531 | 531 | ||
532 | perf_evlist__add(evlist, evsels[i]); | 532 | perf_evlist__add(evlist, evsels[i]); |
533 | 533 | ||
534 | if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { | 534 | if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) { |
535 | pr_debug("failed to open counter: %s, " | 535 | pr_debug("failed to open counter: %s, " |
536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 536 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
537 | strerror(errno)); | 537 | strerror(errno)); |
@@ -561,7 +561,7 @@ static int test__basic_mmap(void) | |||
561 | } | 561 | } |
562 | 562 | ||
563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, | 563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, |
564 | false, &sample); | 564 | false, &sample, false); |
565 | if (err) { | 565 | if (err) { |
566 | pr_err("Can't parse sample, err = %d\n", err); | 566 | pr_err("Can't parse sample, err = %d\n", err); |
567 | goto out_munmap; | 567 | goto out_munmap; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a43433f08300..c9cdedb58134 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * any workload, CPU or specific PID. | 5 | * any workload, CPU or specific PID. |
6 | * | 6 | * |
7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> | 7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> |
8 | * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
8 | * | 9 | * |
9 | * Improvements and fixes by: | 10 | * Improvements and fixes by: |
10 | * | 11 | * |
@@ -36,6 +37,7 @@ | |||
36 | #include "util/parse-events.h" | 37 | #include "util/parse-events.h" |
37 | #include "util/cpumap.h" | 38 | #include "util/cpumap.h" |
38 | #include "util/xyarray.h" | 39 | #include "util/xyarray.h" |
40 | #include "util/sort.h" | ||
39 | 41 | ||
40 | #include "util/debug.h" | 42 | #include "util/debug.h" |
41 | 43 | ||
@@ -65,12 +67,8 @@ | |||
65 | static struct perf_top top = { | 67 | static struct perf_top top = { |
66 | .count_filter = 5, | 68 | .count_filter = 5, |
67 | .delay_secs = 2, | 69 | .delay_secs = 2, |
68 | .display_weighted = -1, | ||
69 | .target_pid = -1, | 70 | .target_pid = -1, |
70 | .target_tid = -1, | 71 | .target_tid = -1, |
71 | .active_symbols = LIST_HEAD_INIT(top.active_symbols), | ||
72 | .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER, | ||
73 | .active_symbols_cond = PTHREAD_COND_INITIALIZER, | ||
74 | .freq = 1000, /* 1 KHz */ | 72 | .freq = 1000, /* 1 KHz */ |
75 | }; | 73 | }; |
76 | 74 | ||
@@ -78,6 +76,12 @@ static bool system_wide = false; | |||
78 | 76 | ||
79 | static bool use_tui, use_stdio; | 77 | static bool use_tui, use_stdio; |
80 | 78 | ||
79 | static bool sort_has_symbols; | ||
80 | |||
81 | static bool dont_use_callchains; | ||
82 | static char callchain_default_opt[] = "fractal,0.5,callee"; | ||
83 | |||
84 | |||
81 | static int default_interval = 0; | 85 | static int default_interval = 0; |
82 | 86 | ||
83 | static bool kptr_restrict_warned; | 87 | static bool kptr_restrict_warned; |
@@ -85,7 +89,7 @@ static bool vmlinux_warned; | |||
85 | static bool inherit = false; | 89 | static bool inherit = false; |
86 | static int realtime_prio = 0; | 90 | static int realtime_prio = 0; |
87 | static bool group = false; | 91 | static bool group = false; |
88 | static unsigned int page_size; | 92 | static bool sample_id_all_avail = true; |
89 | static unsigned int mmap_pages = 128; | 93 | static unsigned int mmap_pages = 128; |
90 | 94 | ||
91 | static bool dump_symtab = false; | 95 | static bool dump_symtab = false; |
@@ -93,7 +97,6 @@ static bool dump_symtab = false; | |||
93 | static struct winsize winsize; | 97 | static struct winsize winsize; |
94 | 98 | ||
95 | static const char *sym_filter = NULL; | 99 | static const char *sym_filter = NULL; |
96 | struct sym_entry *sym_filter_entry_sched = NULL; | ||
97 | static int sym_pcnt_filter = 5; | 100 | static int sym_pcnt_filter = 5; |
98 | 101 | ||
99 | /* | 102 | /* |
@@ -136,18 +139,18 @@ static void sig_winch_handler(int sig __used) | |||
136 | update_print_entries(&winsize); | 139 | update_print_entries(&winsize); |
137 | } | 140 | } |
138 | 141 | ||
139 | static int parse_source(struct sym_entry *syme) | 142 | static int parse_source(struct hist_entry *he) |
140 | { | 143 | { |
141 | struct symbol *sym; | 144 | struct symbol *sym; |
142 | struct annotation *notes; | 145 | struct annotation *notes; |
143 | struct map *map; | 146 | struct map *map; |
144 | int err = -1; | 147 | int err = -1; |
145 | 148 | ||
146 | if (!syme) | 149 | if (!he || !he->ms.sym) |
147 | return -1; | 150 | return -1; |
148 | 151 | ||
149 | sym = sym_entry__symbol(syme); | 152 | sym = he->ms.sym; |
150 | map = syme->map; | 153 | map = he->ms.map; |
151 | 154 | ||
152 | /* | 155 | /* |
153 | * We can't annotate with just /proc/kallsyms | 156 | * We can't annotate with just /proc/kallsyms |
@@ -175,52 +178,63 @@ static int parse_source(struct sym_entry *syme) | |||
175 | return err; | 178 | return err; |
176 | } | 179 | } |
177 | 180 | ||
178 | err = symbol__annotate(sym, syme->map, 0); | 181 | err = symbol__annotate(sym, map, 0); |
179 | if (err == 0) { | 182 | if (err == 0) { |
180 | out_assign: | 183 | out_assign: |
181 | top.sym_filter_entry = syme; | 184 | top.sym_filter_entry = he; |
182 | } | 185 | } |
183 | 186 | ||
184 | pthread_mutex_unlock(¬es->lock); | 187 | pthread_mutex_unlock(¬es->lock); |
185 | return err; | 188 | return err; |
186 | } | 189 | } |
187 | 190 | ||
188 | static void __zero_source_counters(struct sym_entry *syme) | 191 | static void __zero_source_counters(struct hist_entry *he) |
189 | { | 192 | { |
190 | struct symbol *sym = sym_entry__symbol(syme); | 193 | struct symbol *sym = he->ms.sym; |
191 | symbol__annotate_zero_histograms(sym); | 194 | symbol__annotate_zero_histograms(sym); |
192 | } | 195 | } |
193 | 196 | ||
194 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | 197 | static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) |
195 | { | 198 | { |
196 | struct annotation *notes; | 199 | struct annotation *notes; |
197 | struct symbol *sym; | 200 | struct symbol *sym; |
198 | 201 | ||
199 | if (syme != top.sym_filter_entry) | 202 | if (he == NULL || he->ms.sym == NULL || |
203 | ((top.sym_filter_entry == NULL || | ||
204 | top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | ||
200 | return; | 205 | return; |
201 | 206 | ||
202 | sym = sym_entry__symbol(syme); | 207 | sym = he->ms.sym; |
203 | notes = symbol__annotation(sym); | 208 | notes = symbol__annotation(sym); |
204 | 209 | ||
205 | if (pthread_mutex_trylock(¬es->lock)) | 210 | if (pthread_mutex_trylock(¬es->lock)) |
206 | return; | 211 | return; |
207 | 212 | ||
208 | ip = syme->map->map_ip(syme->map, ip); | 213 | if (notes->src == NULL && |
209 | symbol__inc_addr_samples(sym, syme->map, counter, ip); | 214 | symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { |
215 | pthread_mutex_unlock(¬es->lock); | ||
216 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
217 | sym->name); | ||
218 | sleep(1); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | ip = he->ms.map->map_ip(he->ms.map, ip); | ||
223 | symbol__inc_addr_samples(sym, he->ms.map, counter, ip); | ||
210 | 224 | ||
211 | pthread_mutex_unlock(¬es->lock); | 225 | pthread_mutex_unlock(¬es->lock); |
212 | } | 226 | } |
213 | 227 | ||
214 | static void show_details(struct sym_entry *syme) | 228 | static void show_details(struct hist_entry *he) |
215 | { | 229 | { |
216 | struct annotation *notes; | 230 | struct annotation *notes; |
217 | struct symbol *symbol; | 231 | struct symbol *symbol; |
218 | int more; | 232 | int more; |
219 | 233 | ||
220 | if (!syme) | 234 | if (!he) |
221 | return; | 235 | return; |
222 | 236 | ||
223 | symbol = sym_entry__symbol(syme); | 237 | symbol = he->ms.sym; |
224 | notes = symbol__annotation(symbol); | 238 | notes = symbol__annotation(symbol); |
225 | 239 | ||
226 | pthread_mutex_lock(¬es->lock); | 240 | pthread_mutex_lock(¬es->lock); |
@@ -231,7 +245,7 @@ static void show_details(struct sym_entry *syme) | |||
231 | printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); | 245 | printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); |
232 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | 246 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); |
233 | 247 | ||
234 | more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, | 248 | more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, |
235 | 0, sym_pcnt_filter, top.print_entries, 4); | 249 | 0, sym_pcnt_filter, top.print_entries, 4); |
236 | if (top.zero) | 250 | if (top.zero) |
237 | symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); | 251 | symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); |
@@ -245,21 +259,28 @@ out_unlock: | |||
245 | 259 | ||
246 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 260 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
247 | 261 | ||
248 | static void __list_insert_active_sym(struct sym_entry *syme) | 262 | static struct hist_entry * |
263 | perf_session__add_hist_entry(struct perf_session *session, | ||
264 | struct addr_location *al, | ||
265 | struct perf_sample *sample, | ||
266 | struct perf_evsel *evsel) | ||
249 | { | 267 | { |
250 | list_add(&syme->node, &top.active_symbols); | 268 | struct hist_entry *he; |
269 | |||
270 | he = __hists__add_entry(&evsel->hists, al, NULL, sample->period); | ||
271 | if (he == NULL) | ||
272 | return NULL; | ||
273 | |||
274 | session->hists.stats.total_period += sample->period; | ||
275 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | ||
276 | return he; | ||
251 | } | 277 | } |
252 | 278 | ||
253 | static void print_sym_table(struct perf_session *session) | 279 | static void print_sym_table(void) |
254 | { | 280 | { |
255 | char bf[160]; | 281 | char bf[160]; |
256 | int printed = 0; | 282 | int printed = 0; |
257 | struct rb_node *nd; | ||
258 | struct sym_entry *syme; | ||
259 | struct rb_root tmp = RB_ROOT; | ||
260 | const int win_width = winsize.ws_col - 1; | 283 | const int win_width = winsize.ws_col - 1; |
261 | int sym_width, dso_width, dso_short_width; | ||
262 | float sum_ksamples = perf_top__decay_samples(&top, &tmp); | ||
263 | 284 | ||
264 | puts(CONSOLE_CLEAR); | 285 | puts(CONSOLE_CLEAR); |
265 | 286 | ||
@@ -270,10 +291,14 @@ static void print_sym_table(struct perf_session *session) | |||
270 | 291 | ||
271 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 292 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
272 | 293 | ||
273 | if (session->hists.stats.total_lost != 0) { | 294 | if (top.sym_evsel->hists.stats.nr_lost_warned != |
274 | color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); | 295 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { |
275 | printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", | 296 | top.sym_evsel->hists.stats.nr_lost_warned = |
276 | session->hists.stats.total_lost); | 297 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; |
298 | color_fprintf(stdout, PERF_COLOR_RED, | ||
299 | "WARNING: LOST %d chunks, Check IO/CPU overload", | ||
300 | top.sym_evsel->hists.stats.nr_lost_warned); | ||
301 | ++printed; | ||
277 | } | 302 | } |
278 | 303 | ||
279 | if (top.sym_filter_entry) { | 304 | if (top.sym_filter_entry) { |
@@ -281,58 +306,15 @@ static void print_sym_table(struct perf_session *session) | |||
281 | return; | 306 | return; |
282 | } | 307 | } |
283 | 308 | ||
284 | perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, | 309 | hists__collapse_resort_threaded(&top.sym_evsel->hists); |
285 | &sym_width); | 310 | hists__output_resort_threaded(&top.sym_evsel->hists); |
286 | 311 | hists__decay_entries_threaded(&top.sym_evsel->hists, | |
287 | if (sym_width + dso_width > winsize.ws_col - 29) { | 312 | top.hide_user_symbols, |
288 | dso_width = dso_short_width; | 313 | top.hide_kernel_symbols); |
289 | if (sym_width + dso_width > winsize.ws_col - 29) | 314 | hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); |
290 | sym_width = winsize.ws_col - dso_width - 29; | ||
291 | } | ||
292 | putchar('\n'); | 315 | putchar('\n'); |
293 | if (top.evlist->nr_entries == 1) | 316 | hists__fprintf(&top.sym_evsel->hists, NULL, false, false, |
294 | printf(" samples pcnt"); | 317 | winsize.ws_row - 4 - printed, win_width, stdout); |
295 | else | ||
296 | printf(" weight samples pcnt"); | ||
297 | |||
298 | if (verbose) | ||
299 | printf(" RIP "); | ||
300 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); | ||
301 | printf(" %s _______ _____", | ||
302 | top.evlist->nr_entries == 1 ? " " : "______"); | ||
303 | if (verbose) | ||
304 | printf(" ________________"); | ||
305 | printf(" %-*.*s", sym_width, sym_width, graph_line); | ||
306 | printf(" %-*.*s", dso_width, dso_width, graph_line); | ||
307 | puts("\n"); | ||
308 | |||
309 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | ||
310 | struct symbol *sym; | ||
311 | double pcnt; | ||
312 | |||
313 | syme = rb_entry(nd, struct sym_entry, rb_node); | ||
314 | sym = sym_entry__symbol(syme); | ||
315 | if (++printed > top.print_entries || | ||
316 | (int)syme->snap_count < top.count_filter) | ||
317 | continue; | ||
318 | |||
319 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / | ||
320 | sum_ksamples)); | ||
321 | |||
322 | if (top.evlist->nr_entries == 1 || !top.display_weighted) | ||
323 | printf("%20.2f ", syme->weight); | ||
324 | else | ||
325 | printf("%9.1f %10ld ", syme->weight, syme->snap_count); | ||
326 | |||
327 | percent_color_fprintf(stdout, "%4.1f%%", pcnt); | ||
328 | if (verbose) | ||
329 | printf(" %016" PRIx64, sym->start); | ||
330 | printf(" %-*.*s", sym_width, sym_width, sym->name); | ||
331 | printf(" %-*.*s\n", dso_width, dso_width, | ||
332 | dso_width >= syme->map->dso->long_name_len ? | ||
333 | syme->map->dso->long_name : | ||
334 | syme->map->dso->short_name); | ||
335 | } | ||
336 | } | 318 | } |
337 | 319 | ||
338 | static void prompt_integer(int *target, const char *msg) | 320 | static void prompt_integer(int *target, const char *msg) |
@@ -370,10 +352,11 @@ static void prompt_percent(int *target, const char *msg) | |||
370 | *target = tmp; | 352 | *target = tmp; |
371 | } | 353 | } |
372 | 354 | ||
373 | static void prompt_symbol(struct sym_entry **target, const char *msg) | 355 | static void prompt_symbol(struct hist_entry **target, const char *msg) |
374 | { | 356 | { |
375 | char *buf = malloc(0), *p; | 357 | char *buf = malloc(0), *p; |
376 | struct sym_entry *syme = *target, *n, *found = NULL; | 358 | struct hist_entry *syme = *target, *n, *found = NULL; |
359 | struct rb_node *next; | ||
377 | size_t dummy = 0; | 360 | size_t dummy = 0; |
378 | 361 | ||
379 | /* zero counters of active symbol */ | 362 | /* zero counters of active symbol */ |
@@ -390,17 +373,14 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) | |||
390 | if (p) | 373 | if (p) |
391 | *p = 0; | 374 | *p = 0; |
392 | 375 | ||
393 | pthread_mutex_lock(&top.active_symbols_lock); | 376 | next = rb_first(&top.sym_evsel->hists.entries); |
394 | syme = list_entry(top.active_symbols.next, struct sym_entry, node); | 377 | while (next) { |
395 | pthread_mutex_unlock(&top.active_symbols_lock); | 378 | n = rb_entry(next, struct hist_entry, rb_node); |
396 | 379 | if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { | |
397 | list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { | 380 | found = n; |
398 | struct symbol *sym = sym_entry__symbol(syme); | ||
399 | |||
400 | if (!strcmp(buf, sym->name)) { | ||
401 | found = syme; | ||
402 | break; | 381 | break; |
403 | } | 382 | } |
383 | next = rb_next(&n->rb_node); | ||
404 | } | 384 | } |
405 | 385 | ||
406 | if (!found) { | 386 | if (!found) { |
@@ -419,7 +399,7 @@ static void print_mapped_keys(void) | |||
419 | char *name = NULL; | 399 | char *name = NULL; |
420 | 400 | ||
421 | if (top.sym_filter_entry) { | 401 | if (top.sym_filter_entry) { |
422 | struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); | 402 | struct symbol *sym = top.sym_filter_entry->ms.sym; |
423 | name = sym->name; | 403 | name = sym->name; |
424 | } | 404 | } |
425 | 405 | ||
@@ -436,9 +416,6 @@ static void print_mapped_keys(void) | |||
436 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 416 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
437 | fprintf(stdout, "\t[S] stop annotation.\n"); | 417 | fprintf(stdout, "\t[S] stop annotation.\n"); |
438 | 418 | ||
439 | if (top.evlist->nr_entries > 1) | ||
440 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0); | ||
441 | |||
442 | fprintf(stdout, | 419 | fprintf(stdout, |
443 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", | 420 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", |
444 | top.hide_kernel_symbols ? "yes" : "no"); | 421 | top.hide_kernel_symbols ? "yes" : "no"); |
@@ -465,7 +442,6 @@ static int key_mapped(int c) | |||
465 | case 'S': | 442 | case 'S': |
466 | return 1; | 443 | return 1; |
467 | case 'E': | 444 | case 'E': |
468 | case 'w': | ||
469 | return top.evlist->nr_entries > 1 ? 1 : 0; | 445 | return top.evlist->nr_entries > 1 ? 1 : 0; |
470 | default: | 446 | default: |
471 | break; | 447 | break; |
@@ -474,7 +450,7 @@ static int key_mapped(int c) | |||
474 | return 0; | 450 | return 0; |
475 | } | 451 | } |
476 | 452 | ||
477 | static void handle_keypress(struct perf_session *session, int c) | 453 | static void handle_keypress(int c) |
478 | { | 454 | { |
479 | if (!key_mapped(c)) { | 455 | if (!key_mapped(c)) { |
480 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 456 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
@@ -550,7 +526,7 @@ static void handle_keypress(struct perf_session *session, int c) | |||
550 | case 'Q': | 526 | case 'Q': |
551 | printf("exiting.\n"); | 527 | printf("exiting.\n"); |
552 | if (dump_symtab) | 528 | if (dump_symtab) |
553 | perf_session__fprintf_dsos(session, stderr); | 529 | perf_session__fprintf_dsos(top.session, stderr); |
554 | exit(0); | 530 | exit(0); |
555 | case 's': | 531 | case 's': |
556 | prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); | 532 | prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); |
@@ -559,7 +535,7 @@ static void handle_keypress(struct perf_session *session, int c) | |||
559 | if (!top.sym_filter_entry) | 535 | if (!top.sym_filter_entry) |
560 | break; | 536 | break; |
561 | else { | 537 | else { |
562 | struct sym_entry *syme = top.sym_filter_entry; | 538 | struct hist_entry *syme = top.sym_filter_entry; |
563 | 539 | ||
564 | top.sym_filter_entry = NULL; | 540 | top.sym_filter_entry = NULL; |
565 | __zero_source_counters(syme); | 541 | __zero_source_counters(syme); |
@@ -568,9 +544,6 @@ static void handle_keypress(struct perf_session *session, int c) | |||
568 | case 'U': | 544 | case 'U': |
569 | top.hide_user_symbols = !top.hide_user_symbols; | 545 | top.hide_user_symbols = !top.hide_user_symbols; |
570 | break; | 546 | break; |
571 | case 'w': | ||
572 | top.display_weighted = ~top.display_weighted; | ||
573 | break; | ||
574 | case 'z': | 547 | case 'z': |
575 | top.zero = !top.zero; | 548 | top.zero = !top.zero; |
576 | break; | 549 | break; |
@@ -579,19 +552,30 @@ static void handle_keypress(struct perf_session *session, int c) | |||
579 | } | 552 | } |
580 | } | 553 | } |
581 | 554 | ||
555 | static void perf_top__sort_new_samples(void *arg) | ||
556 | { | ||
557 | struct perf_top *t = arg; | ||
558 | perf_top__reset_sample_counters(t); | ||
559 | |||
560 | if (t->evlist->selected != NULL) | ||
561 | t->sym_evsel = t->evlist->selected; | ||
562 | |||
563 | hists__collapse_resort_threaded(&t->sym_evsel->hists); | ||
564 | hists__output_resort_threaded(&t->sym_evsel->hists); | ||
565 | hists__decay_entries_threaded(&t->sym_evsel->hists, | ||
566 | top.hide_user_symbols, | ||
567 | top.hide_kernel_symbols); | ||
568 | } | ||
569 | |||
582 | static void *display_thread_tui(void *arg __used) | 570 | static void *display_thread_tui(void *arg __used) |
583 | { | 571 | { |
584 | int err = 0; | 572 | const char *help = "For a higher level overview, try: perf top --sort comm,dso"; |
585 | pthread_mutex_lock(&top.active_symbols_lock); | 573 | |
586 | while (list_empty(&top.active_symbols)) { | 574 | perf_top__sort_new_samples(&top); |
587 | err = pthread_cond_wait(&top.active_symbols_cond, | 575 | perf_evlist__tui_browse_hists(top.evlist, help, |
588 | &top.active_symbols_lock); | 576 | perf_top__sort_new_samples, |
589 | if (err) | 577 | &top, top.delay_secs); |
590 | break; | 578 | |
591 | } | ||
592 | pthread_mutex_unlock(&top.active_symbols_lock); | ||
593 | if (!err) | ||
594 | perf_top__tui_browser(&top); | ||
595 | exit_browser(0); | 579 | exit_browser(0); |
596 | exit(0); | 580 | exit(0); |
597 | return NULL; | 581 | return NULL; |
@@ -602,7 +586,6 @@ static void *display_thread(void *arg __used) | |||
602 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 586 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
603 | struct termios tc, save; | 587 | struct termios tc, save; |
604 | int delay_msecs, c; | 588 | int delay_msecs, c; |
605 | struct perf_session *session = (struct perf_session *) arg; | ||
606 | 589 | ||
607 | tcgetattr(0, &save); | 590 | tcgetattr(0, &save); |
608 | tc = save; | 591 | tc = save; |
@@ -610,20 +593,35 @@ static void *display_thread(void *arg __used) | |||
610 | tc.c_cc[VMIN] = 0; | 593 | tc.c_cc[VMIN] = 0; |
611 | tc.c_cc[VTIME] = 0; | 594 | tc.c_cc[VTIME] = 0; |
612 | 595 | ||
596 | pthread__unblock_sigwinch(); | ||
613 | repeat: | 597 | repeat: |
614 | delay_msecs = top.delay_secs * 1000; | 598 | delay_msecs = top.delay_secs * 1000; |
615 | tcsetattr(0, TCSANOW, &tc); | 599 | tcsetattr(0, TCSANOW, &tc); |
616 | /* trash return*/ | 600 | /* trash return*/ |
617 | getc(stdin); | 601 | getc(stdin); |
618 | 602 | ||
619 | do { | 603 | while (1) { |
620 | print_sym_table(session); | 604 | print_sym_table(); |
621 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); | 605 | /* |
622 | 606 | * Either timeout expired or we got an EINTR due to SIGWINCH, | |
607 | * refresh screen in both cases. | ||
608 | */ | ||
609 | switch (poll(&stdin_poll, 1, delay_msecs)) { | ||
610 | case 0: | ||
611 | continue; | ||
612 | case -1: | ||
613 | if (errno == EINTR) | ||
614 | continue; | ||
615 | /* Fall trhu */ | ||
616 | default: | ||
617 | goto process_hotkey; | ||
618 | } | ||
619 | } | ||
620 | process_hotkey: | ||
623 | c = getc(stdin); | 621 | c = getc(stdin); |
624 | tcsetattr(0, TCSAFLUSH, &save); | 622 | tcsetattr(0, TCSAFLUSH, &save); |
625 | 623 | ||
626 | handle_keypress(session, c); | 624 | handle_keypress(c); |
627 | goto repeat; | 625 | goto repeat; |
628 | 626 | ||
629 | return NULL; | 627 | return NULL; |
@@ -644,9 +642,8 @@ static const char *skip_symbols[] = { | |||
644 | NULL | 642 | NULL |
645 | }; | 643 | }; |
646 | 644 | ||
647 | static int symbol_filter(struct map *map, struct symbol *sym) | 645 | static int symbol_filter(struct map *map __used, struct symbol *sym) |
648 | { | 646 | { |
649 | struct sym_entry *syme; | ||
650 | const char *name = sym->name; | 647 | const char *name = sym->name; |
651 | int i; | 648 | int i; |
652 | 649 | ||
@@ -666,16 +663,6 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
666 | strstr(name, "_text_end")) | 663 | strstr(name, "_text_end")) |
667 | return 1; | 664 | return 1; |
668 | 665 | ||
669 | syme = symbol__priv(sym); | ||
670 | syme->map = map; | ||
671 | symbol__annotate_init(map, sym); | ||
672 | |||
673 | if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { | ||
674 | /* schedule initial sym_filter_entry setup */ | ||
675 | sym_filter_entry_sched = syme; | ||
676 | sym_filter = NULL; | ||
677 | } | ||
678 | |||
679 | for (i = 0; skip_symbols[i]; i++) { | 666 | for (i = 0; skip_symbols[i]; i++) { |
680 | if (!strcmp(skip_symbols[i], name)) { | 667 | if (!strcmp(skip_symbols[i], name)) { |
681 | sym->ignore = true; | 668 | sym->ignore = true; |
@@ -687,13 +674,15 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
687 | } | 674 | } |
688 | 675 | ||
689 | static void perf_event__process_sample(const union perf_event *event, | 676 | static void perf_event__process_sample(const union perf_event *event, |
677 | struct perf_evsel *evsel, | ||
690 | struct perf_sample *sample, | 678 | struct perf_sample *sample, |
691 | struct perf_session *session) | 679 | struct perf_session *session) |
692 | { | 680 | { |
681 | struct symbol *parent = NULL; | ||
693 | u64 ip = event->ip.ip; | 682 | u64 ip = event->ip.ip; |
694 | struct sym_entry *syme; | ||
695 | struct addr_location al; | 683 | struct addr_location al; |
696 | struct machine *machine; | 684 | struct machine *machine; |
685 | int err; | ||
697 | u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 686 | u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
698 | 687 | ||
699 | ++top.samples; | 688 | ++top.samples; |
@@ -782,51 +771,43 @@ static void perf_event__process_sample(const union perf_event *event, | |||
782 | sleep(5); | 771 | sleep(5); |
783 | vmlinux_warned = true; | 772 | vmlinux_warned = true; |
784 | } | 773 | } |
785 | |||
786 | return; | ||
787 | } | 774 | } |
788 | 775 | ||
789 | /* let's see, whether we need to install initial sym_filter_entry */ | 776 | if (al.sym == NULL || !al.sym->ignore) { |
790 | if (sym_filter_entry_sched) { | 777 | struct hist_entry *he; |
791 | top.sym_filter_entry = sym_filter_entry_sched; | 778 | |
792 | sym_filter_entry_sched = NULL; | 779 | if ((sort__has_parent || symbol_conf.use_callchain) && |
793 | if (parse_source(top.sym_filter_entry) < 0) { | 780 | sample->callchain) { |
794 | struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); | 781 | err = perf_session__resolve_callchain(session, al.thread, |
795 | 782 | sample->callchain, &parent); | |
796 | pr_err("Can't annotate %s", sym->name); | 783 | if (err) |
797 | if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) { | 784 | return; |
798 | pr_err(": No vmlinux file was found in the path:\n"); | ||
799 | machine__fprintf_vmlinux_path(machine, stderr); | ||
800 | } else | ||
801 | pr_err(".\n"); | ||
802 | exit(1); | ||
803 | } | 785 | } |
804 | } | ||
805 | 786 | ||
806 | syme = symbol__priv(al.sym); | 787 | he = perf_session__add_hist_entry(session, &al, sample, evsel); |
807 | if (!al.sym->ignore) { | 788 | if (he == NULL) { |
808 | struct perf_evsel *evsel; | 789 | pr_err("Problem incrementing symbol period, skipping event\n"); |
790 | return; | ||
791 | } | ||
809 | 792 | ||
810 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | 793 | if (symbol_conf.use_callchain) { |
811 | assert(evsel != NULL); | 794 | err = callchain_append(he->callchain, &session->callchain_cursor, |
812 | syme->count[evsel->idx]++; | 795 | sample->period); |
813 | record_precise_ip(syme, evsel->idx, ip); | 796 | if (err) |
814 | pthread_mutex_lock(&top.active_symbols_lock); | 797 | return; |
815 | if (list_empty(&syme->node) || !syme->node.next) { | ||
816 | static bool first = true; | ||
817 | __list_insert_active_sym(syme); | ||
818 | if (first) { | ||
819 | pthread_cond_broadcast(&top.active_symbols_cond); | ||
820 | first = false; | ||
821 | } | ||
822 | } | 798 | } |
823 | pthread_mutex_unlock(&top.active_symbols_lock); | 799 | |
800 | if (sort_has_symbols) | ||
801 | record_precise_ip(he, evsel->idx, ip); | ||
824 | } | 802 | } |
803 | |||
804 | return; | ||
825 | } | 805 | } |
826 | 806 | ||
827 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | 807 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) |
828 | { | 808 | { |
829 | struct perf_sample sample; | 809 | struct perf_sample sample; |
810 | struct perf_evsel *evsel; | ||
830 | union perf_event *event; | 811 | union perf_event *event; |
831 | int ret; | 812 | int ret; |
832 | 813 | ||
@@ -837,10 +818,16 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | |||
837 | continue; | 818 | continue; |
838 | } | 819 | } |
839 | 820 | ||
821 | evsel = perf_evlist__id2evsel(self->evlist, sample.id); | ||
822 | assert(evsel != NULL); | ||
823 | |||
840 | if (event->header.type == PERF_RECORD_SAMPLE) | 824 | if (event->header.type == PERF_RECORD_SAMPLE) |
841 | perf_event__process_sample(event, &sample, self); | 825 | perf_event__process_sample(event, evsel, &sample, self); |
842 | else | 826 | else if (event->header.type < PERF_RECORD_MAX) { |
827 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
843 | perf_event__process(event, &sample, self); | 828 | perf_event__process(event, &sample, self); |
829 | } else | ||
830 | ++self->hists.stats.nr_unknown_events; | ||
844 | } | 831 | } |
845 | } | 832 | } |
846 | 833 | ||
@@ -854,10 +841,16 @@ static void perf_session__mmap_read(struct perf_session *self) | |||
854 | 841 | ||
855 | static void start_counters(struct perf_evlist *evlist) | 842 | static void start_counters(struct perf_evlist *evlist) |
856 | { | 843 | { |
857 | struct perf_evsel *counter; | 844 | struct perf_evsel *counter, *first; |
845 | |||
846 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
858 | 847 | ||
859 | list_for_each_entry(counter, &evlist->entries, node) { | 848 | list_for_each_entry(counter, &evlist->entries, node) { |
860 | struct perf_event_attr *attr = &counter->attr; | 849 | struct perf_event_attr *attr = &counter->attr; |
850 | struct xyarray *group_fd = NULL; | ||
851 | |||
852 | if (group && counter != first) | ||
853 | group_fd = first->fd; | ||
861 | 854 | ||
862 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 855 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
863 | 856 | ||
@@ -872,16 +865,29 @@ static void start_counters(struct perf_evlist *evlist) | |||
872 | attr->read_format |= PERF_FORMAT_ID; | 865 | attr->read_format |= PERF_FORMAT_ID; |
873 | } | 866 | } |
874 | 867 | ||
868 | if (symbol_conf.use_callchain) | ||
869 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | ||
870 | |||
875 | attr->mmap = 1; | 871 | attr->mmap = 1; |
872 | attr->comm = 1; | ||
876 | attr->inherit = inherit; | 873 | attr->inherit = inherit; |
874 | retry_sample_id: | ||
875 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | ||
877 | try_again: | 876 | try_again: |
878 | if (perf_evsel__open(counter, top.evlist->cpus, | 877 | if (perf_evsel__open(counter, top.evlist->cpus, |
879 | top.evlist->threads, group) < 0) { | 878 | top.evlist->threads, group, |
879 | group_fd) < 0) { | ||
880 | int err = errno; | 880 | int err = errno; |
881 | 881 | ||
882 | if (err == EPERM || err == EACCES) { | 882 | if (err == EPERM || err == EACCES) { |
883 | ui__warning_paranoid(); | 883 | ui__error_paranoid(); |
884 | goto out_err; | 884 | goto out_err; |
885 | } else if (err == EINVAL && sample_id_all_avail) { | ||
886 | /* | ||
887 | * Old kernel, no attr->sample_id_type_all field | ||
888 | */ | ||
889 | sample_id_all_avail = false; | ||
890 | goto retry_sample_id; | ||
885 | } | 891 | } |
886 | /* | 892 | /* |
887 | * If it's cycles then fall back to hrtimer | 893 | * If it's cycles then fall back to hrtimer |
@@ -927,35 +933,56 @@ out_err: | |||
927 | exit(0); | 933 | exit(0); |
928 | } | 934 | } |
929 | 935 | ||
936 | static int setup_sample_type(void) | ||
937 | { | ||
938 | if (!sort_has_symbols) { | ||
939 | if (symbol_conf.use_callchain) { | ||
940 | ui__warning("Selected -g but \"sym\" not present in --sort/-s."); | ||
941 | return -EINVAL; | ||
942 | } | ||
943 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { | ||
944 | if (callchain_register_param(&callchain_param) < 0) { | ||
945 | ui__warning("Can't register callchain params.\n"); | ||
946 | return -EINVAL; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | return 0; | ||
951 | } | ||
952 | |||
930 | static int __cmd_top(void) | 953 | static int __cmd_top(void) |
931 | { | 954 | { |
932 | pthread_t thread; | 955 | pthread_t thread; |
933 | int ret __used; | 956 | int ret; |
934 | /* | 957 | /* |
935 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 958 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this |
936 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | 959 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. |
937 | */ | 960 | */ |
938 | struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); | 961 | top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); |
939 | if (session == NULL) | 962 | if (top.session == NULL) |
940 | return -ENOMEM; | 963 | return -ENOMEM; |
941 | 964 | ||
965 | ret = setup_sample_type(); | ||
966 | if (ret) | ||
967 | goto out_delete; | ||
968 | |||
942 | if (top.target_tid != -1) | 969 | if (top.target_tid != -1) |
943 | perf_event__synthesize_thread_map(top.evlist->threads, | 970 | perf_event__synthesize_thread_map(top.evlist->threads, |
944 | perf_event__process, session); | 971 | perf_event__process, top.session); |
945 | else | 972 | else |
946 | perf_event__synthesize_threads(perf_event__process, session); | 973 | perf_event__synthesize_threads(perf_event__process, top.session); |
947 | 974 | ||
948 | start_counters(top.evlist); | 975 | start_counters(top.evlist); |
949 | session->evlist = top.evlist; | 976 | top.session->evlist = top.evlist; |
950 | perf_session__update_sample_type(session); | 977 | perf_session__update_sample_type(top.session); |
951 | 978 | ||
952 | /* Wait for a minimal set of events before starting the snapshot */ | 979 | /* Wait for a minimal set of events before starting the snapshot */ |
953 | poll(top.evlist->pollfd, top.evlist->nr_fds, 100); | 980 | poll(top.evlist->pollfd, top.evlist->nr_fds, 100); |
954 | 981 | ||
955 | perf_session__mmap_read(session); | 982 | perf_session__mmap_read(top.session); |
956 | 983 | ||
957 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 984 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
958 | display_thread), session)) { | 985 | display_thread), NULL)) { |
959 | printf("Could not create display thread.\n"); | 986 | printf("Could not create display thread.\n"); |
960 | exit(-1); | 987 | exit(-1); |
961 | } | 988 | } |
@@ -973,12 +1000,96 @@ static int __cmd_top(void) | |||
973 | while (1) { | 1000 | while (1) { |
974 | u64 hits = top.samples; | 1001 | u64 hits = top.samples; |
975 | 1002 | ||
976 | perf_session__mmap_read(session); | 1003 | perf_session__mmap_read(top.session); |
977 | 1004 | ||
978 | if (hits == top.samples) | 1005 | if (hits == top.samples) |
979 | ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); | 1006 | ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); |
980 | } | 1007 | } |
981 | 1008 | ||
1009 | out_delete: | ||
1010 | perf_session__delete(top.session); | ||
1011 | top.session = NULL; | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | static int | ||
1017 | parse_callchain_opt(const struct option *opt __used, const char *arg, | ||
1018 | int unset) | ||
1019 | { | ||
1020 | char *tok, *tok2; | ||
1021 | char *endptr; | ||
1022 | |||
1023 | /* | ||
1024 | * --no-call-graph | ||
1025 | */ | ||
1026 | if (unset) { | ||
1027 | dont_use_callchains = true; | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | symbol_conf.use_callchain = true; | ||
1032 | |||
1033 | if (!arg) | ||
1034 | return 0; | ||
1035 | |||
1036 | tok = strtok((char *)arg, ","); | ||
1037 | if (!tok) | ||
1038 | return -1; | ||
1039 | |||
1040 | /* get the output mode */ | ||
1041 | if (!strncmp(tok, "graph", strlen(arg))) | ||
1042 | callchain_param.mode = CHAIN_GRAPH_ABS; | ||
1043 | |||
1044 | else if (!strncmp(tok, "flat", strlen(arg))) | ||
1045 | callchain_param.mode = CHAIN_FLAT; | ||
1046 | |||
1047 | else if (!strncmp(tok, "fractal", strlen(arg))) | ||
1048 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
1049 | |||
1050 | else if (!strncmp(tok, "none", strlen(arg))) { | ||
1051 | callchain_param.mode = CHAIN_NONE; | ||
1052 | symbol_conf.use_callchain = false; | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | else | ||
1058 | return -1; | ||
1059 | |||
1060 | /* get the min percentage */ | ||
1061 | tok = strtok(NULL, ","); | ||
1062 | if (!tok) | ||
1063 | goto setup; | ||
1064 | |||
1065 | callchain_param.min_percent = strtod(tok, &endptr); | ||
1066 | if (tok == endptr) | ||
1067 | return -1; | ||
1068 | |||
1069 | /* get the print limit */ | ||
1070 | tok2 = strtok(NULL, ","); | ||
1071 | if (!tok2) | ||
1072 | goto setup; | ||
1073 | |||
1074 | if (tok2[0] != 'c') { | ||
1075 | callchain_param.print_limit = strtod(tok2, &endptr); | ||
1076 | tok2 = strtok(NULL, ","); | ||
1077 | if (!tok2) | ||
1078 | goto setup; | ||
1079 | } | ||
1080 | |||
1081 | /* get the call chain order */ | ||
1082 | if (!strcmp(tok2, "caller")) | ||
1083 | callchain_param.order = ORDER_CALLER; | ||
1084 | else if (!strcmp(tok2, "callee")) | ||
1085 | callchain_param.order = ORDER_CALLEE; | ||
1086 | else | ||
1087 | return -1; | ||
1088 | setup: | ||
1089 | if (callchain_register_param(&callchain_param) < 0) { | ||
1090 | fprintf(stderr, "Can't register callchain params\n"); | ||
1091 | return -1; | ||
1092 | } | ||
982 | return 0; | 1093 | return 0; |
983 | } | 1094 | } |
984 | 1095 | ||
@@ -1018,7 +1129,7 @@ static const struct option options[] = { | |||
1018 | "put the counters into a counter group"), | 1129 | "put the counters into a counter group"), |
1019 | OPT_BOOLEAN('i', "inherit", &inherit, | 1130 | OPT_BOOLEAN('i', "inherit", &inherit, |
1020 | "child tasks inherit counters"), | 1131 | "child tasks inherit counters"), |
1021 | OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", | 1132 | OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", |
1022 | "symbol to annotate"), | 1133 | "symbol to annotate"), |
1023 | OPT_BOOLEAN('z', "zero", &top.zero, | 1134 | OPT_BOOLEAN('z', "zero", &top.zero, |
1024 | "zero history across updates"), | 1135 | "zero history across updates"), |
@@ -1032,6 +1143,28 @@ static const struct option options[] = { | |||
1032 | OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), | 1143 | OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), |
1033 | OPT_INCR('v', "verbose", &verbose, | 1144 | OPT_INCR('v', "verbose", &verbose, |
1034 | "be more verbose (show counter open errors, etc)"), | 1145 | "be more verbose (show counter open errors, etc)"), |
1146 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | ||
1147 | "sort by key(s): pid, comm, dso, symbol, parent"), | ||
1148 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | ||
1149 | "Show a column with the number of samples"), | ||
1150 | OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", | ||
1151 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " | ||
1152 | "Default: fractal,0.5,callee", &parse_callchain_opt, | ||
1153 | callchain_default_opt), | ||
1154 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | ||
1155 | "Show a column with the sum of periods"), | ||
1156 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | ||
1157 | "only consider symbols in these dsos"), | ||
1158 | OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | ||
1159 | "only consider symbols in these comms"), | ||
1160 | OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | ||
1161 | "only consider these symbols"), | ||
1162 | OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, | ||
1163 | "Interleave source code with assembly code (default)"), | ||
1164 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | ||
1165 | "Display raw encoding of assembly instructions (default)"), | ||
1166 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | ||
1167 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | ||
1035 | OPT_END() | 1168 | OPT_END() |
1036 | }; | 1169 | }; |
1037 | 1170 | ||
@@ -1044,18 +1177,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1044 | if (top.evlist == NULL) | 1177 | if (top.evlist == NULL) |
1045 | return -ENOMEM; | 1178 | return -ENOMEM; |
1046 | 1179 | ||
1047 | page_size = sysconf(_SC_PAGE_SIZE); | 1180 | symbol_conf.exclude_other = false; |
1048 | 1181 | ||
1049 | argc = parse_options(argc, argv, options, top_usage, 0); | 1182 | argc = parse_options(argc, argv, options, top_usage, 0); |
1050 | if (argc) | 1183 | if (argc) |
1051 | usage_with_options(top_usage, options); | 1184 | usage_with_options(top_usage, options); |
1052 | 1185 | ||
1053 | /* | 1186 | if (sort_order == default_sort_order) |
1054 | * XXX For now start disabled, only using TUI if explicitely asked for. | 1187 | sort_order = "dso,symbol"; |
1055 | * Change that when handle_keys equivalent gets written, live annotation | 1188 | |
1056 | * done, etc. | 1189 | setup_sorting(top_usage, options); |
1057 | */ | ||
1058 | use_browser = 0; | ||
1059 | 1190 | ||
1060 | if (use_stdio) | 1191 | if (use_stdio) |
1061 | use_browser = 0; | 1192 | use_browser = 0; |
@@ -1118,13 +1249,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1118 | 1249 | ||
1119 | top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); | 1250 | top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); |
1120 | 1251 | ||
1121 | symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + | 1252 | symbol_conf.priv_size = sizeof(struct annotation); |
1122 | (top.evlist->nr_entries + 1) * sizeof(unsigned long)); | ||
1123 | 1253 | ||
1124 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1254 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1125 | if (symbol__init() < 0) | 1255 | if (symbol__init() < 0) |
1126 | return -1; | 1256 | return -1; |
1127 | 1257 | ||
1258 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); | ||
1259 | sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); | ||
1260 | sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); | ||
1261 | |||
1262 | /* | ||
1263 | * Avoid annotation data structures overhead when symbols aren't on the | ||
1264 | * sort list. | ||
1265 | */ | ||
1266 | sort_has_symbols = sort_sym.list.next != NULL; | ||
1267 | |||
1128 | get_term_dimensions(&winsize); | 1268 | get_term_dimensions(&winsize); |
1129 | if (top.print_entries == 0) { | 1269 | if (top.print_entries == 0) { |
1130 | update_print_entries(&winsize); | 1270 | update_print_entries(&winsize); |
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 4702e2443a8e..b382bd551aac 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
@@ -4,7 +4,6 @@ | |||
4 | #include "util/util.h" | 4 | #include "util/util.h" |
5 | #include "util/strbuf.h" | 5 | #include "util/strbuf.h" |
6 | 6 | ||
7 | extern const char perf_version_string[]; | ||
8 | extern const char perf_usage_string[]; | 7 | extern const char perf_usage_string[]; |
9 | extern const char perf_more_info_string[]; | 8 | extern const char perf_more_info_string[]; |
10 | 9 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index ec635b7cc8ea..73d0cac8b67e 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void) | |||
427 | debugfs_mntpt[0] = '\0'; | 427 | debugfs_mntpt[0] = '\0'; |
428 | } | 428 | } |
429 | 429 | ||
430 | static void pthread__block_sigwinch(void) | ||
431 | { | ||
432 | sigset_t set; | ||
433 | |||
434 | sigemptyset(&set); | ||
435 | sigaddset(&set, SIGWINCH); | ||
436 | pthread_sigmask(SIG_BLOCK, &set, NULL); | ||
437 | } | ||
438 | |||
439 | void pthread__unblock_sigwinch(void) | ||
440 | { | ||
441 | sigset_t set; | ||
442 | |||
443 | sigemptyset(&set); | ||
444 | sigaddset(&set, SIGWINCH); | ||
445 | pthread_sigmask(SIG_UNBLOCK, &set, NULL); | ||
446 | } | ||
447 | |||
430 | int main(int argc, const char **argv) | 448 | int main(int argc, const char **argv) |
431 | { | 449 | { |
432 | const char *cmd; | 450 | const char *cmd; |
@@ -480,6 +498,12 @@ int main(int argc, const char **argv) | |||
480 | * time. | 498 | * time. |
481 | */ | 499 | */ |
482 | setup_path(); | 500 | setup_path(); |
501 | /* | ||
502 | * Block SIGWINCH notifications so that the thread that wants it can | ||
503 | * unblock and get syscalls like select interrupted instead of waiting | ||
504 | * forever while the signal goes to some other non interested thread. | ||
505 | */ | ||
506 | pthread__block_sigwinch(); | ||
483 | 507 | ||
484 | while (1) { | 508 | while (1) { |
485 | static int done_help; | 509 | static int done_help; |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index a5fc660c1f12..914c895510f7 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -9,18 +9,21 @@ void get_term_dimensions(struct winsize *ws); | |||
9 | #include "../../arch/x86/include/asm/unistd.h" | 9 | #include "../../arch/x86/include/asm/unistd.h" |
10 | #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") | 10 | #define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") |
11 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | 11 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); |
12 | #define CPUINFO_PROC "model name" | ||
12 | #endif | 13 | #endif |
13 | 14 | ||
14 | #if defined(__x86_64__) | 15 | #if defined(__x86_64__) |
15 | #include "../../arch/x86/include/asm/unistd.h" | 16 | #include "../../arch/x86/include/asm/unistd.h" |
16 | #define rmb() asm volatile("lfence" ::: "memory") | 17 | #define rmb() asm volatile("lfence" ::: "memory") |
17 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); | 18 | #define cpu_relax() asm volatile("rep; nop" ::: "memory"); |
19 | #define CPUINFO_PROC "model name" | ||
18 | #endif | 20 | #endif |
19 | 21 | ||
20 | #ifdef __powerpc__ | 22 | #ifdef __powerpc__ |
21 | #include "../../arch/powerpc/include/asm/unistd.h" | 23 | #include "../../arch/powerpc/include/asm/unistd.h" |
22 | #define rmb() asm volatile ("sync" ::: "memory") | 24 | #define rmb() asm volatile ("sync" ::: "memory") |
23 | #define cpu_relax() asm volatile ("" ::: "memory"); | 25 | #define cpu_relax() asm volatile ("" ::: "memory"); |
26 | #define CPUINFO_PROC "cpu" | ||
24 | #endif | 27 | #endif |
25 | 28 | ||
26 | #ifdef __s390__ | 29 | #ifdef __s390__ |
@@ -37,30 +40,35 @@ void get_term_dimensions(struct winsize *ws); | |||
37 | # define rmb() asm volatile("" ::: "memory") | 40 | # define rmb() asm volatile("" ::: "memory") |
38 | #endif | 41 | #endif |
39 | #define cpu_relax() asm volatile("" ::: "memory") | 42 | #define cpu_relax() asm volatile("" ::: "memory") |
43 | #define CPUINFO_PROC "cpu type" | ||
40 | #endif | 44 | #endif |
41 | 45 | ||
42 | #ifdef __hppa__ | 46 | #ifdef __hppa__ |
43 | #include "../../arch/parisc/include/asm/unistd.h" | 47 | #include "../../arch/parisc/include/asm/unistd.h" |
44 | #define rmb() asm volatile("" ::: "memory") | 48 | #define rmb() asm volatile("" ::: "memory") |
45 | #define cpu_relax() asm volatile("" ::: "memory"); | 49 | #define cpu_relax() asm volatile("" ::: "memory"); |
50 | #define CPUINFO_PROC "cpu" | ||
46 | #endif | 51 | #endif |
47 | 52 | ||
48 | #ifdef __sparc__ | 53 | #ifdef __sparc__ |
49 | #include "../../arch/sparc/include/asm/unistd.h" | 54 | #include "../../arch/sparc/include/asm/unistd.h" |
50 | #define rmb() asm volatile("":::"memory") | 55 | #define rmb() asm volatile("":::"memory") |
51 | #define cpu_relax() asm volatile("":::"memory") | 56 | #define cpu_relax() asm volatile("":::"memory") |
57 | #define CPUINFO_PROC "cpu" | ||
52 | #endif | 58 | #endif |
53 | 59 | ||
54 | #ifdef __alpha__ | 60 | #ifdef __alpha__ |
55 | #include "../../arch/alpha/include/asm/unistd.h" | 61 | #include "../../arch/alpha/include/asm/unistd.h" |
56 | #define rmb() asm volatile("mb" ::: "memory") | 62 | #define rmb() asm volatile("mb" ::: "memory") |
57 | #define cpu_relax() asm volatile("" ::: "memory") | 63 | #define cpu_relax() asm volatile("" ::: "memory") |
64 | #define CPUINFO_PROC "cpu model" | ||
58 | #endif | 65 | #endif |
59 | 66 | ||
60 | #ifdef __ia64__ | 67 | #ifdef __ia64__ |
61 | #include "../../arch/ia64/include/asm/unistd.h" | 68 | #include "../../arch/ia64/include/asm/unistd.h" |
62 | #define rmb() asm volatile ("mf" ::: "memory") | 69 | #define rmb() asm volatile ("mf" ::: "memory") |
63 | #define cpu_relax() asm volatile ("hint @pause" ::: "memory") | 70 | #define cpu_relax() asm volatile ("hint @pause" ::: "memory") |
71 | #define CPUINFO_PROC "model name" | ||
64 | #endif | 72 | #endif |
65 | 73 | ||
66 | #ifdef __arm__ | 74 | #ifdef __arm__ |
@@ -71,6 +79,7 @@ void get_term_dimensions(struct winsize *ws); | |||
71 | */ | 79 | */ |
72 | #define rmb() ((void(*)(void))0xffff0fa0)() | 80 | #define rmb() ((void(*)(void))0xffff0fa0)() |
73 | #define cpu_relax() asm volatile("":::"memory") | 81 | #define cpu_relax() asm volatile("":::"memory") |
82 | #define CPUINFO_PROC "Processor" | ||
74 | #endif | 83 | #endif |
75 | 84 | ||
76 | #ifdef __mips__ | 85 | #ifdef __mips__ |
@@ -83,6 +92,7 @@ void get_term_dimensions(struct winsize *ws); | |||
83 | : /* no input */ \ | 92 | : /* no input */ \ |
84 | : "memory") | 93 | : "memory") |
85 | #define cpu_relax() asm volatile("" ::: "memory") | 94 | #define cpu_relax() asm volatile("" ::: "memory") |
95 | #define CPUINFO_PROC "cpu model" | ||
86 | #endif | 96 | #endif |
87 | 97 | ||
88 | #include <time.h> | 98 | #include <time.h> |
@@ -171,5 +181,8 @@ struct ip_callchain { | |||
171 | }; | 181 | }; |
172 | 182 | ||
173 | extern bool perf_host, perf_guest; | 183 | extern bool perf_host, perf_guest; |
184 | extern const char perf_version_string[]; | ||
185 | |||
186 | void pthread__unblock_sigwinch(void); | ||
174 | 187 | ||
175 | #endif | 188 | #endif |
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-record b/tools/perf/scripts/python/bin/net_dropmonitor-record new file mode 100755 index 000000000000..423fb81dadae --- /dev/null +++ b/tools/perf/scripts/python/bin/net_dropmonitor-record | |||
@@ -0,0 +1,2 @@ | |||
1 | #!/bin/bash | ||
2 | perf record -e skb:kfree_skb $@ | ||
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-report b/tools/perf/scripts/python/bin/net_dropmonitor-report new file mode 100755 index 000000000000..8d698f5a06aa --- /dev/null +++ b/tools/perf/scripts/python/bin/net_dropmonitor-report | |||
@@ -0,0 +1,4 @@ | |||
1 | #!/bin/bash | ||
2 | # description: display a table of dropped frames | ||
3 | |||
4 | perf script -s "$PERF_EXEC_PATH"/scripts/python/net_dropmonitor.py $@ | ||
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py new file mode 100755 index 000000000000..a4ffc9500023 --- /dev/null +++ b/tools/perf/scripts/python/net_dropmonitor.py | |||
@@ -0,0 +1,72 @@ | |||
1 | # Monitor the system for dropped packets and proudce a report of drop locations and counts | ||
2 | |||
3 | import os | ||
4 | import sys | ||
5 | |||
6 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
7 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
8 | |||
9 | from perf_trace_context import * | ||
10 | from Core import * | ||
11 | from Util import * | ||
12 | |||
13 | drop_log = {} | ||
14 | kallsyms = [] | ||
15 | |||
16 | def get_kallsyms_table(): | ||
17 | global kallsyms | ||
18 | try: | ||
19 | f = open("/proc/kallsyms", "r") | ||
20 | linecount = 0 | ||
21 | for line in f: | ||
22 | linecount = linecount+1 | ||
23 | f.seek(0) | ||
24 | except: | ||
25 | return | ||
26 | |||
27 | |||
28 | j = 0 | ||
29 | for line in f: | ||
30 | loc = int(line.split()[0], 16) | ||
31 | name = line.split()[2] | ||
32 | j = j +1 | ||
33 | if ((j % 100) == 0): | ||
34 | print "\r" + str(j) + "/" + str(linecount), | ||
35 | kallsyms.append({ 'loc': loc, 'name' : name}) | ||
36 | |||
37 | print "\r" + str(j) + "/" + str(linecount) | ||
38 | kallsyms.sort() | ||
39 | return | ||
40 | |||
41 | def get_sym(sloc): | ||
42 | loc = int(sloc) | ||
43 | for i in kallsyms: | ||
44 | if (i['loc'] >= loc): | ||
45 | return (i['name'], i['loc']-loc) | ||
46 | return (None, 0) | ||
47 | |||
48 | def print_drop_table(): | ||
49 | print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT") | ||
50 | for i in drop_log.keys(): | ||
51 | (sym, off) = get_sym(i) | ||
52 | if sym == None: | ||
53 | sym = i | ||
54 | print "%25s %25s %25s" % (sym, off, drop_log[i]) | ||
55 | |||
56 | |||
57 | def trace_begin(): | ||
58 | print "Starting trace (Ctrl-C to dump results)" | ||
59 | |||
60 | def trace_end(): | ||
61 | print "Gathering kallsyms data" | ||
62 | get_kallsyms_table() | ||
63 | print_drop_table() | ||
64 | |||
65 | # called from perf, when it finds a correspoinding event | ||
66 | def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, | ||
67 | skbaddr, protocol, location): | ||
68 | slocation = str(location) | ||
69 | try: | ||
70 | drop_log[slocation] = drop_log[slocation] + 1 | ||
71 | except: | ||
72 | drop_log[slocation] = 1 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e01af2b1a469..119e996035c8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include "annotate.h" | 16 | #include "annotate.h" |
17 | #include <pthread.h> | 17 | #include <pthread.h> |
18 | 18 | ||
19 | const char *disassembler_style; | ||
20 | |||
19 | int symbol__annotate_init(struct map *map __used, struct symbol *sym) | 21 | int symbol__annotate_init(struct map *map __used, struct symbol *sym) |
20 | { | 22 | { |
21 | struct annotation *notes = symbol__annotation(sym); | 23 | struct annotation *notes = symbol__annotation(sym); |
@@ -308,9 +310,12 @@ fallback: | |||
308 | } | 310 | } |
309 | err = -ENOENT; | 311 | err = -ENOENT; |
310 | dso->annotate_warned = 1; | 312 | dso->annotate_warned = 1; |
311 | pr_err("Can't annotate %s: No vmlinux file%s was found in the " | 313 | pr_err("Can't annotate %s:\n\n" |
312 | "path.\nPlease use 'perf buildid-cache -av vmlinux' or " | 314 | "No vmlinux file%s\nwas found in the path.\n\n" |
313 | "--vmlinux vmlinux.\n", | 315 | "Please use:\n\n" |
316 | " perf buildid-cache -av vmlinux\n\n" | ||
317 | "or:\n\n" | ||
318 | " --vmlinux vmlinux", | ||
314 | sym->name, build_id_msg ?: ""); | 319 | sym->name, build_id_msg ?: ""); |
315 | goto out_free_filename; | 320 | goto out_free_filename; |
316 | } | 321 | } |
@@ -323,10 +328,15 @@ fallback: | |||
323 | dso, dso->long_name, sym, sym->name); | 328 | dso, dso->long_name, sym, sym->name); |
324 | 329 | ||
325 | snprintf(command, sizeof(command), | 330 | snprintf(command, sizeof(command), |
326 | "objdump --start-address=0x%016" PRIx64 | 331 | "objdump %s%s --start-address=0x%016" PRIx64 |
327 | " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", | 332 | " --stop-address=0x%016" PRIx64 |
333 | " -d %s %s -C %s|grep -v %s|expand", | ||
334 | disassembler_style ? "-M " : "", | ||
335 | disassembler_style ? disassembler_style : "", | ||
328 | map__rip_2objdump(map, sym->start), | 336 | map__rip_2objdump(map, sym->start), |
329 | map__rip_2objdump(map, sym->end), | 337 | map__rip_2objdump(map, sym->end), |
338 | symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", | ||
339 | symbol_conf.annotate_src ? "-S" : "", | ||
330 | symfs_filename, filename); | 340 | symfs_filename, filename); |
331 | 341 | ||
332 | pr_debug("Executing: %s\n", command); | 342 | pr_debug("Executing: %s\n", command); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c2c286896801..d9072523d342 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -91,13 +91,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
91 | #ifdef NO_NEWT_SUPPORT | 91 | #ifdef NO_NEWT_SUPPORT |
92 | static inline int symbol__tui_annotate(struct symbol *sym __used, | 92 | static inline int symbol__tui_annotate(struct symbol *sym __used, |
93 | struct map *map __used, | 93 | struct map *map __used, |
94 | int evidx __used, int refresh __used) | 94 | int evidx __used, |
95 | void(*timer)(void *arg) __used, | ||
96 | void *arg __used, int delay_secs __used) | ||
95 | { | 97 | { |
96 | return 0; | 98 | return 0; |
97 | } | 99 | } |
98 | #else | 100 | #else |
99 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 101 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
100 | int refresh); | 102 | int nr_events, void(*timer)(void *arg), void *arg, |
103 | int delay_secs); | ||
101 | #endif | 104 | #endif |
102 | 105 | ||
106 | extern const char *disassembler_style; | ||
107 | |||
103 | #endif /* __PERF_ANNOTATE_H */ | 108 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index e191eb9a667f..521c38a79190 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, | |||
200 | * Auto-detect: | 200 | * Auto-detect: |
201 | */ | 201 | */ |
202 | if (perf_use_color_default < 0) { | 202 | if (perf_use_color_default < 0) { |
203 | if (isatty(1) || pager_in_use()) | 203 | if (isatty(fileno(fp)) || pager_in_use()) |
204 | perf_use_color_default = 1; | 204 | perf_use_color_default = 1; |
205 | else | 205 | else |
206 | perf_use_color_default = 0; | 206 | perf_use_color_default = 0; |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e02d78cae70f..80d9598db31a 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -341,7 +341,7 @@ const char *perf_config_dirname(const char *name, const char *value) | |||
341 | 341 | ||
342 | static int perf_default_core_config(const char *var __used, const char *value __used) | 342 | static int perf_default_core_config(const char *var __used, const char *value __used) |
343 | { | 343 | { |
344 | /* Add other config variables here and to Documentation/config.txt. */ | 344 | /* Add other config variables here. */ |
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
347 | 347 | ||
@@ -350,7 +350,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used) | |||
350 | if (!prefixcmp(var, "core.")) | 350 | if (!prefixcmp(var, "core.")) |
351 | return perf_default_core_config(var, value); | 351 | return perf_default_core_config(var, value); |
352 | 352 | ||
353 | /* Add other config variables here and to Documentation/config.txt. */ | 353 | /* Add other config variables here. */ |
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
356 | 356 | ||
@@ -399,7 +399,6 @@ static int perf_config_global(void) | |||
399 | int perf_config(config_fn_t fn, void *data) | 399 | int perf_config(config_fn_t fn, void *data) |
400 | { | 400 | { |
401 | int ret = 0, found = 0; | 401 | int ret = 0, found = 0; |
402 | char *repo_config = NULL; | ||
403 | const char *home = NULL; | 402 | const char *home = NULL; |
404 | 403 | ||
405 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ | 404 | /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ |
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data) | |||
414 | home = getenv("HOME"); | 413 | home = getenv("HOME"); |
415 | if (perf_config_global() && home) { | 414 | if (perf_config_global() && home) { |
416 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); | 415 | char *user_config = strdup(mkpath("%s/.perfconfig", home)); |
417 | if (!access(user_config, R_OK)) { | 416 | struct stat st; |
418 | ret += perf_config_from_file(fn, user_config, data); | 417 | |
419 | found += 1; | 418 | if (user_config == NULL) { |
419 | warning("Not enough memory to process %s/.perfconfig, " | ||
420 | "ignoring it.", home); | ||
421 | goto out; | ||
420 | } | 422 | } |
421 | free(user_config); | ||
422 | } | ||
423 | 423 | ||
424 | repo_config = perf_pathdup("config"); | 424 | if (stat(user_config, &st) < 0) |
425 | if (!access(repo_config, R_OK)) { | 425 | goto out_free; |
426 | ret += perf_config_from_file(fn, repo_config, data); | 426 | |
427 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
428 | warning("File %s not owned by current user or root, " | ||
429 | "ignoring it.", user_config); | ||
430 | goto out_free; | ||
431 | } | ||
432 | |||
433 | if (!st.st_size) | ||
434 | goto out_free; | ||
435 | |||
436 | ret += perf_config_from_file(fn, user_config, data); | ||
427 | found += 1; | 437 | found += 1; |
438 | out_free: | ||
439 | free(user_config); | ||
428 | } | 440 | } |
429 | free(repo_config); | 441 | out: |
430 | if (found == 0) | 442 | if (found == 0) |
431 | return -1; | 443 | return -1; |
432 | return ret; | 444 | return ret; |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 155749d74350..26817daa2961 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -47,19 +47,20 @@ int dump_printf(const char *fmt, ...) | |||
47 | } | 47 | } |
48 | 48 | ||
49 | #ifdef NO_NEWT_SUPPORT | 49 | #ifdef NO_NEWT_SUPPORT |
50 | void ui__warning(const char *format, ...) | 50 | int ui__warning(const char *format, ...) |
51 | { | 51 | { |
52 | va_list args; | 52 | va_list args; |
53 | 53 | ||
54 | va_start(args, format); | 54 | va_start(args, format); |
55 | vfprintf(stderr, format, args); | 55 | vfprintf(stderr, format, args); |
56 | va_end(args); | 56 | va_end(args); |
57 | return 0; | ||
57 | } | 58 | } |
58 | #endif | 59 | #endif |
59 | 60 | ||
60 | void ui__warning_paranoid(void) | 61 | int ui__error_paranoid(void) |
61 | { | 62 | { |
62 | ui__warning("Permission error - are you root?\n" | 63 | return ui__error("Permission error - are you root?\n" |
63 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" | 64 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" |
64 | " -1 - Not paranoid at all\n" | 65 | " -1 - Not paranoid at all\n" |
65 | " 0 - Disallow raw tracepoint access for unpriv\n" | 66 | " 0 - Disallow raw tracepoint access for unpriv\n" |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index fd53db47e3de..f2ce88d04f54 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -19,23 +19,18 @@ static inline int ui_helpline__show_help(const char *format __used, va_list ap _ | |||
19 | return 0; | 19 | return 0; |
20 | } | 20 | } |
21 | 21 | ||
22 | static inline struct ui_progress *ui_progress__new(const char *title __used, | 22 | static inline void ui_progress__update(u64 curr __used, u64 total __used, |
23 | u64 total __used) | 23 | const char *title __used) {} |
24 | { | ||
25 | return (struct ui_progress *)1; | ||
26 | } | ||
27 | |||
28 | static inline void ui_progress__update(struct ui_progress *self __used, | ||
29 | u64 curr __used) {} | ||
30 | 24 | ||
31 | static inline void ui_progress__delete(struct ui_progress *self __used) {} | 25 | #define ui__error(format, arg...) ui__warning(format, ##arg) |
32 | #else | 26 | #else |
33 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
34 | int ui_helpline__show_help(const char *format, va_list ap); | 28 | int ui_helpline__show_help(const char *format, va_list ap); |
35 | #include "ui/progress.h" | 29 | #include "ui/progress.h" |
30 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
36 | #endif | 31 | #endif |
37 | 32 | ||
38 | void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 33 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
39 | void ui__warning_paranoid(void); | 34 | int ui__error_paranoid(void); |
40 | 35 | ||
41 | #endif /* __PERF_DEBUG_H */ | 36 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index fddf40f30d3e..ee51e9b4dc09 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, | |||
96 | return *lineno ?: -ENOENT; | 96 | return *lineno ?: -ENOENT; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); | ||
100 | |||
101 | /** | ||
102 | * cu_walk_functions_at - Walk on function DIEs at given address | ||
103 | * @cu_die: A CU DIE | ||
104 | * @addr: An address | ||
105 | * @callback: A callback which called with found DIEs | ||
106 | * @data: A user data | ||
107 | * | ||
108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs | ||
109 | * should be subprogram or inlined-subroutines. | ||
110 | */ | ||
111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
112 | int (*callback)(Dwarf_Die *, void *), void *data) | ||
113 | { | ||
114 | Dwarf_Die die_mem; | ||
115 | Dwarf_Die *sc_die; | ||
116 | int ret = -ENOENT; | ||
117 | |||
118 | /* Inlined function could be recursive. Trace it until fail */ | ||
119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); | ||
120 | sc_die != NULL; | ||
121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, | ||
122 | &die_mem)) { | ||
123 | ret = callback(sc_die, data); | ||
124 | if (ret) | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | return ret; | ||
129 | |||
130 | } | ||
131 | |||
99 | /** | 132 | /** |
100 | * die_compare_name - Compare diename and tname | 133 | * die_compare_name - Compare diename and tname |
101 | * @dw_die: a DIE | 134 | * @dw_die: a DIE |
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | |||
198 | return 0; | 231 | return 0; |
199 | } | 232 | } |
200 | 233 | ||
234 | /* Get attribute and translate it as a sdata */ | ||
235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
236 | Dwarf_Sword *result) | ||
237 | { | ||
238 | Dwarf_Attribute attr; | ||
239 | |||
240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
241 | dwarf_formsdata(&attr, result) != 0) | ||
242 | return -ENOENT; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
201 | /** | 247 | /** |
202 | * die_is_signed_type - Check whether a type DIE is signed or not | 248 | * die_is_signed_type - Check whether a type DIE is signed or not |
203 | * @tp_die: a DIE of a type | 249 | * @tp_die: a DIE of a type |
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | |||
250 | return 0; | 296 | return 0; |
251 | } | 297 | } |
252 | 298 | ||
299 | /* Get the call file index number in CU DIE */ | ||
300 | static int die_get_call_fileno(Dwarf_Die *in_die) | ||
301 | { | ||
302 | Dwarf_Sword idx; | ||
303 | |||
304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | ||
305 | return (int)idx; | ||
306 | else | ||
307 | return -ENOENT; | ||
308 | } | ||
309 | |||
310 | /* Get the declared file index number in CU DIE */ | ||
311 | static int die_get_decl_fileno(Dwarf_Die *pdie) | ||
312 | { | ||
313 | Dwarf_Sword idx; | ||
314 | |||
315 | if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0) | ||
316 | return (int)idx; | ||
317 | else | ||
318 | return -ENOENT; | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * die_get_call_file - Get callsite file name of inlined function instance | ||
323 | * @in_die: a DIE of an inlined function instance | ||
324 | * | ||
325 | * Get call-site file name of @in_die. This means from which file the inline | ||
326 | * function is called. | ||
327 | */ | ||
328 | const char *die_get_call_file(Dwarf_Die *in_die) | ||
329 | { | ||
330 | Dwarf_Die cu_die; | ||
331 | Dwarf_Files *files; | ||
332 | int idx; | ||
333 | |||
334 | idx = die_get_call_fileno(in_die); | ||
335 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | ||
336 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | ||
337 | return NULL; | ||
338 | |||
339 | return dwarf_filesrc(files, idx, NULL, NULL); | ||
340 | } | ||
341 | |||
342 | |||
253 | /** | 343 | /** |
254 | * die_find_child - Generic DIE search function in DIE tree | 344 | * die_find_child - Generic DIE search function in DIE tree |
255 | * @rt_die: a root DIE | 345 | * @rt_die: a root DIE |
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
374 | return die_mem; | 464 | return die_mem; |
375 | } | 465 | } |
376 | 466 | ||
467 | struct __instance_walk_param { | ||
468 | void *addr; | ||
469 | int (*callback)(Dwarf_Die *, void *); | ||
470 | void *data; | ||
471 | int retval; | ||
472 | }; | ||
473 | |||
474 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
475 | { | ||
476 | struct __instance_walk_param *iwp = data; | ||
477 | Dwarf_Attribute attr_mem; | ||
478 | Dwarf_Die origin_mem; | ||
479 | Dwarf_Attribute *attr; | ||
480 | Dwarf_Die *origin; | ||
481 | int tmp; | ||
482 | |||
483 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
484 | if (attr == NULL) | ||
485 | return DIE_FIND_CB_CONTINUE; | ||
486 | |||
487 | origin = dwarf_formref_die(attr, &origin_mem); | ||
488 | if (origin == NULL || origin->addr != iwp->addr) | ||
489 | return DIE_FIND_CB_CONTINUE; | ||
490 | |||
491 | /* Ignore redundant instances */ | ||
492 | if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { | ||
493 | dwarf_decl_line(origin, &tmp); | ||
494 | if (die_get_call_lineno(inst) == tmp) { | ||
495 | tmp = die_get_decl_fileno(origin); | ||
496 | if (die_get_call_fileno(inst) == tmp) | ||
497 | return DIE_FIND_CB_CONTINUE; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | iwp->retval = iwp->callback(inst, iwp->data); | ||
502 | |||
503 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * die_walk_instances - Walk on instances of given DIE | ||
508 | * @or_die: an abstract original DIE | ||
509 | * @callback: a callback function which is called with instance DIE | ||
510 | * @data: user data | ||
511 | * | ||
512 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
513 | * declartion. This returns the return value of @callback if it returns | ||
514 | * non-zero value, or -ENOENT if there is no instance. | ||
515 | */ | ||
516 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
517 | void *data) | ||
518 | { | ||
519 | Dwarf_Die cu_die; | ||
520 | Dwarf_Die die_mem; | ||
521 | struct __instance_walk_param iwp = { | ||
522 | .addr = or_die->addr, | ||
523 | .callback = callback, | ||
524 | .data = data, | ||
525 | .retval = -ENOENT, | ||
526 | }; | ||
527 | |||
528 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
529 | return -ENOENT; | ||
530 | |||
531 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
532 | |||
533 | return iwp.retval; | ||
534 | } | ||
535 | |||
377 | /* Line walker internal parameters */ | 536 | /* Line walker internal parameters */ |
378 | struct __line_walk_param { | 537 | struct __line_walk_param { |
379 | const char *fname; | 538 | bool recursive; |
380 | line_walk_callback_t callback; | 539 | line_walk_callback_t callback; |
381 | void *data; | 540 | void *data; |
382 | int retval; | 541 | int retval; |
@@ -385,39 +544,56 @@ struct __line_walk_param { | |||
385 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 544 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
386 | { | 545 | { |
387 | struct __line_walk_param *lw = data; | 546 | struct __line_walk_param *lw = data; |
388 | Dwarf_Addr addr; | 547 | Dwarf_Addr addr = 0; |
548 | const char *fname; | ||
389 | int lineno; | 549 | int lineno; |
390 | 550 | ||
391 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 551 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
552 | fname = die_get_call_file(in_die); | ||
392 | lineno = die_get_call_lineno(in_die); | 553 | lineno = die_get_call_lineno(in_die); |
393 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 554 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
394 | lw->retval = lw->callback(lw->fname, lineno, addr, | 555 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
395 | lw->data); | ||
396 | if (lw->retval != 0) | 556 | if (lw->retval != 0) |
397 | return DIE_FIND_CB_END; | 557 | return DIE_FIND_CB_END; |
398 | } | 558 | } |
399 | } | 559 | } |
400 | return DIE_FIND_CB_SIBLING; | 560 | if (!lw->recursive) |
561 | /* Don't need to search recursively */ | ||
562 | return DIE_FIND_CB_SIBLING; | ||
563 | |||
564 | if (addr) { | ||
565 | fname = dwarf_decl_file(in_die); | ||
566 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | ||
567 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | ||
568 | if (lw->retval != 0) | ||
569 | return DIE_FIND_CB_END; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* Continue to search nested inlined function call-sites */ | ||
574 | return DIE_FIND_CB_CONTINUE; | ||
401 | } | 575 | } |
402 | 576 | ||
403 | /* Walk on lines of blocks included in given DIE */ | 577 | /* Walk on lines of blocks included in given DIE */ |
404 | static int __die_walk_funclines(Dwarf_Die *sp_die, | 578 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
405 | line_walk_callback_t callback, void *data) | 579 | line_walk_callback_t callback, void *data) |
406 | { | 580 | { |
407 | struct __line_walk_param lw = { | 581 | struct __line_walk_param lw = { |
582 | .recursive = recursive, | ||
408 | .callback = callback, | 583 | .callback = callback, |
409 | .data = data, | 584 | .data = data, |
410 | .retval = 0, | 585 | .retval = 0, |
411 | }; | 586 | }; |
412 | Dwarf_Die die_mem; | 587 | Dwarf_Die die_mem; |
413 | Dwarf_Addr addr; | 588 | Dwarf_Addr addr; |
589 | const char *fname; | ||
414 | int lineno; | 590 | int lineno; |
415 | 591 | ||
416 | /* Handle function declaration line */ | 592 | /* Handle function declaration line */ |
417 | lw.fname = dwarf_decl_file(sp_die); | 593 | fname = dwarf_decl_file(sp_die); |
418 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 594 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
419 | dwarf_entrypc(sp_die, &addr) == 0) { | 595 | dwarf_entrypc(sp_die, &addr) == 0) { |
420 | lw.retval = callback(lw.fname, lineno, addr, data); | 596 | lw.retval = callback(fname, lineno, addr, data); |
421 | if (lw.retval != 0) | 597 | if (lw.retval != 0) |
422 | goto done; | 598 | goto done; |
423 | } | 599 | } |
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
430 | { | 606 | { |
431 | struct __line_walk_param *lw = data; | 607 | struct __line_walk_param *lw = data; |
432 | 608 | ||
433 | lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); | 609 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
434 | if (lw->retval != 0) | 610 | if (lw->retval != 0) |
435 | return DWARF_CB_ABORT; | 611 | return DWARF_CB_ABORT; |
436 | 612 | ||
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
439 | 615 | ||
440 | /** | 616 | /** |
441 | * die_walk_lines - Walk on lines inside given DIE | 617 | * die_walk_lines - Walk on lines inside given DIE |
442 | * @rt_die: a root DIE (CU or subprogram) | 618 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) |
443 | * @callback: callback routine | 619 | * @callback: callback routine |
444 | * @data: user data | 620 | * @data: user data |
445 | * | 621 | * |
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
460 | size_t nlines, i; | 636 | size_t nlines, i; |
461 | 637 | ||
462 | /* Get the CU die */ | 638 | /* Get the CU die */ |
463 | if (dwarf_tag(rt_die) == DW_TAG_subprogram) | 639 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) |
464 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); | 640 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); |
465 | else | 641 | else |
466 | cu_die = rt_die; | 642 | cu_die = rt_die; |
467 | if (!cu_die) { | 643 | if (!cu_die) { |
468 | pr_debug2("Failed to get CU from subprogram\n"); | 644 | pr_debug2("Failed to get CU from given DIE.\n"); |
469 | return -EINVAL; | 645 | return -EINVAL; |
470 | } | 646 | } |
471 | 647 | ||
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
509 | * subroutines. We have to check functions list or given function. | 685 | * subroutines. We have to check functions list or given function. |
510 | */ | 686 | */ |
511 | if (rt_die != cu_die) | 687 | if (rt_die != cu_die) |
512 | ret = __die_walk_funclines(rt_die, callback, data); | 688 | /* |
689 | * Don't need walk functions recursively, because nested | ||
690 | * inlined functions don't have lines of the specified DIE. | ||
691 | */ | ||
692 | ret = __die_walk_funclines(rt_die, false, callback, data); | ||
513 | else { | 693 | else { |
514 | struct __line_walk_param param = { | 694 | struct __line_walk_param param = { |
515 | .callback = callback, | 695 | .callback = callback, |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bc3b21167e70..6ce1717784b7 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); | |||
34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
35 | const char **fname, int *lineno); | 35 | const char **fname, int *lineno); |
36 | 36 | ||
37 | /* Walk on funcitons at given address */ | ||
38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
39 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
40 | |||
37 | /* Compare diename and tname */ | 41 | /* Compare diename and tname */ |
38 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
39 | 43 | ||
40 | /* Get callsite line number of inline-function instance */ | 44 | /* Get callsite line number of inline-function instance */ |
41 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 45 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
42 | 46 | ||
47 | /* Get callsite file name of inlined function instance */ | ||
48 | extern const char *die_get_call_file(Dwarf_Die *in_die); | ||
49 | |||
43 | /* Get type die */ | 50 | /* Get type die */ |
44 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
45 | 52 | ||
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
73 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
74 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
75 | 82 | ||
83 | /* Walk on the instances of given DIE */ | ||
84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
86 | |||
76 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
77 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
78 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3c1b8a632101..437f8ca679a0 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, | |||
169 | continue; | 169 | continue; |
170 | pbf += n + 3; | 170 | pbf += n + 3; |
171 | if (*pbf == 'x') { /* vm_exec */ | 171 | if (*pbf == 'x') { /* vm_exec */ |
172 | char anonstr[] = "//anon\n"; | ||
172 | char *execname = strchr(bf, '/'); | 173 | char *execname = strchr(bf, '/'); |
173 | 174 | ||
174 | /* Catch VDSO */ | 175 | /* Catch VDSO */ |
175 | if (execname == NULL) | 176 | if (execname == NULL) |
176 | execname = strstr(bf, "[vdso]"); | 177 | execname = strstr(bf, "[vdso]"); |
177 | 178 | ||
179 | /* Catch anonymous mmaps */ | ||
180 | if ((execname == NULL) && !strstr(bf, "[")) | ||
181 | execname = anonstr; | ||
182 | |||
178 | if (execname == NULL) | 183 | if (execname == NULL) |
179 | continue; | 184 | continue; |
180 | 185 | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1d7f66488a88..357a85b85248 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id); | |||
186 | 186 | ||
187 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 187 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
188 | int sample_size, bool sample_id_all, | 188 | int sample_size, bool sample_id_all, |
189 | struct perf_sample *sample); | 189 | struct perf_sample *sample, bool swapped); |
190 | 190 | ||
191 | #endif /* __PERF_RECORD_H */ | 191 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b021ea9265c3..fbb4b4ab9cc6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -85,10 +85,45 @@ int perf_evlist__add_default(struct perf_evlist *evlist) | |||
85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); | 85 | struct perf_evsel *evsel = perf_evsel__new(&attr, 0); |
86 | 86 | ||
87 | if (evsel == NULL) | 87 | if (evsel == NULL) |
88 | return -ENOMEM; | 88 | goto error; |
89 | |||
90 | /* use strdup() because free(evsel) assumes name is allocated */ | ||
91 | evsel->name = strdup("cycles"); | ||
92 | if (!evsel->name) | ||
93 | goto error_free; | ||
89 | 94 | ||
90 | perf_evlist__add(evlist, evsel); | 95 | perf_evlist__add(evlist, evsel); |
91 | return 0; | 96 | return 0; |
97 | error_free: | ||
98 | perf_evsel__delete(evsel); | ||
99 | error: | ||
100 | return -ENOMEM; | ||
101 | } | ||
102 | |||
103 | void perf_evlist__disable(struct perf_evlist *evlist) | ||
104 | { | ||
105 | int cpu, thread; | ||
106 | struct perf_evsel *pos; | ||
107 | |||
108 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
109 | list_for_each_entry(pos, &evlist->entries, node) { | ||
110 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
111 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void perf_evlist__enable(struct perf_evlist *evlist) | ||
117 | { | ||
118 | int cpu, thread; | ||
119 | struct perf_evsel *pos; | ||
120 | |||
121 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
122 | list_for_each_entry(pos, &evlist->entries, node) { | ||
123 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
124 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); | ||
125 | } | ||
126 | } | ||
92 | } | 127 | } |
93 | 128 | ||
94 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 129 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
@@ -498,3 +533,39 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) | |||
498 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 533 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
499 | return first->attr.sample_id_all; | 534 | return first->attr.sample_id_all; |
500 | } | 535 | } |
536 | |||
537 | void perf_evlist__set_selected(struct perf_evlist *evlist, | ||
538 | struct perf_evsel *evsel) | ||
539 | { | ||
540 | evlist->selected = evsel; | ||
541 | } | ||
542 | |||
543 | int perf_evlist__open(struct perf_evlist *evlist, bool group) | ||
544 | { | ||
545 | struct perf_evsel *evsel, *first; | ||
546 | int err, ncpus, nthreads; | ||
547 | |||
548 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
549 | |||
550 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
551 | struct xyarray *group_fd = NULL; | ||
552 | |||
553 | if (group && evsel != first) | ||
554 | group_fd = first->fd; | ||
555 | |||
556 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads, | ||
557 | group, group_fd); | ||
558 | if (err < 0) | ||
559 | goto out_err; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | out_err: | ||
564 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | ||
565 | nthreads = evlist->threads ? evlist->threads->nr : 1; | ||
566 | |||
567 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
568 | perf_evsel__close(evsel, ncpus, nthreads); | ||
569 | |||
570 | return err; | ||
571 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index b2b862374f37..1779ffef7828 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -25,6 +25,7 @@ struct perf_evlist { | |||
25 | struct pollfd *pollfd; | 25 | struct pollfd *pollfd; |
26 | struct thread_map *threads; | 26 | struct thread_map *threads; |
27 | struct cpu_map *cpus; | 27 | struct cpu_map *cpus; |
28 | struct perf_evsel *selected; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct perf_evsel; | 31 | struct perf_evsel; |
@@ -49,10 +50,18 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | |||
49 | 50 | ||
50 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 51 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
51 | 52 | ||
53 | int perf_evlist__open(struct perf_evlist *evlist, bool group); | ||
54 | |||
52 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); | 55 | int perf_evlist__alloc_mmap(struct perf_evlist *evlist); |
53 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | 56 | int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); |
54 | void perf_evlist__munmap(struct perf_evlist *evlist); | 57 | void perf_evlist__munmap(struct perf_evlist *evlist); |
55 | 58 | ||
59 | void perf_evlist__disable(struct perf_evlist *evlist); | ||
60 | void perf_evlist__enable(struct perf_evlist *evlist); | ||
61 | |||
62 | void perf_evlist__set_selected(struct perf_evlist *evlist, | ||
63 | struct perf_evsel *evsel); | ||
64 | |||
56 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | 65 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, |
57 | struct cpu_map *cpus, | 66 | struct cpu_map *cpus, |
58 | struct thread_map *threads) | 67 | struct thread_map *threads) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a03a36b7908a..e42626422587 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <byteswap.h> | ||
11 | #include "asm/bug.h" | ||
10 | #include "evsel.h" | 12 | #include "evsel.h" |
11 | #include "evlist.h" | 13 | #include "evlist.h" |
12 | #include "util.h" | 14 | #include "util.h" |
@@ -14,6 +16,7 @@ | |||
14 | #include "thread_map.h" | 16 | #include "thread_map.h" |
15 | 17 | ||
16 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 18 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
19 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) | ||
17 | 20 | ||
18 | int __perf_evsel__sample_size(u64 sample_type) | 21 | int __perf_evsel__sample_size(u64 sample_type) |
19 | { | 22 | { |
@@ -37,6 +40,7 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
37 | evsel->idx = idx; | 40 | evsel->idx = idx; |
38 | evsel->attr = *attr; | 41 | evsel->attr = *attr; |
39 | INIT_LIST_HEAD(&evsel->node); | 42 | INIT_LIST_HEAD(&evsel->node); |
43 | hists__init(&evsel->hists); | ||
40 | } | 44 | } |
41 | 45 | ||
42 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 46 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
@@ -201,15 +205,16 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
201 | } | 205 | } |
202 | 206 | ||
203 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 207 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
204 | struct thread_map *threads, bool group) | 208 | struct thread_map *threads, bool group, |
209 | struct xyarray *group_fds) | ||
205 | { | 210 | { |
206 | int cpu, thread; | 211 | int cpu, thread; |
207 | unsigned long flags = 0; | 212 | unsigned long flags = 0; |
208 | int pid = -1; | 213 | int pid = -1, err; |
209 | 214 | ||
210 | if (evsel->fd == NULL && | 215 | if (evsel->fd == NULL && |
211 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 216 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) |
212 | return -1; | 217 | return -ENOMEM; |
213 | 218 | ||
214 | if (evsel->cgrp) { | 219 | if (evsel->cgrp) { |
215 | flags = PERF_FLAG_PID_CGROUP; | 220 | flags = PERF_FLAG_PID_CGROUP; |
@@ -217,7 +222,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
217 | } | 222 | } |
218 | 223 | ||
219 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 224 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
220 | int group_fd = -1; | 225 | int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; |
221 | 226 | ||
222 | for (thread = 0; thread < threads->nr; thread++) { | 227 | for (thread = 0; thread < threads->nr; thread++) { |
223 | 228 | ||
@@ -228,8 +233,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
228 | pid, | 233 | pid, |
229 | cpus->map[cpu], | 234 | cpus->map[cpu], |
230 | group_fd, flags); | 235 | group_fd, flags); |
231 | if (FD(evsel, cpu, thread) < 0) | 236 | if (FD(evsel, cpu, thread) < 0) { |
237 | err = -errno; | ||
232 | goto out_close; | 238 | goto out_close; |
239 | } | ||
233 | 240 | ||
234 | if (group && group_fd == -1) | 241 | if (group && group_fd == -1) |
235 | group_fd = FD(evsel, cpu, thread); | 242 | group_fd = FD(evsel, cpu, thread); |
@@ -246,7 +253,17 @@ out_close: | |||
246 | } | 253 | } |
247 | thread = threads->nr; | 254 | thread = threads->nr; |
248 | } while (--cpu >= 0); | 255 | } while (--cpu >= 0); |
249 | return -1; | 256 | return err; |
257 | } | ||
258 | |||
259 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | ||
260 | { | ||
261 | if (evsel->fd == NULL) | ||
262 | return; | ||
263 | |||
264 | perf_evsel__close_fd(evsel, ncpus, nthreads); | ||
265 | perf_evsel__free_fd(evsel); | ||
266 | evsel->fd = NULL; | ||
250 | } | 267 | } |
251 | 268 | ||
252 | static struct { | 269 | static struct { |
@@ -266,7 +283,8 @@ static struct { | |||
266 | }; | 283 | }; |
267 | 284 | ||
268 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 285 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
269 | struct thread_map *threads, bool group) | 286 | struct thread_map *threads, bool group, |
287 | struct xyarray *group_fd) | ||
270 | { | 288 | { |
271 | if (cpus == NULL) { | 289 | if (cpus == NULL) { |
272 | /* Work around old compiler warnings about strict aliasing */ | 290 | /* Work around old compiler warnings about strict aliasing */ |
@@ -276,19 +294,23 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | |||
276 | if (threads == NULL) | 294 | if (threads == NULL) |
277 | threads = &empty_thread_map.map; | 295 | threads = &empty_thread_map.map; |
278 | 296 | ||
279 | return __perf_evsel__open(evsel, cpus, threads, group); | 297 | return __perf_evsel__open(evsel, cpus, threads, group, group_fd); |
280 | } | 298 | } |
281 | 299 | ||
282 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 300 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
283 | struct cpu_map *cpus, bool group) | 301 | struct cpu_map *cpus, bool group, |
302 | struct xyarray *group_fd) | ||
284 | { | 303 | { |
285 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); | 304 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, |
305 | group_fd); | ||
286 | } | 306 | } |
287 | 307 | ||
288 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 308 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
289 | struct thread_map *threads, bool group) | 309 | struct thread_map *threads, bool group, |
310 | struct xyarray *group_fd) | ||
290 | { | 311 | { |
291 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); | 312 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, |
313 | group_fd); | ||
292 | } | 314 | } |
293 | 315 | ||
294 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 316 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, |
@@ -342,10 +364,20 @@ static bool sample_overlap(const union perf_event *event, | |||
342 | 364 | ||
343 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 365 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
344 | int sample_size, bool sample_id_all, | 366 | int sample_size, bool sample_id_all, |
345 | struct perf_sample *data) | 367 | struct perf_sample *data, bool swapped) |
346 | { | 368 | { |
347 | const u64 *array; | 369 | const u64 *array; |
348 | 370 | ||
371 | /* | ||
372 | * used for cross-endian analysis. See git commit 65014ab3 | ||
373 | * for why this goofiness is needed. | ||
374 | */ | ||
375 | union { | ||
376 | u64 val64; | ||
377 | u32 val32[2]; | ||
378 | } u; | ||
379 | |||
380 | |||
349 | data->cpu = data->pid = data->tid = -1; | 381 | data->cpu = data->pid = data->tid = -1; |
350 | data->stream_id = data->id = data->time = -1ULL; | 382 | data->stream_id = data->id = data->time = -1ULL; |
351 | 383 | ||
@@ -366,9 +398,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
366 | } | 398 | } |
367 | 399 | ||
368 | if (type & PERF_SAMPLE_TID) { | 400 | if (type & PERF_SAMPLE_TID) { |
369 | u32 *p = (u32 *)array; | 401 | u.val64 = *array; |
370 | data->pid = p[0]; | 402 | if (swapped) { |
371 | data->tid = p[1]; | 403 | /* undo swap of u64, then swap on individual u32s */ |
404 | u.val64 = bswap_64(u.val64); | ||
405 | u.val32[0] = bswap_32(u.val32[0]); | ||
406 | u.val32[1] = bswap_32(u.val32[1]); | ||
407 | } | ||
408 | |||
409 | data->pid = u.val32[0]; | ||
410 | data->tid = u.val32[1]; | ||
372 | array++; | 411 | array++; |
373 | } | 412 | } |
374 | 413 | ||
@@ -395,8 +434,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
395 | } | 434 | } |
396 | 435 | ||
397 | if (type & PERF_SAMPLE_CPU) { | 436 | if (type & PERF_SAMPLE_CPU) { |
398 | u32 *p = (u32 *)array; | 437 | |
399 | data->cpu = *p; | 438 | u.val64 = *array; |
439 | if (swapped) { | ||
440 | /* undo swap of u64, then swap on individual u32s */ | ||
441 | u.val64 = bswap_64(u.val64); | ||
442 | u.val32[0] = bswap_32(u.val32[0]); | ||
443 | } | ||
444 | |||
445 | data->cpu = u.val32[0]; | ||
400 | array++; | 446 | array++; |
401 | } | 447 | } |
402 | 448 | ||
@@ -423,18 +469,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
423 | } | 469 | } |
424 | 470 | ||
425 | if (type & PERF_SAMPLE_RAW) { | 471 | if (type & PERF_SAMPLE_RAW) { |
426 | u32 *p = (u32 *)array; | 472 | const u64 *pdata; |
473 | |||
474 | u.val64 = *array; | ||
475 | if (WARN_ONCE(swapped, | ||
476 | "Endianness of raw data not corrected!\n")) { | ||
477 | /* undo swap of u64, then swap on individual u32s */ | ||
478 | u.val64 = bswap_64(u.val64); | ||
479 | u.val32[0] = bswap_32(u.val32[0]); | ||
480 | u.val32[1] = bswap_32(u.val32[1]); | ||
481 | } | ||
427 | 482 | ||
428 | if (sample_overlap(event, array, sizeof(u32))) | 483 | if (sample_overlap(event, array, sizeof(u32))) |
429 | return -EFAULT; | 484 | return -EFAULT; |
430 | 485 | ||
431 | data->raw_size = *p; | 486 | data->raw_size = u.val32[0]; |
432 | p++; | 487 | pdata = (void *) array + sizeof(u32); |
433 | 488 | ||
434 | if (sample_overlap(event, p, data->raw_size)) | 489 | if (sample_overlap(event, pdata, data->raw_size)) |
435 | return -EFAULT; | 490 | return -EFAULT; |
436 | 491 | ||
437 | data->raw_data = p; | 492 | data->raw_data = (void *) pdata; |
438 | } | 493 | } |
439 | 494 | ||
440 | return 0; | 495 | return 0; |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index e9a31554e265..b1d15e6f7ae3 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -82,11 +82,15 @@ void perf_evsel__free_id(struct perf_evsel *evsel); | |||
82 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 82 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
83 | 83 | ||
84 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 84 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
85 | struct cpu_map *cpus, bool group); | 85 | struct cpu_map *cpus, bool group, |
86 | struct xyarray *group_fds); | ||
86 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 87 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
87 | struct thread_map *threads, bool group); | 88 | struct thread_map *threads, bool group, |
89 | struct xyarray *group_fds); | ||
88 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 90 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
89 | struct thread_map *threads, bool group); | 91 | struct thread_map *threads, bool group, |
92 | struct xyarray *group_fds); | ||
93 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
90 | 94 | ||
91 | #define perf_evsel__match(evsel, t, c) \ | 95 | #define perf_evsel__match(evsel, t, c) \ |
92 | (evsel->attr.type == PERF_TYPE_##t && \ | 96 | (evsel->attr.type == PERF_TYPE_##t && \ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index cb2959a3fb43..bcd05d05b4f0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _FILE_OFFSET_BITS 64 | 1 | #define _FILE_OFFSET_BITS 64 |
2 | 2 | ||
3 | #include "util.h" | ||
3 | #include <sys/types.h> | 4 | #include <sys/types.h> |
4 | #include <byteswap.h> | 5 | #include <byteswap.h> |
5 | #include <unistd.h> | 6 | #include <unistd.h> |
@@ -7,22 +8,29 @@ | |||
7 | #include <stdlib.h> | 8 | #include <stdlib.h> |
8 | #include <linux/list.h> | 9 | #include <linux/list.h> |
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <sys/utsname.h> | ||
10 | 12 | ||
11 | #include "evlist.h" | 13 | #include "evlist.h" |
12 | #include "evsel.h" | 14 | #include "evsel.h" |
13 | #include "util.h" | ||
14 | #include "header.h" | 15 | #include "header.h" |
15 | #include "../perf.h" | 16 | #include "../perf.h" |
16 | #include "trace-event.h" | 17 | #include "trace-event.h" |
17 | #include "session.h" | 18 | #include "session.h" |
18 | #include "symbol.h" | 19 | #include "symbol.h" |
19 | #include "debug.h" | 20 | #include "debug.h" |
21 | #include "cpumap.h" | ||
20 | 22 | ||
21 | static bool no_buildid_cache = false; | 23 | static bool no_buildid_cache = false; |
22 | 24 | ||
23 | static int event_count; | 25 | static int event_count; |
24 | static struct perf_trace_event_type *events; | 26 | static struct perf_trace_event_type *events; |
25 | 27 | ||
28 | static u32 header_argc; | ||
29 | static const char **header_argv; | ||
30 | |||
31 | static int dsos__write_buildid_table(struct perf_header *header, int fd); | ||
32 | static int perf_session__cache_build_ids(struct perf_session *session); | ||
33 | |||
26 | int perf_header__push_event(u64 id, const char *name) | 34 | int perf_header__push_event(u64 id, const char *name) |
27 | { | 35 | { |
28 | if (strlen(name) > MAX_EVENT_NAME) | 36 | if (strlen(name) > MAX_EVENT_NAME) |
@@ -110,6 +118,1020 @@ static int write_padded(int fd, const void *bf, size_t count, | |||
110 | return err; | 118 | return err; |
111 | } | 119 | } |
112 | 120 | ||
121 | static int do_write_string(int fd, const char *str) | ||
122 | { | ||
123 | u32 len, olen; | ||
124 | int ret; | ||
125 | |||
126 | olen = strlen(str) + 1; | ||
127 | len = ALIGN(olen, NAME_ALIGN); | ||
128 | |||
129 | /* write len, incl. \0 */ | ||
130 | ret = do_write(fd, &len, sizeof(len)); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | |||
134 | return write_padded(fd, str, olen, len); | ||
135 | } | ||
136 | |||
137 | static char *do_read_string(int fd, struct perf_header *ph) | ||
138 | { | ||
139 | ssize_t sz, ret; | ||
140 | u32 len; | ||
141 | char *buf; | ||
142 | |||
143 | sz = read(fd, &len, sizeof(len)); | ||
144 | if (sz < (ssize_t)sizeof(len)) | ||
145 | return NULL; | ||
146 | |||
147 | if (ph->needs_swap) | ||
148 | len = bswap_32(len); | ||
149 | |||
150 | buf = malloc(len); | ||
151 | if (!buf) | ||
152 | return NULL; | ||
153 | |||
154 | ret = read(fd, buf, len); | ||
155 | if (ret == (ssize_t)len) { | ||
156 | /* | ||
157 | * strings are padded by zeroes | ||
158 | * thus the actual strlen of buf | ||
159 | * may be less than len | ||
160 | */ | ||
161 | return buf; | ||
162 | } | ||
163 | |||
164 | free(buf); | ||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | int | ||
169 | perf_header__set_cmdline(int argc, const char **argv) | ||
170 | { | ||
171 | int i; | ||
172 | |||
173 | header_argc = (u32)argc; | ||
174 | |||
175 | /* do not include NULL termination */ | ||
176 | header_argv = calloc(argc, sizeof(char *)); | ||
177 | if (!header_argv) | ||
178 | return -ENOMEM; | ||
179 | |||
180 | /* | ||
181 | * must copy argv contents because it gets moved | ||
182 | * around during option parsing | ||
183 | */ | ||
184 | for (i = 0; i < argc ; i++) | ||
185 | header_argv[i] = argv[i]; | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int write_trace_info(int fd, struct perf_header *h __used, | ||
191 | struct perf_evlist *evlist) | ||
192 | { | ||
193 | return read_tracing_data(fd, &evlist->entries); | ||
194 | } | ||
195 | |||
196 | |||
197 | static int write_build_id(int fd, struct perf_header *h, | ||
198 | struct perf_evlist *evlist __used) | ||
199 | { | ||
200 | struct perf_session *session; | ||
201 | int err; | ||
202 | |||
203 | session = container_of(h, struct perf_session, header); | ||
204 | |||
205 | err = dsos__write_buildid_table(h, fd); | ||
206 | if (err < 0) { | ||
207 | pr_debug("failed to write buildid table\n"); | ||
208 | return err; | ||
209 | } | ||
210 | if (!no_buildid_cache) | ||
211 | perf_session__cache_build_ids(session); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int write_hostname(int fd, struct perf_header *h __used, | ||
217 | struct perf_evlist *evlist __used) | ||
218 | { | ||
219 | struct utsname uts; | ||
220 | int ret; | ||
221 | |||
222 | ret = uname(&uts); | ||
223 | if (ret < 0) | ||
224 | return -1; | ||
225 | |||
226 | return do_write_string(fd, uts.nodename); | ||
227 | } | ||
228 | |||
229 | static int write_osrelease(int fd, struct perf_header *h __used, | ||
230 | struct perf_evlist *evlist __used) | ||
231 | { | ||
232 | struct utsname uts; | ||
233 | int ret; | ||
234 | |||
235 | ret = uname(&uts); | ||
236 | if (ret < 0) | ||
237 | return -1; | ||
238 | |||
239 | return do_write_string(fd, uts.release); | ||
240 | } | ||
241 | |||
242 | static int write_arch(int fd, struct perf_header *h __used, | ||
243 | struct perf_evlist *evlist __used) | ||
244 | { | ||
245 | struct utsname uts; | ||
246 | int ret; | ||
247 | |||
248 | ret = uname(&uts); | ||
249 | if (ret < 0) | ||
250 | return -1; | ||
251 | |||
252 | return do_write_string(fd, uts.machine); | ||
253 | } | ||
254 | |||
255 | static int write_version(int fd, struct perf_header *h __used, | ||
256 | struct perf_evlist *evlist __used) | ||
257 | { | ||
258 | return do_write_string(fd, perf_version_string); | ||
259 | } | ||
260 | |||
261 | static int write_cpudesc(int fd, struct perf_header *h __used, | ||
262 | struct perf_evlist *evlist __used) | ||
263 | { | ||
264 | #ifndef CPUINFO_PROC | ||
265 | #define CPUINFO_PROC NULL | ||
266 | #endif | ||
267 | FILE *file; | ||
268 | char *buf = NULL; | ||
269 | char *s, *p; | ||
270 | const char *search = CPUINFO_PROC; | ||
271 | size_t len = 0; | ||
272 | int ret = -1; | ||
273 | |||
274 | if (!search) | ||
275 | return -1; | ||
276 | |||
277 | file = fopen("/proc/cpuinfo", "r"); | ||
278 | if (!file) | ||
279 | return -1; | ||
280 | |||
281 | while (getline(&buf, &len, file) > 0) { | ||
282 | ret = strncmp(buf, search, strlen(search)); | ||
283 | if (!ret) | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | if (ret) | ||
288 | goto done; | ||
289 | |||
290 | s = buf; | ||
291 | |||
292 | p = strchr(buf, ':'); | ||
293 | if (p && *(p+1) == ' ' && *(p+2)) | ||
294 | s = p + 2; | ||
295 | p = strchr(s, '\n'); | ||
296 | if (p) | ||
297 | *p = '\0'; | ||
298 | |||
299 | /* squash extra space characters (branding string) */ | ||
300 | p = s; | ||
301 | while (*p) { | ||
302 | if (isspace(*p)) { | ||
303 | char *r = p + 1; | ||
304 | char *q = r; | ||
305 | *p = ' '; | ||
306 | while (*q && isspace(*q)) | ||
307 | q++; | ||
308 | if (q != (p+1)) | ||
309 | while ((*r++ = *q++)); | ||
310 | } | ||
311 | p++; | ||
312 | } | ||
313 | ret = do_write_string(fd, s); | ||
314 | done: | ||
315 | free(buf); | ||
316 | fclose(file); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | static int write_nrcpus(int fd, struct perf_header *h __used, | ||
321 | struct perf_evlist *evlist __used) | ||
322 | { | ||
323 | long nr; | ||
324 | u32 nrc, nra; | ||
325 | int ret; | ||
326 | |||
327 | nr = sysconf(_SC_NPROCESSORS_CONF); | ||
328 | if (nr < 0) | ||
329 | return -1; | ||
330 | |||
331 | nrc = (u32)(nr & UINT_MAX); | ||
332 | |||
333 | nr = sysconf(_SC_NPROCESSORS_ONLN); | ||
334 | if (nr < 0) | ||
335 | return -1; | ||
336 | |||
337 | nra = (u32)(nr & UINT_MAX); | ||
338 | |||
339 | ret = do_write(fd, &nrc, sizeof(nrc)); | ||
340 | if (ret < 0) | ||
341 | return ret; | ||
342 | |||
343 | return do_write(fd, &nra, sizeof(nra)); | ||
344 | } | ||
345 | |||
346 | static int write_event_desc(int fd, struct perf_header *h __used, | ||
347 | struct perf_evlist *evlist) | ||
348 | { | ||
349 | struct perf_evsel *attr; | ||
350 | u32 nre = 0, nri, sz; | ||
351 | int ret; | ||
352 | |||
353 | list_for_each_entry(attr, &evlist->entries, node) | ||
354 | nre++; | ||
355 | |||
356 | /* | ||
357 | * write number of events | ||
358 | */ | ||
359 | ret = do_write(fd, &nre, sizeof(nre)); | ||
360 | if (ret < 0) | ||
361 | return ret; | ||
362 | |||
363 | /* | ||
364 | * size of perf_event_attr struct | ||
365 | */ | ||
366 | sz = (u32)sizeof(attr->attr); | ||
367 | ret = do_write(fd, &sz, sizeof(sz)); | ||
368 | if (ret < 0) | ||
369 | return ret; | ||
370 | |||
371 | list_for_each_entry(attr, &evlist->entries, node) { | ||
372 | |||
373 | ret = do_write(fd, &attr->attr, sz); | ||
374 | if (ret < 0) | ||
375 | return ret; | ||
376 | /* | ||
377 | * write number of unique id per event | ||
378 | * there is one id per instance of an event | ||
379 | * | ||
380 | * copy into an nri to be independent of the | ||
381 | * type of ids, | ||
382 | */ | ||
383 | nri = attr->ids; | ||
384 | ret = do_write(fd, &nri, sizeof(nri)); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | |||
388 | /* | ||
389 | * write event string as passed on cmdline | ||
390 | */ | ||
391 | ret = do_write_string(fd, attr->name); | ||
392 | if (ret < 0) | ||
393 | return ret; | ||
394 | /* | ||
395 | * write unique ids for this event | ||
396 | */ | ||
397 | ret = do_write(fd, attr->id, attr->ids * sizeof(u64)); | ||
398 | if (ret < 0) | ||
399 | return ret; | ||
400 | } | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int write_cmdline(int fd, struct perf_header *h __used, | ||
405 | struct perf_evlist *evlist __used) | ||
406 | { | ||
407 | char buf[MAXPATHLEN]; | ||
408 | char proc[32]; | ||
409 | u32 i, n; | ||
410 | int ret; | ||
411 | |||
412 | /* | ||
413 | * actual atual path to perf binary | ||
414 | */ | ||
415 | sprintf(proc, "/proc/%d/exe", getpid()); | ||
416 | ret = readlink(proc, buf, sizeof(buf)); | ||
417 | if (ret <= 0) | ||
418 | return -1; | ||
419 | |||
420 | /* readlink() does not add null termination */ | ||
421 | buf[ret] = '\0'; | ||
422 | |||
423 | /* account for binary path */ | ||
424 | n = header_argc + 1; | ||
425 | |||
426 | ret = do_write(fd, &n, sizeof(n)); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | |||
430 | ret = do_write_string(fd, buf); | ||
431 | if (ret < 0) | ||
432 | return ret; | ||
433 | |||
434 | for (i = 0 ; i < header_argc; i++) { | ||
435 | ret = do_write_string(fd, header_argv[i]); | ||
436 | if (ret < 0) | ||
437 | return ret; | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | #define CORE_SIB_FMT \ | ||
443 | "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list" | ||
444 | #define THRD_SIB_FMT \ | ||
445 | "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list" | ||
446 | |||
447 | struct cpu_topo { | ||
448 | u32 core_sib; | ||
449 | u32 thread_sib; | ||
450 | char **core_siblings; | ||
451 | char **thread_siblings; | ||
452 | }; | ||
453 | |||
454 | static int build_cpu_topo(struct cpu_topo *tp, int cpu) | ||
455 | { | ||
456 | FILE *fp; | ||
457 | char filename[MAXPATHLEN]; | ||
458 | char *buf = NULL, *p; | ||
459 | size_t len = 0; | ||
460 | u32 i = 0; | ||
461 | int ret = -1; | ||
462 | |||
463 | sprintf(filename, CORE_SIB_FMT, cpu); | ||
464 | fp = fopen(filename, "r"); | ||
465 | if (!fp) | ||
466 | return -1; | ||
467 | |||
468 | if (getline(&buf, &len, fp) <= 0) | ||
469 | goto done; | ||
470 | |||
471 | fclose(fp); | ||
472 | |||
473 | p = strchr(buf, '\n'); | ||
474 | if (p) | ||
475 | *p = '\0'; | ||
476 | |||
477 | for (i = 0; i < tp->core_sib; i++) { | ||
478 | if (!strcmp(buf, tp->core_siblings[i])) | ||
479 | break; | ||
480 | } | ||
481 | if (i == tp->core_sib) { | ||
482 | tp->core_siblings[i] = buf; | ||
483 | tp->core_sib++; | ||
484 | buf = NULL; | ||
485 | len = 0; | ||
486 | } | ||
487 | |||
488 | sprintf(filename, THRD_SIB_FMT, cpu); | ||
489 | fp = fopen(filename, "r"); | ||
490 | if (!fp) | ||
491 | goto done; | ||
492 | |||
493 | if (getline(&buf, &len, fp) <= 0) | ||
494 | goto done; | ||
495 | |||
496 | p = strchr(buf, '\n'); | ||
497 | if (p) | ||
498 | *p = '\0'; | ||
499 | |||
500 | for (i = 0; i < tp->thread_sib; i++) { | ||
501 | if (!strcmp(buf, tp->thread_siblings[i])) | ||
502 | break; | ||
503 | } | ||
504 | if (i == tp->thread_sib) { | ||
505 | tp->thread_siblings[i] = buf; | ||
506 | tp->thread_sib++; | ||
507 | buf = NULL; | ||
508 | } | ||
509 | ret = 0; | ||
510 | done: | ||
511 | if(fp) | ||
512 | fclose(fp); | ||
513 | free(buf); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | static void free_cpu_topo(struct cpu_topo *tp) | ||
518 | { | ||
519 | u32 i; | ||
520 | |||
521 | if (!tp) | ||
522 | return; | ||
523 | |||
524 | for (i = 0 ; i < tp->core_sib; i++) | ||
525 | free(tp->core_siblings[i]); | ||
526 | |||
527 | for (i = 0 ; i < tp->thread_sib; i++) | ||
528 | free(tp->thread_siblings[i]); | ||
529 | |||
530 | free(tp); | ||
531 | } | ||
532 | |||
533 | static struct cpu_topo *build_cpu_topology(void) | ||
534 | { | ||
535 | struct cpu_topo *tp; | ||
536 | void *addr; | ||
537 | u32 nr, i; | ||
538 | size_t sz; | ||
539 | long ncpus; | ||
540 | int ret = -1; | ||
541 | |||
542 | ncpus = sysconf(_SC_NPROCESSORS_CONF); | ||
543 | if (ncpus < 0) | ||
544 | return NULL; | ||
545 | |||
546 | nr = (u32)(ncpus & UINT_MAX); | ||
547 | |||
548 | sz = nr * sizeof(char *); | ||
549 | |||
550 | addr = calloc(1, sizeof(*tp) + 2 * sz); | ||
551 | if (!addr) | ||
552 | return NULL; | ||
553 | |||
554 | tp = addr; | ||
555 | |||
556 | addr += sizeof(*tp); | ||
557 | tp->core_siblings = addr; | ||
558 | addr += sz; | ||
559 | tp->thread_siblings = addr; | ||
560 | |||
561 | for (i = 0; i < nr; i++) { | ||
562 | ret = build_cpu_topo(tp, i); | ||
563 | if (ret < 0) | ||
564 | break; | ||
565 | } | ||
566 | if (ret) { | ||
567 | free_cpu_topo(tp); | ||
568 | tp = NULL; | ||
569 | } | ||
570 | return tp; | ||
571 | } | ||
572 | |||
573 | static int write_cpu_topology(int fd, struct perf_header *h __used, | ||
574 | struct perf_evlist *evlist __used) | ||
575 | { | ||
576 | struct cpu_topo *tp; | ||
577 | u32 i; | ||
578 | int ret; | ||
579 | |||
580 | tp = build_cpu_topology(); | ||
581 | if (!tp) | ||
582 | return -1; | ||
583 | |||
584 | ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib)); | ||
585 | if (ret < 0) | ||
586 | goto done; | ||
587 | |||
588 | for (i = 0; i < tp->core_sib; i++) { | ||
589 | ret = do_write_string(fd, tp->core_siblings[i]); | ||
590 | if (ret < 0) | ||
591 | goto done; | ||
592 | } | ||
593 | ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib)); | ||
594 | if (ret < 0) | ||
595 | goto done; | ||
596 | |||
597 | for (i = 0; i < tp->thread_sib; i++) { | ||
598 | ret = do_write_string(fd, tp->thread_siblings[i]); | ||
599 | if (ret < 0) | ||
600 | break; | ||
601 | } | ||
602 | done: | ||
603 | free_cpu_topo(tp); | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | |||
608 | |||
609 | static int write_total_mem(int fd, struct perf_header *h __used, | ||
610 | struct perf_evlist *evlist __used) | ||
611 | { | ||
612 | char *buf = NULL; | ||
613 | FILE *fp; | ||
614 | size_t len = 0; | ||
615 | int ret = -1, n; | ||
616 | uint64_t mem; | ||
617 | |||
618 | fp = fopen("/proc/meminfo", "r"); | ||
619 | if (!fp) | ||
620 | return -1; | ||
621 | |||
622 | while (getline(&buf, &len, fp) > 0) { | ||
623 | ret = strncmp(buf, "MemTotal:", 9); | ||
624 | if (!ret) | ||
625 | break; | ||
626 | } | ||
627 | if (!ret) { | ||
628 | n = sscanf(buf, "%*s %"PRIu64, &mem); | ||
629 | if (n == 1) | ||
630 | ret = do_write(fd, &mem, sizeof(mem)); | ||
631 | } | ||
632 | free(buf); | ||
633 | fclose(fp); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static int write_topo_node(int fd, int node) | ||
638 | { | ||
639 | char str[MAXPATHLEN]; | ||
640 | char field[32]; | ||
641 | char *buf = NULL, *p; | ||
642 | size_t len = 0; | ||
643 | FILE *fp; | ||
644 | u64 mem_total, mem_free, mem; | ||
645 | int ret = -1; | ||
646 | |||
647 | sprintf(str, "/sys/devices/system/node/node%d/meminfo", node); | ||
648 | fp = fopen(str, "r"); | ||
649 | if (!fp) | ||
650 | return -1; | ||
651 | |||
652 | while (getline(&buf, &len, fp) > 0) { | ||
653 | /* skip over invalid lines */ | ||
654 | if (!strchr(buf, ':')) | ||
655 | continue; | ||
656 | if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2) | ||
657 | goto done; | ||
658 | if (!strcmp(field, "MemTotal:")) | ||
659 | mem_total = mem; | ||
660 | if (!strcmp(field, "MemFree:")) | ||
661 | mem_free = mem; | ||
662 | } | ||
663 | |||
664 | fclose(fp); | ||
665 | |||
666 | ret = do_write(fd, &mem_total, sizeof(u64)); | ||
667 | if (ret) | ||
668 | goto done; | ||
669 | |||
670 | ret = do_write(fd, &mem_free, sizeof(u64)); | ||
671 | if (ret) | ||
672 | goto done; | ||
673 | |||
674 | ret = -1; | ||
675 | sprintf(str, "/sys/devices/system/node/node%d/cpulist", node); | ||
676 | |||
677 | fp = fopen(str, "r"); | ||
678 | if (!fp) | ||
679 | goto done; | ||
680 | |||
681 | if (getline(&buf, &len, fp) <= 0) | ||
682 | goto done; | ||
683 | |||
684 | p = strchr(buf, '\n'); | ||
685 | if (p) | ||
686 | *p = '\0'; | ||
687 | |||
688 | ret = do_write_string(fd, buf); | ||
689 | done: | ||
690 | free(buf); | ||
691 | fclose(fp); | ||
692 | return ret; | ||
693 | } | ||
694 | |||
695 | static int write_numa_topology(int fd, struct perf_header *h __used, | ||
696 | struct perf_evlist *evlist __used) | ||
697 | { | ||
698 | char *buf = NULL; | ||
699 | size_t len = 0; | ||
700 | FILE *fp; | ||
701 | struct cpu_map *node_map = NULL; | ||
702 | char *c; | ||
703 | u32 nr, i, j; | ||
704 | int ret = -1; | ||
705 | |||
706 | fp = fopen("/sys/devices/system/node/online", "r"); | ||
707 | if (!fp) | ||
708 | return -1; | ||
709 | |||
710 | if (getline(&buf, &len, fp) <= 0) | ||
711 | goto done; | ||
712 | |||
713 | c = strchr(buf, '\n'); | ||
714 | if (c) | ||
715 | *c = '\0'; | ||
716 | |||
717 | node_map = cpu_map__new(buf); | ||
718 | if (!node_map) | ||
719 | goto done; | ||
720 | |||
721 | nr = (u32)node_map->nr; | ||
722 | |||
723 | ret = do_write(fd, &nr, sizeof(nr)); | ||
724 | if (ret < 0) | ||
725 | goto done; | ||
726 | |||
727 | for (i = 0; i < nr; i++) { | ||
728 | j = (u32)node_map->map[i]; | ||
729 | ret = do_write(fd, &j, sizeof(j)); | ||
730 | if (ret < 0) | ||
731 | break; | ||
732 | |||
733 | ret = write_topo_node(fd, i); | ||
734 | if (ret < 0) | ||
735 | break; | ||
736 | } | ||
737 | done: | ||
738 | free(buf); | ||
739 | fclose(fp); | ||
740 | free(node_map); | ||
741 | return ret; | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * default get_cpuid(): nothing gets recorded | ||
746 | * actual implementation must be in arch/$(ARCH)/util/header.c | ||
747 | */ | ||
748 | int __attribute__((weak)) get_cpuid(char *buffer __used, size_t sz __used) | ||
749 | { | ||
750 | return -1; | ||
751 | } | ||
752 | |||
753 | static int write_cpuid(int fd, struct perf_header *h __used, | ||
754 | struct perf_evlist *evlist __used) | ||
755 | { | ||
756 | char buffer[64]; | ||
757 | int ret; | ||
758 | |||
759 | ret = get_cpuid(buffer, sizeof(buffer)); | ||
760 | if (!ret) | ||
761 | goto write_it; | ||
762 | |||
763 | return -1; | ||
764 | write_it: | ||
765 | return do_write_string(fd, buffer); | ||
766 | } | ||
767 | |||
768 | static void print_hostname(struct perf_header *ph, int fd, FILE *fp) | ||
769 | { | ||
770 | char *str = do_read_string(fd, ph); | ||
771 | fprintf(fp, "# hostname : %s\n", str); | ||
772 | free(str); | ||
773 | } | ||
774 | |||
775 | static void print_osrelease(struct perf_header *ph, int fd, FILE *fp) | ||
776 | { | ||
777 | char *str = do_read_string(fd, ph); | ||
778 | fprintf(fp, "# os release : %s\n", str); | ||
779 | free(str); | ||
780 | } | ||
781 | |||
782 | static void print_arch(struct perf_header *ph, int fd, FILE *fp) | ||
783 | { | ||
784 | char *str = do_read_string(fd, ph); | ||
785 | fprintf(fp, "# arch : %s\n", str); | ||
786 | free(str); | ||
787 | } | ||
788 | |||
789 | static void print_cpudesc(struct perf_header *ph, int fd, FILE *fp) | ||
790 | { | ||
791 | char *str = do_read_string(fd, ph); | ||
792 | fprintf(fp, "# cpudesc : %s\n", str); | ||
793 | free(str); | ||
794 | } | ||
795 | |||
796 | static void print_nrcpus(struct perf_header *ph, int fd, FILE *fp) | ||
797 | { | ||
798 | ssize_t ret; | ||
799 | u32 nr; | ||
800 | |||
801 | ret = read(fd, &nr, sizeof(nr)); | ||
802 | if (ret != (ssize_t)sizeof(nr)) | ||
803 | nr = -1; /* interpreted as error */ | ||
804 | |||
805 | if (ph->needs_swap) | ||
806 | nr = bswap_32(nr); | ||
807 | |||
808 | fprintf(fp, "# nrcpus online : %u\n", nr); | ||
809 | |||
810 | ret = read(fd, &nr, sizeof(nr)); | ||
811 | if (ret != (ssize_t)sizeof(nr)) | ||
812 | nr = -1; /* interpreted as error */ | ||
813 | |||
814 | if (ph->needs_swap) | ||
815 | nr = bswap_32(nr); | ||
816 | |||
817 | fprintf(fp, "# nrcpus avail : %u\n", nr); | ||
818 | } | ||
819 | |||
820 | static void print_version(struct perf_header *ph, int fd, FILE *fp) | ||
821 | { | ||
822 | char *str = do_read_string(fd, ph); | ||
823 | fprintf(fp, "# perf version : %s\n", str); | ||
824 | free(str); | ||
825 | } | ||
826 | |||
827 | static void print_cmdline(struct perf_header *ph, int fd, FILE *fp) | ||
828 | { | ||
829 | ssize_t ret; | ||
830 | char *str; | ||
831 | u32 nr, i; | ||
832 | |||
833 | ret = read(fd, &nr, sizeof(nr)); | ||
834 | if (ret != (ssize_t)sizeof(nr)) | ||
835 | return; | ||
836 | |||
837 | if (ph->needs_swap) | ||
838 | nr = bswap_32(nr); | ||
839 | |||
840 | fprintf(fp, "# cmdline : "); | ||
841 | |||
842 | for (i = 0; i < nr; i++) { | ||
843 | str = do_read_string(fd, ph); | ||
844 | fprintf(fp, "%s ", str); | ||
845 | free(str); | ||
846 | } | ||
847 | fputc('\n', fp); | ||
848 | } | ||
849 | |||
850 | static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp) | ||
851 | { | ||
852 | ssize_t ret; | ||
853 | u32 nr, i; | ||
854 | char *str; | ||
855 | |||
856 | ret = read(fd, &nr, sizeof(nr)); | ||
857 | if (ret != (ssize_t)sizeof(nr)) | ||
858 | return; | ||
859 | |||
860 | if (ph->needs_swap) | ||
861 | nr = bswap_32(nr); | ||
862 | |||
863 | for (i = 0; i < nr; i++) { | ||
864 | str = do_read_string(fd, ph); | ||
865 | fprintf(fp, "# sibling cores : %s\n", str); | ||
866 | free(str); | ||
867 | } | ||
868 | |||
869 | ret = read(fd, &nr, sizeof(nr)); | ||
870 | if (ret != (ssize_t)sizeof(nr)) | ||
871 | return; | ||
872 | |||
873 | if (ph->needs_swap) | ||
874 | nr = bswap_32(nr); | ||
875 | |||
876 | for (i = 0; i < nr; i++) { | ||
877 | str = do_read_string(fd, ph); | ||
878 | fprintf(fp, "# sibling threads : %s\n", str); | ||
879 | free(str); | ||
880 | } | ||
881 | } | ||
882 | |||
883 | static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | ||
884 | { | ||
885 | struct perf_event_attr attr; | ||
886 | uint64_t id; | ||
887 | void *buf = NULL; | ||
888 | char *str; | ||
889 | u32 nre, sz, nr, i, j, msz; | ||
890 | int ret; | ||
891 | |||
892 | /* number of events */ | ||
893 | ret = read(fd, &nre, sizeof(nre)); | ||
894 | if (ret != (ssize_t)sizeof(nre)) | ||
895 | goto error; | ||
896 | |||
897 | if (ph->needs_swap) | ||
898 | nre = bswap_32(nre); | ||
899 | |||
900 | ret = read(fd, &sz, sizeof(sz)); | ||
901 | if (ret != (ssize_t)sizeof(sz)) | ||
902 | goto error; | ||
903 | |||
904 | if (ph->needs_swap) | ||
905 | sz = bswap_32(sz); | ||
906 | |||
907 | /* | ||
908 | * ensure it is at least to our ABI rev | ||
909 | */ | ||
910 | if (sz < (u32)sizeof(attr)) | ||
911 | goto error; | ||
912 | |||
913 | memset(&attr, 0, sizeof(attr)); | ||
914 | |||
915 | /* read entire region to sync up to next field */ | ||
916 | buf = malloc(sz); | ||
917 | if (!buf) | ||
918 | goto error; | ||
919 | |||
920 | msz = sizeof(attr); | ||
921 | if (sz < msz) | ||
922 | msz = sz; | ||
923 | |||
924 | for (i = 0 ; i < nre; i++) { | ||
925 | |||
926 | ret = read(fd, buf, sz); | ||
927 | if (ret != (ssize_t)sz) | ||
928 | goto error; | ||
929 | |||
930 | if (ph->needs_swap) | ||
931 | perf_event__attr_swap(buf); | ||
932 | |||
933 | memcpy(&attr, buf, msz); | ||
934 | |||
935 | ret = read(fd, &nr, sizeof(nr)); | ||
936 | if (ret != (ssize_t)sizeof(nr)) | ||
937 | goto error; | ||
938 | |||
939 | if (ph->needs_swap) | ||
940 | nr = bswap_32(nr); | ||
941 | |||
942 | str = do_read_string(fd, ph); | ||
943 | fprintf(fp, "# event : name = %s, ", str); | ||
944 | free(str); | ||
945 | |||
946 | fprintf(fp, "type = %d, config = 0x%"PRIx64 | ||
947 | ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64, | ||
948 | attr.type, | ||
949 | (u64)attr.config, | ||
950 | (u64)attr.config1, | ||
951 | (u64)attr.config2); | ||
952 | |||
953 | fprintf(fp, ", excl_usr = %d, excl_kern = %d", | ||
954 | attr.exclude_user, | ||
955 | attr.exclude_kernel); | ||
956 | |||
957 | if (nr) | ||
958 | fprintf(fp, ", id = {"); | ||
959 | |||
960 | for (j = 0 ; j < nr; j++) { | ||
961 | ret = read(fd, &id, sizeof(id)); | ||
962 | if (ret != (ssize_t)sizeof(id)) | ||
963 | goto error; | ||
964 | |||
965 | if (ph->needs_swap) | ||
966 | id = bswap_64(id); | ||
967 | |||
968 | if (j) | ||
969 | fputc(',', fp); | ||
970 | |||
971 | fprintf(fp, " %"PRIu64, id); | ||
972 | } | ||
973 | if (nr && j == nr) | ||
974 | fprintf(fp, " }"); | ||
975 | fputc('\n', fp); | ||
976 | } | ||
977 | free(buf); | ||
978 | return; | ||
979 | error: | ||
980 | fprintf(fp, "# event desc: not available or unable to read\n"); | ||
981 | } | ||
982 | |||
983 | static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp) | ||
984 | { | ||
985 | uint64_t mem; | ||
986 | ssize_t ret; | ||
987 | |||
988 | ret = read(fd, &mem, sizeof(mem)); | ||
989 | if (ret != sizeof(mem)) | ||
990 | goto error; | ||
991 | |||
992 | if (h->needs_swap) | ||
993 | mem = bswap_64(mem); | ||
994 | |||
995 | fprintf(fp, "# total memory : %"PRIu64" kB\n", mem); | ||
996 | return; | ||
997 | error: | ||
998 | fprintf(fp, "# total memory : unknown\n"); | ||
999 | } | ||
1000 | |||
1001 | static void print_numa_topology(struct perf_header *h __used, int fd, FILE *fp) | ||
1002 | { | ||
1003 | ssize_t ret; | ||
1004 | u32 nr, c, i; | ||
1005 | char *str; | ||
1006 | uint64_t mem_total, mem_free; | ||
1007 | |||
1008 | /* nr nodes */ | ||
1009 | ret = read(fd, &nr, sizeof(nr)); | ||
1010 | if (ret != (ssize_t)sizeof(nr)) | ||
1011 | goto error; | ||
1012 | |||
1013 | if (h->needs_swap) | ||
1014 | nr = bswap_32(nr); | ||
1015 | |||
1016 | for (i = 0; i < nr; i++) { | ||
1017 | |||
1018 | /* node number */ | ||
1019 | ret = read(fd, &c, sizeof(c)); | ||
1020 | if (ret != (ssize_t)sizeof(c)) | ||
1021 | goto error; | ||
1022 | |||
1023 | if (h->needs_swap) | ||
1024 | c = bswap_32(c); | ||
1025 | |||
1026 | ret = read(fd, &mem_total, sizeof(u64)); | ||
1027 | if (ret != sizeof(u64)) | ||
1028 | goto error; | ||
1029 | |||
1030 | ret = read(fd, &mem_free, sizeof(u64)); | ||
1031 | if (ret != sizeof(u64)) | ||
1032 | goto error; | ||
1033 | |||
1034 | if (h->needs_swap) { | ||
1035 | mem_total = bswap_64(mem_total); | ||
1036 | mem_free = bswap_64(mem_free); | ||
1037 | } | ||
1038 | |||
1039 | fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," | ||
1040 | " free = %"PRIu64" kB\n", | ||
1041 | c, | ||
1042 | mem_total, | ||
1043 | mem_free); | ||
1044 | |||
1045 | str = do_read_string(fd, h); | ||
1046 | fprintf(fp, "# node%u cpu list : %s\n", c, str); | ||
1047 | free(str); | ||
1048 | } | ||
1049 | return; | ||
1050 | error: | ||
1051 | fprintf(fp, "# numa topology : not available\n"); | ||
1052 | } | ||
1053 | |||
1054 | static void print_cpuid(struct perf_header *ph, int fd, FILE *fp) | ||
1055 | { | ||
1056 | char *str = do_read_string(fd, ph); | ||
1057 | fprintf(fp, "# cpuid : %s\n", str); | ||
1058 | free(str); | ||
1059 | } | ||
1060 | |||
1061 | struct feature_ops { | ||
1062 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | ||
1063 | void (*print)(struct perf_header *h, int fd, FILE *fp); | ||
1064 | const char *name; | ||
1065 | bool full_only; | ||
1066 | }; | ||
1067 | |||
1068 | #define FEAT_OPA(n, w, p) \ | ||
1069 | [n] = { .name = #n, .write = w, .print = p } | ||
1070 | #define FEAT_OPF(n, w, p) \ | ||
1071 | [n] = { .name = #n, .write = w, .print = p, .full_only = true } | ||
1072 | |||
1073 | static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | ||
1074 | FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL), | ||
1075 | FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL), | ||
1076 | FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname), | ||
1077 | FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease), | ||
1078 | FEAT_OPA(HEADER_VERSION, write_version, print_version), | ||
1079 | FEAT_OPA(HEADER_ARCH, write_arch, print_arch), | ||
1080 | FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus), | ||
1081 | FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc), | ||
1082 | FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid), | ||
1083 | FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem), | ||
1084 | FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc), | ||
1085 | FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline), | ||
1086 | FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology), | ||
1087 | FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology), | ||
1088 | }; | ||
1089 | |||
1090 | struct header_print_data { | ||
1091 | FILE *fp; | ||
1092 | bool full; /* extended list of headers */ | ||
1093 | }; | ||
1094 | |||
1095 | static int perf_file_section__fprintf_info(struct perf_file_section *section, | ||
1096 | struct perf_header *ph, | ||
1097 | int feat, int fd, void *data) | ||
1098 | { | ||
1099 | struct header_print_data *hd = data; | ||
1100 | |||
1101 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { | ||
1102 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " | ||
1103 | "%d, continuing...\n", section->offset, feat); | ||
1104 | return 0; | ||
1105 | } | ||
1106 | if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { | ||
1107 | pr_warning("unknown feature %d\n", feat); | ||
1108 | return -1; | ||
1109 | } | ||
1110 | if (!feat_ops[feat].print) | ||
1111 | return 0; | ||
1112 | |||
1113 | if (!feat_ops[feat].full_only || hd->full) | ||
1114 | feat_ops[feat].print(ph, fd, hd->fp); | ||
1115 | else | ||
1116 | fprintf(hd->fp, "# %s info available, use -I to display\n", | ||
1117 | feat_ops[feat].name); | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) | ||
1123 | { | ||
1124 | struct header_print_data hd; | ||
1125 | struct perf_header *header = &session->header; | ||
1126 | int fd = session->fd; | ||
1127 | hd.fp = fp; | ||
1128 | hd.full = full; | ||
1129 | |||
1130 | perf_header__process_sections(header, fd, &hd, | ||
1131 | perf_file_section__fprintf_info); | ||
1132 | return 0; | ||
1133 | } | ||
1134 | |||
113 | #define dsos__for_each_with_build_id(pos, head) \ | 1135 | #define dsos__for_each_with_build_id(pos, head) \ |
114 | list_for_each_entry(pos, head, node) \ | 1136 | list_for_each_entry(pos, head, node) \ |
115 | if (!pos->has_build_id) \ | 1137 | if (!pos->has_build_id) \ |
@@ -189,8 +1211,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
189 | const char *name, bool is_kallsyms) | 1211 | const char *name, bool is_kallsyms) |
190 | { | 1212 | { |
191 | const size_t size = PATH_MAX; | 1213 | const size_t size = PATH_MAX; |
192 | char *realname, *filename = malloc(size), | 1214 | char *realname, *filename = zalloc(size), |
193 | *linkname = malloc(size), *targetname; | 1215 | *linkname = zalloc(size), *targetname; |
194 | int len, err = -1; | 1216 | int len, err = -1; |
195 | 1217 | ||
196 | if (is_kallsyms) { | 1218 | if (is_kallsyms) { |
@@ -254,8 +1276,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, | |||
254 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | 1276 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) |
255 | { | 1277 | { |
256 | const size_t size = PATH_MAX; | 1278 | const size_t size = PATH_MAX; |
257 | char *filename = malloc(size), | 1279 | char *filename = zalloc(size), |
258 | *linkname = malloc(size); | 1280 | *linkname = zalloc(size); |
259 | int err = -1; | 1281 | int err = -1; |
260 | 1282 | ||
261 | if (filename == NULL || linkname == NULL) | 1283 | if (filename == NULL || linkname == NULL) |
@@ -267,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | |||
267 | if (access(linkname, F_OK)) | 1289 | if (access(linkname, F_OK)) |
268 | goto out_free; | 1290 | goto out_free; |
269 | 1291 | ||
270 | if (readlink(linkname, filename, size) < 0) | 1292 | if (readlink(linkname, filename, size - 1) < 0) |
271 | goto out_free; | 1293 | goto out_free; |
272 | 1294 | ||
273 | if (unlink(linkname)) | 1295 | if (unlink(linkname)) |
@@ -356,15 +1378,41 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with | |||
356 | return ret; | 1378 | return ret; |
357 | } | 1379 | } |
358 | 1380 | ||
1381 | static int do_write_feat(int fd, struct perf_header *h, int type, | ||
1382 | struct perf_file_section **p, | ||
1383 | struct perf_evlist *evlist) | ||
1384 | { | ||
1385 | int err; | ||
1386 | int ret = 0; | ||
1387 | |||
1388 | if (perf_header__has_feat(h, type)) { | ||
1389 | |||
1390 | (*p)->offset = lseek(fd, 0, SEEK_CUR); | ||
1391 | |||
1392 | err = feat_ops[type].write(fd, h, evlist); | ||
1393 | if (err < 0) { | ||
1394 | pr_debug("failed to write feature %d\n", type); | ||
1395 | |||
1396 | /* undo anything written */ | ||
1397 | lseek(fd, (*p)->offset, SEEK_SET); | ||
1398 | |||
1399 | return -1; | ||
1400 | } | ||
1401 | (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset; | ||
1402 | (*p)++; | ||
1403 | } | ||
1404 | return ret; | ||
1405 | } | ||
1406 | |||
359 | static int perf_header__adds_write(struct perf_header *header, | 1407 | static int perf_header__adds_write(struct perf_header *header, |
360 | struct perf_evlist *evlist, int fd) | 1408 | struct perf_evlist *evlist, int fd) |
361 | { | 1409 | { |
362 | int nr_sections; | 1410 | int nr_sections; |
363 | struct perf_session *session; | 1411 | struct perf_session *session; |
364 | struct perf_file_section *feat_sec; | 1412 | struct perf_file_section *feat_sec, *p; |
365 | int sec_size; | 1413 | int sec_size; |
366 | u64 sec_start; | 1414 | u64 sec_start; |
367 | int idx = 0, err; | 1415 | int err; |
368 | 1416 | ||
369 | session = container_of(header, struct perf_session, header); | 1417 | session = container_of(header, struct perf_session, header); |
370 | 1418 | ||
@@ -376,7 +1424,7 @@ static int perf_header__adds_write(struct perf_header *header, | |||
376 | if (!nr_sections) | 1424 | if (!nr_sections) |
377 | return 0; | 1425 | return 0; |
378 | 1426 | ||
379 | feat_sec = calloc(sizeof(*feat_sec), nr_sections); | 1427 | feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); |
380 | if (feat_sec == NULL) | 1428 | if (feat_sec == NULL) |
381 | return -ENOMEM; | 1429 | return -ENOMEM; |
382 | 1430 | ||
@@ -385,36 +1433,69 @@ static int perf_header__adds_write(struct perf_header *header, | |||
385 | sec_start = header->data_offset + header->data_size; | 1433 | sec_start = header->data_offset + header->data_size; |
386 | lseek(fd, sec_start + sec_size, SEEK_SET); | 1434 | lseek(fd, sec_start + sec_size, SEEK_SET); |
387 | 1435 | ||
388 | if (perf_header__has_feat(header, HEADER_TRACE_INFO)) { | 1436 | err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); |
389 | struct perf_file_section *trace_sec; | 1437 | if (err) |
390 | 1438 | goto out_free; | |
391 | trace_sec = &feat_sec[idx++]; | ||
392 | 1439 | ||
393 | /* Write trace info */ | 1440 | err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist); |
394 | trace_sec->offset = lseek(fd, 0, SEEK_CUR); | 1441 | if (err) { |
395 | read_tracing_data(fd, &evlist->entries); | 1442 | perf_header__clear_feat(header, HEADER_BUILD_ID); |
396 | trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; | 1443 | goto out_free; |
397 | } | 1444 | } |
398 | 1445 | ||
399 | if (perf_header__has_feat(header, HEADER_BUILD_ID)) { | 1446 | err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist); |
400 | struct perf_file_section *buildid_sec; | 1447 | if (err) |
1448 | perf_header__clear_feat(header, HEADER_HOSTNAME); | ||
401 | 1449 | ||
402 | buildid_sec = &feat_sec[idx++]; | 1450 | err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist); |
1451 | if (err) | ||
1452 | perf_header__clear_feat(header, HEADER_OSRELEASE); | ||
403 | 1453 | ||
404 | /* Write build-ids */ | 1454 | err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist); |
405 | buildid_sec->offset = lseek(fd, 0, SEEK_CUR); | 1455 | if (err) |
406 | err = dsos__write_buildid_table(header, fd); | 1456 | perf_header__clear_feat(header, HEADER_VERSION); |
407 | if (err < 0) { | 1457 | |
408 | pr_debug("failed to write buildid table\n"); | 1458 | err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist); |
409 | goto out_free; | 1459 | if (err) |
410 | } | 1460 | perf_header__clear_feat(header, HEADER_ARCH); |
411 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - | 1461 | |
412 | buildid_sec->offset; | 1462 | err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist); |
413 | if (!no_buildid_cache) | 1463 | if (err) |
414 | perf_session__cache_build_ids(session); | 1464 | perf_header__clear_feat(header, HEADER_NRCPUS); |
415 | } | 1465 | |
1466 | err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist); | ||
1467 | if (err) | ||
1468 | perf_header__clear_feat(header, HEADER_CPUDESC); | ||
1469 | |||
1470 | err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist); | ||
1471 | if (err) | ||
1472 | perf_header__clear_feat(header, HEADER_CPUID); | ||
1473 | |||
1474 | err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist); | ||
1475 | if (err) | ||
1476 | perf_header__clear_feat(header, HEADER_TOTAL_MEM); | ||
1477 | |||
1478 | err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist); | ||
1479 | if (err) | ||
1480 | perf_header__clear_feat(header, HEADER_CMDLINE); | ||
1481 | |||
1482 | err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist); | ||
1483 | if (err) | ||
1484 | perf_header__clear_feat(header, HEADER_EVENT_DESC); | ||
1485 | |||
1486 | err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist); | ||
1487 | if (err) | ||
1488 | perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY); | ||
1489 | |||
1490 | err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist); | ||
1491 | if (err) | ||
1492 | perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY); | ||
416 | 1493 | ||
417 | lseek(fd, sec_start, SEEK_SET); | 1494 | lseek(fd, sec_start, SEEK_SET); |
1495 | /* | ||
1496 | * may write more than needed due to dropped feature, but | ||
1497 | * this is okay, reader will skip the mising entries | ||
1498 | */ | ||
418 | err = do_write(fd, feat_sec, sec_size); | 1499 | err = do_write(fd, feat_sec, sec_size); |
419 | if (err < 0) | 1500 | if (err < 0) |
420 | pr_debug("failed to write feature section\n"); | 1501 | pr_debug("failed to write feature section\n"); |
@@ -554,9 +1635,10 @@ static int perf_header__getbuffer64(struct perf_header *header, | |||
554 | } | 1635 | } |
555 | 1636 | ||
556 | int perf_header__process_sections(struct perf_header *header, int fd, | 1637 | int perf_header__process_sections(struct perf_header *header, int fd, |
1638 | void *data, | ||
557 | int (*process)(struct perf_file_section *section, | 1639 | int (*process)(struct perf_file_section *section, |
558 | struct perf_header *ph, | 1640 | struct perf_header *ph, |
559 | int feat, int fd)) | 1641 | int feat, int fd, void *data)) |
560 | { | 1642 | { |
561 | struct perf_file_section *feat_sec; | 1643 | struct perf_file_section *feat_sec; |
562 | int nr_sections; | 1644 | int nr_sections; |
@@ -584,7 +1666,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, | |||
584 | if (perf_header__has_feat(header, feat)) { | 1666 | if (perf_header__has_feat(header, feat)) { |
585 | struct perf_file_section *sec = &feat_sec[idx++]; | 1667 | struct perf_file_section *sec = &feat_sec[idx++]; |
586 | 1668 | ||
587 | err = process(sec, header, feat, fd); | 1669 | err = process(sec, header, feat, fd, data); |
588 | if (err < 0) | 1670 | if (err < 0) |
589 | break; | 1671 | break; |
590 | } | 1672 | } |
@@ -621,21 +1703,41 @@ int perf_file_header__read(struct perf_file_header *header, | |||
621 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); | 1703 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); |
622 | else | 1704 | else |
623 | return -1; | 1705 | return -1; |
1706 | } else if (ph->needs_swap) { | ||
1707 | unsigned int i; | ||
1708 | /* | ||
1709 | * feature bitmap is declared as an array of unsigned longs -- | ||
1710 | * not good since its size can differ between the host that | ||
1711 | * generated the data file and the host analyzing the file. | ||
1712 | * | ||
1713 | * We need to handle endianness, but we don't know the size of | ||
1714 | * the unsigned long where the file was generated. Take a best | ||
1715 | * guess at determining it: try 64-bit swap first (ie., file | ||
1716 | * created on a 64-bit host), and check if the hostname feature | ||
1717 | * bit is set (this feature bit is forced on as of fbe96f2). | ||
1718 | * If the bit is not, undo the 64-bit swap and try a 32-bit | ||
1719 | * swap. If the hostname bit is still not set (e.g., older data | ||
1720 | * file), punt and fallback to the original behavior -- | ||
1721 | * clearing all feature bits and setting buildid. | ||
1722 | */ | ||
1723 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) | ||
1724 | header->adds_features[i] = bswap_64(header->adds_features[i]); | ||
1725 | |||
1726 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | ||
1727 | for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) { | ||
1728 | header->adds_features[i] = bswap_64(header->adds_features[i]); | ||
1729 | header->adds_features[i] = bswap_32(header->adds_features[i]); | ||
1730 | } | ||
1731 | } | ||
1732 | |||
1733 | if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { | ||
1734 | bitmap_zero(header->adds_features, HEADER_FEAT_BITS); | ||
1735 | set_bit(HEADER_BUILD_ID, header->adds_features); | ||
1736 | } | ||
624 | } | 1737 | } |
625 | 1738 | ||
626 | memcpy(&ph->adds_features, &header->adds_features, | 1739 | memcpy(&ph->adds_features, &header->adds_features, |
627 | sizeof(ph->adds_features)); | 1740 | sizeof(ph->adds_features)); |
628 | /* | ||
629 | * FIXME: hack that assumes that if we need swap the perf.data file | ||
630 | * may be coming from an arch with a different word-size, ergo different | ||
631 | * DEFINE_BITMAP format, investigate more later, but for now its mostly | ||
632 | * safe to assume that we have a build-id section. Trace files probably | ||
633 | * have several other issues in this realm anyway... | ||
634 | */ | ||
635 | if (ph->needs_swap) { | ||
636 | memset(&ph->adds_features, 0, sizeof(ph->adds_features)); | ||
637 | perf_header__set_feat(ph, HEADER_BUILD_ID); | ||
638 | } | ||
639 | 1741 | ||
640 | ph->event_offset = header->event_types.offset; | 1742 | ph->event_offset = header->event_types.offset; |
641 | ph->event_size = header->event_types.size; | 1743 | ph->event_size = header->event_types.size; |
@@ -726,7 +1828,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
726 | return -1; | 1828 | return -1; |
727 | 1829 | ||
728 | bev.header = old_bev.header; | 1830 | bev.header = old_bev.header; |
729 | bev.pid = 0; | 1831 | |
1832 | /* | ||
1833 | * As the pid is the missing value, we need to fill | ||
1834 | * it properly. The header.misc value give us nice hint. | ||
1835 | */ | ||
1836 | bev.pid = HOST_KERNEL_ID; | ||
1837 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
1838 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
1839 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
1840 | |||
730 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | 1841 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); |
731 | __event_process_build_id(&bev, filename, session); | 1842 | __event_process_build_id(&bev, filename, session); |
732 | 1843 | ||
@@ -787,7 +1898,7 @@ out: | |||
787 | 1898 | ||
788 | static int perf_file_section__process(struct perf_file_section *section, | 1899 | static int perf_file_section__process(struct perf_file_section *section, |
789 | struct perf_header *ph, | 1900 | struct perf_header *ph, |
790 | int feat, int fd) | 1901 | int feat, int fd, void *data __used) |
791 | { | 1902 | { |
792 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { | 1903 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { |
793 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " | 1904 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " |
@@ -804,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section, | |||
804 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) | 1915 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
805 | pr_debug("Failed to read buildids, continuing...\n"); | 1916 | pr_debug("Failed to read buildids, continuing...\n"); |
806 | break; | 1917 | break; |
1918 | |||
1919 | case HEADER_HOSTNAME: | ||
1920 | case HEADER_OSRELEASE: | ||
1921 | case HEADER_VERSION: | ||
1922 | case HEADER_ARCH: | ||
1923 | case HEADER_NRCPUS: | ||
1924 | case HEADER_CPUDESC: | ||
1925 | case HEADER_CPUID: | ||
1926 | case HEADER_TOTAL_MEM: | ||
1927 | case HEADER_CMDLINE: | ||
1928 | case HEADER_EVENT_DESC: | ||
1929 | case HEADER_CPU_TOPOLOGY: | ||
1930 | case HEADER_NUMA_TOPOLOGY: | ||
1931 | break; | ||
1932 | |||
807 | default: | 1933 | default: |
808 | pr_debug("unknown feature %d, continuing...\n", feat); | 1934 | pr_debug("unknown feature %d, continuing...\n", feat); |
809 | } | 1935 | } |
@@ -926,7 +2052,8 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
926 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 2052 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
927 | } | 2053 | } |
928 | 2054 | ||
929 | perf_header__process_sections(header, fd, perf_file_section__process); | 2055 | perf_header__process_sections(header, fd, NULL, |
2056 | perf_file_section__process); | ||
930 | 2057 | ||
931 | lseek(fd, header->data_offset, SEEK_SET); | 2058 | lseek(fd, header->data_offset, SEEK_SET); |
932 | 2059 | ||
@@ -1091,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, | |||
1091 | struct perf_session *session __unused) | 2218 | struct perf_session *session __unused) |
1092 | { | 2219 | { |
1093 | union perf_event ev; | 2220 | union perf_event ev; |
2221 | struct tracing_data *tdata; | ||
1094 | ssize_t size = 0, aligned_size = 0, padding; | 2222 | ssize_t size = 0, aligned_size = 0, padding; |
1095 | int err __used = 0; | 2223 | int err __used = 0; |
1096 | 2224 | ||
2225 | /* | ||
2226 | * We are going to store the size of the data followed | ||
2227 | * by the data contents. Since the fd descriptor is a pipe, | ||
2228 | * we cannot seek back to store the size of the data once | ||
2229 | * we know it. Instead we: | ||
2230 | * | ||
2231 | * - write the tracing data to the temp file | ||
2232 | * - get/write the data size to pipe | ||
2233 | * - write the tracing data from the temp file | ||
2234 | * to the pipe | ||
2235 | */ | ||
2236 | tdata = tracing_data_get(&evlist->entries, fd, true); | ||
2237 | if (!tdata) | ||
2238 | return -1; | ||
2239 | |||
1097 | memset(&ev, 0, sizeof(ev)); | 2240 | memset(&ev, 0, sizeof(ev)); |
1098 | 2241 | ||
1099 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | 2242 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; |
1100 | size = read_tracing_data_size(fd, &evlist->entries); | 2243 | size = tdata->size; |
1101 | if (size <= 0) | ||
1102 | return size; | ||
1103 | aligned_size = ALIGN(size, sizeof(u64)); | 2244 | aligned_size = ALIGN(size, sizeof(u64)); |
1104 | padding = aligned_size - size; | 2245 | padding = aligned_size - size; |
1105 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | 2246 | ev.tracing_data.header.size = sizeof(ev.tracing_data); |
@@ -1107,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, | |||
1107 | 2248 | ||
1108 | process(&ev, NULL, session); | 2249 | process(&ev, NULL, session); |
1109 | 2250 | ||
1110 | err = read_tracing_data(fd, &evlist->entries); | 2251 | /* |
2252 | * The put function will copy all the tracing data | ||
2253 | * stored in temp file to the pipe. | ||
2254 | */ | ||
2255 | tracing_data_put(tdata); | ||
2256 | |||
1111 | write_padded(fd, NULL, 0, padding); | 2257 | write_padded(fd, NULL, 0, padding); |
1112 | 2258 | ||
1113 | return aligned_size; | 2259 | return aligned_size; |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 1886256768a1..3d5a742f4a2a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -12,6 +12,20 @@ | |||
12 | enum { | 12 | enum { |
13 | HEADER_TRACE_INFO = 1, | 13 | HEADER_TRACE_INFO = 1, |
14 | HEADER_BUILD_ID, | 14 | HEADER_BUILD_ID, |
15 | |||
16 | HEADER_HOSTNAME, | ||
17 | HEADER_OSRELEASE, | ||
18 | HEADER_VERSION, | ||
19 | HEADER_ARCH, | ||
20 | HEADER_NRCPUS, | ||
21 | HEADER_CPUDESC, | ||
22 | HEADER_CPUID, | ||
23 | HEADER_TOTAL_MEM, | ||
24 | HEADER_CMDLINE, | ||
25 | HEADER_EVENT_DESC, | ||
26 | HEADER_CPU_TOPOLOGY, | ||
27 | HEADER_NUMA_TOPOLOGY, | ||
28 | |||
15 | HEADER_LAST_FEATURE, | 29 | HEADER_LAST_FEATURE, |
16 | }; | 30 | }; |
17 | 31 | ||
@@ -68,10 +82,15 @@ void perf_header__set_feat(struct perf_header *header, int feat); | |||
68 | void perf_header__clear_feat(struct perf_header *header, int feat); | 82 | void perf_header__clear_feat(struct perf_header *header, int feat); |
69 | bool perf_header__has_feat(const struct perf_header *header, int feat); | 83 | bool perf_header__has_feat(const struct perf_header *header, int feat); |
70 | 84 | ||
85 | int perf_header__set_cmdline(int argc, const char **argv); | ||
86 | |||
71 | int perf_header__process_sections(struct perf_header *header, int fd, | 87 | int perf_header__process_sections(struct perf_header *header, int fd, |
88 | void *data, | ||
72 | int (*process)(struct perf_file_section *section, | 89 | int (*process)(struct perf_file_section *section, |
73 | struct perf_header *ph, | 90 | struct perf_header *ph, |
74 | int feat, int fd)); | 91 | int feat, int fd, void *data)); |
92 | |||
93 | int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); | ||
75 | 94 | ||
76 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | 95 | int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, |
77 | const char *name, bool is_kallsyms); | 96 | const char *name, bool is_kallsyms); |
@@ -104,4 +123,10 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc, | |||
104 | struct perf_session *session); | 123 | struct perf_session *session); |
105 | int perf_event__process_build_id(union perf_event *event, | 124 | int perf_event__process_build_id(union perf_event *event, |
106 | struct perf_session *session); | 125 | struct perf_session *session); |
126 | |||
127 | /* | ||
128 | * arch specific callback | ||
129 | */ | ||
130 | int get_cpuid(char *buffer, size_t sz); | ||
131 | |||
107 | #endif /* __PERF_HEADER_H */ | 132 | #endif /* __PERF_HEADER_H */ |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 677e1da6bb3e..a36a3fa81ffb 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -6,6 +6,11 @@ | |||
6 | #include "sort.h" | 6 | #include "sort.h" |
7 | #include <math.h> | 7 | #include <math.h> |
8 | 8 | ||
9 | static bool hists__filter_entry_by_dso(struct hists *hists, | ||
10 | struct hist_entry *he); | ||
11 | static bool hists__filter_entry_by_thread(struct hists *hists, | ||
12 | struct hist_entry *he); | ||
13 | |||
9 | enum hist_filter { | 14 | enum hist_filter { |
10 | HIST_FILTER__DSO, | 15 | HIST_FILTER__DSO, |
11 | HIST_FILTER__THREAD, | 16 | HIST_FILTER__THREAD, |
@@ -18,56 +23,56 @@ struct callchain_param callchain_param = { | |||
18 | .order = ORDER_CALLEE | 23 | .order = ORDER_CALLEE |
19 | }; | 24 | }; |
20 | 25 | ||
21 | u16 hists__col_len(struct hists *self, enum hist_column col) | 26 | u16 hists__col_len(struct hists *hists, enum hist_column col) |
22 | { | 27 | { |
23 | return self->col_len[col]; | 28 | return hists->col_len[col]; |
24 | } | 29 | } |
25 | 30 | ||
26 | void hists__set_col_len(struct hists *self, enum hist_column col, u16 len) | 31 | void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len) |
27 | { | 32 | { |
28 | self->col_len[col] = len; | 33 | hists->col_len[col] = len; |
29 | } | 34 | } |
30 | 35 | ||
31 | bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len) | 36 | bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len) |
32 | { | 37 | { |
33 | if (len > hists__col_len(self, col)) { | 38 | if (len > hists__col_len(hists, col)) { |
34 | hists__set_col_len(self, col, len); | 39 | hists__set_col_len(hists, col, len); |
35 | return true; | 40 | return true; |
36 | } | 41 | } |
37 | return false; | 42 | return false; |
38 | } | 43 | } |
39 | 44 | ||
40 | static void hists__reset_col_len(struct hists *self) | 45 | static void hists__reset_col_len(struct hists *hists) |
41 | { | 46 | { |
42 | enum hist_column col; | 47 | enum hist_column col; |
43 | 48 | ||
44 | for (col = 0; col < HISTC_NR_COLS; ++col) | 49 | for (col = 0; col < HISTC_NR_COLS; ++col) |
45 | hists__set_col_len(self, col, 0); | 50 | hists__set_col_len(hists, col, 0); |
46 | } | 51 | } |
47 | 52 | ||
48 | static void hists__calc_col_len(struct hists *self, struct hist_entry *h) | 53 | static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) |
49 | { | 54 | { |
50 | u16 len; | 55 | u16 len; |
51 | 56 | ||
52 | if (h->ms.sym) | 57 | if (h->ms.sym) |
53 | hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen); | 58 | hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen); |
54 | else { | 59 | else { |
55 | const unsigned int unresolved_col_width = BITS_PER_LONG / 4; | 60 | const unsigned int unresolved_col_width = BITS_PER_LONG / 4; |
56 | 61 | ||
57 | if (hists__col_len(self, HISTC_DSO) < unresolved_col_width && | 62 | if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width && |
58 | !symbol_conf.col_width_list_str && !symbol_conf.field_sep && | 63 | !symbol_conf.col_width_list_str && !symbol_conf.field_sep && |
59 | !symbol_conf.dso_list) | 64 | !symbol_conf.dso_list) |
60 | hists__set_col_len(self, HISTC_DSO, | 65 | hists__set_col_len(hists, HISTC_DSO, |
61 | unresolved_col_width); | 66 | unresolved_col_width); |
62 | } | 67 | } |
63 | 68 | ||
64 | len = thread__comm_len(h->thread); | 69 | len = thread__comm_len(h->thread); |
65 | if (hists__new_col_len(self, HISTC_COMM, len)) | 70 | if (hists__new_col_len(hists, HISTC_COMM, len)) |
66 | hists__set_col_len(self, HISTC_THREAD, len + 6); | 71 | hists__set_col_len(hists, HISTC_THREAD, len + 6); |
67 | 72 | ||
68 | if (h->ms.map) { | 73 | if (h->ms.map) { |
69 | len = dso__name_len(h->ms.map->dso); | 74 | len = dso__name_len(h->ms.map->dso); |
70 | hists__new_col_len(self, HISTC_DSO, len); | 75 | hists__new_col_len(hists, HISTC_DSO, len); |
71 | } | 76 | } |
72 | } | 77 | } |
73 | 78 | ||
@@ -92,6 +97,67 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self, | |||
92 | } | 97 | } |
93 | } | 98 | } |
94 | 99 | ||
100 | static void hist_entry__decay(struct hist_entry *he) | ||
101 | { | ||
102 | he->period = (he->period * 7) / 8; | ||
103 | he->nr_events = (he->nr_events * 7) / 8; | ||
104 | } | ||
105 | |||
106 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | ||
107 | { | ||
108 | u64 prev_period = he->period; | ||
109 | |||
110 | if (prev_period == 0) | ||
111 | return true; | ||
112 | |||
113 | hist_entry__decay(he); | ||
114 | |||
115 | if (!he->filtered) | ||
116 | hists->stats.total_period -= prev_period - he->period; | ||
117 | |||
118 | return he->period == 0; | ||
119 | } | ||
120 | |||
121 | static void __hists__decay_entries(struct hists *hists, bool zap_user, | ||
122 | bool zap_kernel, bool threaded) | ||
123 | { | ||
124 | struct rb_node *next = rb_first(&hists->entries); | ||
125 | struct hist_entry *n; | ||
126 | |||
127 | while (next) { | ||
128 | n = rb_entry(next, struct hist_entry, rb_node); | ||
129 | next = rb_next(&n->rb_node); | ||
130 | /* | ||
131 | * We may be annotating this, for instance, so keep it here in | ||
132 | * case some it gets new samples, we'll eventually free it when | ||
133 | * the user stops browsing and it agains gets fully decayed. | ||
134 | */ | ||
135 | if (((zap_user && n->level == '.') || | ||
136 | (zap_kernel && n->level != '.') || | ||
137 | hists__decay_entry(hists, n)) && | ||
138 | !n->used) { | ||
139 | rb_erase(&n->rb_node, &hists->entries); | ||
140 | |||
141 | if (sort__need_collapse || threaded) | ||
142 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | ||
143 | |||
144 | hist_entry__free(n); | ||
145 | --hists->nr_entries; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | ||
151 | { | ||
152 | return __hists__decay_entries(hists, zap_user, zap_kernel, false); | ||
153 | } | ||
154 | |||
155 | void hists__decay_entries_threaded(struct hists *hists, | ||
156 | bool zap_user, bool zap_kernel) | ||
157 | { | ||
158 | return __hists__decay_entries(hists, zap_user, zap_kernel, true); | ||
159 | } | ||
160 | |||
95 | /* | 161 | /* |
96 | * histogram, sorted on item, collects periods | 162 | * histogram, sorted on item, collects periods |
97 | */ | 163 | */ |
@@ -113,11 +179,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
113 | return self; | 179 | return self; |
114 | } | 180 | } |
115 | 181 | ||
116 | static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h) | 182 | static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) |
117 | { | 183 | { |
118 | if (!h->filtered) { | 184 | if (!h->filtered) { |
119 | hists__calc_col_len(self, h); | 185 | hists__calc_col_len(hists, h); |
120 | ++self->nr_entries; | 186 | ++hists->nr_entries; |
187 | hists->stats.total_period += h->period; | ||
121 | } | 188 | } |
122 | } | 189 | } |
123 | 190 | ||
@@ -128,11 +195,11 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
128 | return 0; | 195 | return 0; |
129 | } | 196 | } |
130 | 197 | ||
131 | struct hist_entry *__hists__add_entry(struct hists *self, | 198 | struct hist_entry *__hists__add_entry(struct hists *hists, |
132 | struct addr_location *al, | 199 | struct addr_location *al, |
133 | struct symbol *sym_parent, u64 period) | 200 | struct symbol *sym_parent, u64 period) |
134 | { | 201 | { |
135 | struct rb_node **p = &self->entries.rb_node; | 202 | struct rb_node **p; |
136 | struct rb_node *parent = NULL; | 203 | struct rb_node *parent = NULL; |
137 | struct hist_entry *he; | 204 | struct hist_entry *he; |
138 | struct hist_entry entry = { | 205 | struct hist_entry entry = { |
@@ -150,9 +217,13 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
150 | }; | 217 | }; |
151 | int cmp; | 218 | int cmp; |
152 | 219 | ||
220 | pthread_mutex_lock(&hists->lock); | ||
221 | |||
222 | p = &hists->entries_in->rb_node; | ||
223 | |||
153 | while (*p != NULL) { | 224 | while (*p != NULL) { |
154 | parent = *p; | 225 | parent = *p; |
155 | he = rb_entry(parent, struct hist_entry, rb_node); | 226 | he = rb_entry(parent, struct hist_entry, rb_node_in); |
156 | 227 | ||
157 | cmp = hist_entry__cmp(&entry, he); | 228 | cmp = hist_entry__cmp(&entry, he); |
158 | 229 | ||
@@ -170,12 +241,14 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
170 | 241 | ||
171 | he = hist_entry__new(&entry); | 242 | he = hist_entry__new(&entry); |
172 | if (!he) | 243 | if (!he) |
173 | return NULL; | 244 | goto out_unlock; |
174 | rb_link_node(&he->rb_node, parent, p); | 245 | |
175 | rb_insert_color(&he->rb_node, &self->entries); | 246 | rb_link_node(&he->rb_node_in, parent, p); |
176 | hists__inc_nr_entries(self, he); | 247 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
177 | out: | 248 | out: |
178 | hist_entry__add_cpumode_period(he, al->cpumode, period); | 249 | hist_entry__add_cpumode_period(he, al->cpumode, period); |
250 | out_unlock: | ||
251 | pthread_mutex_unlock(&hists->lock); | ||
179 | return he; | 252 | return he; |
180 | } | 253 | } |
181 | 254 | ||
@@ -222,7 +295,7 @@ void hist_entry__free(struct hist_entry *he) | |||
222 | * collapse the histogram | 295 | * collapse the histogram |
223 | */ | 296 | */ |
224 | 297 | ||
225 | static bool hists__collapse_insert_entry(struct hists *self, | 298 | static bool hists__collapse_insert_entry(struct hists *hists, |
226 | struct rb_root *root, | 299 | struct rb_root *root, |
227 | struct hist_entry *he) | 300 | struct hist_entry *he) |
228 | { | 301 | { |
@@ -233,15 +306,16 @@ static bool hists__collapse_insert_entry(struct hists *self, | |||
233 | 306 | ||
234 | while (*p != NULL) { | 307 | while (*p != NULL) { |
235 | parent = *p; | 308 | parent = *p; |
236 | iter = rb_entry(parent, struct hist_entry, rb_node); | 309 | iter = rb_entry(parent, struct hist_entry, rb_node_in); |
237 | 310 | ||
238 | cmp = hist_entry__collapse(iter, he); | 311 | cmp = hist_entry__collapse(iter, he); |
239 | 312 | ||
240 | if (!cmp) { | 313 | if (!cmp) { |
241 | iter->period += he->period; | 314 | iter->period += he->period; |
315 | iter->nr_events += he->nr_events; | ||
242 | if (symbol_conf.use_callchain) { | 316 | if (symbol_conf.use_callchain) { |
243 | callchain_cursor_reset(&self->callchain_cursor); | 317 | callchain_cursor_reset(&hists->callchain_cursor); |
244 | callchain_merge(&self->callchain_cursor, iter->callchain, | 318 | callchain_merge(&hists->callchain_cursor, iter->callchain, |
245 | he->callchain); | 319 | he->callchain); |
246 | } | 320 | } |
247 | hist_entry__free(he); | 321 | hist_entry__free(he); |
@@ -254,35 +328,68 @@ static bool hists__collapse_insert_entry(struct hists *self, | |||
254 | p = &(*p)->rb_right; | 328 | p = &(*p)->rb_right; |
255 | } | 329 | } |
256 | 330 | ||
257 | rb_link_node(&he->rb_node, parent, p); | 331 | rb_link_node(&he->rb_node_in, parent, p); |
258 | rb_insert_color(&he->rb_node, root); | 332 | rb_insert_color(&he->rb_node_in, root); |
259 | return true; | 333 | return true; |
260 | } | 334 | } |
261 | 335 | ||
262 | void hists__collapse_resort(struct hists *self) | 336 | static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) |
337 | { | ||
338 | struct rb_root *root; | ||
339 | |||
340 | pthread_mutex_lock(&hists->lock); | ||
341 | |||
342 | root = hists->entries_in; | ||
343 | if (++hists->entries_in > &hists->entries_in_array[1]) | ||
344 | hists->entries_in = &hists->entries_in_array[0]; | ||
345 | |||
346 | pthread_mutex_unlock(&hists->lock); | ||
347 | |||
348 | return root; | ||
349 | } | ||
350 | |||
351 | static void hists__apply_filters(struct hists *hists, struct hist_entry *he) | ||
352 | { | ||
353 | hists__filter_entry_by_dso(hists, he); | ||
354 | hists__filter_entry_by_thread(hists, he); | ||
355 | } | ||
356 | |||
357 | static void __hists__collapse_resort(struct hists *hists, bool threaded) | ||
263 | { | 358 | { |
264 | struct rb_root tmp; | 359 | struct rb_root *root; |
265 | struct rb_node *next; | 360 | struct rb_node *next; |
266 | struct hist_entry *n; | 361 | struct hist_entry *n; |
267 | 362 | ||
268 | if (!sort__need_collapse) | 363 | if (!sort__need_collapse && !threaded) |
269 | return; | 364 | return; |
270 | 365 | ||
271 | tmp = RB_ROOT; | 366 | root = hists__get_rotate_entries_in(hists); |
272 | next = rb_first(&self->entries); | 367 | next = rb_first(root); |
273 | self->nr_entries = 0; | ||
274 | hists__reset_col_len(self); | ||
275 | 368 | ||
276 | while (next) { | 369 | while (next) { |
277 | n = rb_entry(next, struct hist_entry, rb_node); | 370 | n = rb_entry(next, struct hist_entry, rb_node_in); |
278 | next = rb_next(&n->rb_node); | 371 | next = rb_next(&n->rb_node_in); |
279 | 372 | ||
280 | rb_erase(&n->rb_node, &self->entries); | 373 | rb_erase(&n->rb_node_in, root); |
281 | if (hists__collapse_insert_entry(self, &tmp, n)) | 374 | if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) { |
282 | hists__inc_nr_entries(self, n); | 375 | /* |
376 | * If it wasn't combined with one of the entries already | ||
377 | * collapsed, we need to apply the filters that may have | ||
378 | * been set by, say, the hist_browser. | ||
379 | */ | ||
380 | hists__apply_filters(hists, n); | ||
381 | } | ||
283 | } | 382 | } |
383 | } | ||
284 | 384 | ||
285 | self->entries = tmp; | 385 | void hists__collapse_resort(struct hists *hists) |
386 | { | ||
387 | return __hists__collapse_resort(hists, false); | ||
388 | } | ||
389 | |||
390 | void hists__collapse_resort_threaded(struct hists *hists) | ||
391 | { | ||
392 | return __hists__collapse_resort(hists, true); | ||
286 | } | 393 | } |
287 | 394 | ||
288 | /* | 395 | /* |
@@ -315,31 +422,44 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
315 | rb_insert_color(&he->rb_node, entries); | 422 | rb_insert_color(&he->rb_node, entries); |
316 | } | 423 | } |
317 | 424 | ||
318 | void hists__output_resort(struct hists *self) | 425 | static void __hists__output_resort(struct hists *hists, bool threaded) |
319 | { | 426 | { |
320 | struct rb_root tmp; | 427 | struct rb_root *root; |
321 | struct rb_node *next; | 428 | struct rb_node *next; |
322 | struct hist_entry *n; | 429 | struct hist_entry *n; |
323 | u64 min_callchain_hits; | 430 | u64 min_callchain_hits; |
324 | 431 | ||
325 | min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); | 432 | min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); |
433 | |||
434 | if (sort__need_collapse || threaded) | ||
435 | root = &hists->entries_collapsed; | ||
436 | else | ||
437 | root = hists->entries_in; | ||
326 | 438 | ||
327 | tmp = RB_ROOT; | 439 | next = rb_first(root); |
328 | next = rb_first(&self->entries); | 440 | hists->entries = RB_ROOT; |
329 | 441 | ||
330 | self->nr_entries = 0; | 442 | hists->nr_entries = 0; |
331 | hists__reset_col_len(self); | 443 | hists->stats.total_period = 0; |
444 | hists__reset_col_len(hists); | ||
332 | 445 | ||
333 | while (next) { | 446 | while (next) { |
334 | n = rb_entry(next, struct hist_entry, rb_node); | 447 | n = rb_entry(next, struct hist_entry, rb_node_in); |
335 | next = rb_next(&n->rb_node); | 448 | next = rb_next(&n->rb_node_in); |
336 | 449 | ||
337 | rb_erase(&n->rb_node, &self->entries); | 450 | __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); |
338 | __hists__insert_output_entry(&tmp, n, min_callchain_hits); | 451 | hists__inc_nr_entries(hists, n); |
339 | hists__inc_nr_entries(self, n); | ||
340 | } | 452 | } |
453 | } | ||
341 | 454 | ||
342 | self->entries = tmp; | 455 | void hists__output_resort(struct hists *hists) |
456 | { | ||
457 | return __hists__output_resort(hists, false); | ||
458 | } | ||
459 | |||
460 | void hists__output_resort_threaded(struct hists *hists) | ||
461 | { | ||
462 | return __hists__output_resort(hists, true); | ||
343 | } | 463 | } |
344 | 464 | ||
345 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 465 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
@@ -594,12 +714,27 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
594 | return ret; | 714 | return ret; |
595 | } | 715 | } |
596 | 716 | ||
597 | int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | 717 | void hists__output_recalc_col_len(struct hists *hists, int max_rows) |
598 | struct hists *hists, struct hists *pair_hists, | 718 | { |
599 | bool show_displacement, long displacement, | 719 | struct rb_node *next = rb_first(&hists->entries); |
600 | bool color, u64 session_total) | 720 | struct hist_entry *n; |
721 | int row = 0; | ||
722 | |||
723 | hists__reset_col_len(hists); | ||
724 | |||
725 | while (next && row++ < max_rows) { | ||
726 | n = rb_entry(next, struct hist_entry, rb_node); | ||
727 | if (!n->filtered) | ||
728 | hists__calc_col_len(hists, n); | ||
729 | next = rb_next(&n->rb_node); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, | ||
734 | size_t size, struct hists *pair_hists, | ||
735 | bool show_displacement, long displacement, | ||
736 | bool color, u64 session_total) | ||
601 | { | 737 | { |
602 | struct sort_entry *se; | ||
603 | u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; | 738 | u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; |
604 | u64 nr_events; | 739 | u64 nr_events; |
605 | const char *sep = symbol_conf.field_sep; | 740 | const char *sep = symbol_conf.field_sep; |
@@ -664,6 +799,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | |||
664 | ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); | 799 | ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); |
665 | } | 800 | } |
666 | 801 | ||
802 | if (symbol_conf.show_total_period) { | ||
803 | if (sep) | ||
804 | ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); | ||
805 | else | ||
806 | ret += snprintf(s + ret, size - ret, " %12" PRIu64, period); | ||
807 | } | ||
808 | |||
667 | if (pair_hists) { | 809 | if (pair_hists) { |
668 | char bf[32]; | 810 | char bf[32]; |
669 | double old_percent = 0, new_percent = 0, diff; | 811 | double old_percent = 0, new_percent = 0, diff; |
@@ -698,26 +840,42 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | |||
698 | } | 840 | } |
699 | } | 841 | } |
700 | 842 | ||
843 | return ret; | ||
844 | } | ||
845 | |||
846 | int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, | ||
847 | struct hists *hists) | ||
848 | { | ||
849 | const char *sep = symbol_conf.field_sep; | ||
850 | struct sort_entry *se; | ||
851 | int ret = 0; | ||
852 | |||
701 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 853 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
702 | if (se->elide) | 854 | if (se->elide) |
703 | continue; | 855 | continue; |
704 | 856 | ||
705 | ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); | 857 | ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); |
706 | ret += se->se_snprintf(self, s + ret, size - ret, | 858 | ret += se->se_snprintf(he, s + ret, size - ret, |
707 | hists__col_len(hists, se->se_width_idx)); | 859 | hists__col_len(hists, se->se_width_idx)); |
708 | } | 860 | } |
709 | 861 | ||
710 | return ret; | 862 | return ret; |
711 | } | 863 | } |
712 | 864 | ||
713 | int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, | 865 | int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, |
714 | struct hists *pair_hists, bool show_displacement, | 866 | struct hists *pair_hists, bool show_displacement, |
715 | long displacement, FILE *fp, u64 session_total) | 867 | long displacement, FILE *fp, u64 session_total) |
716 | { | 868 | { |
717 | char bf[512]; | 869 | char bf[512]; |
718 | hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists, | 870 | int ret; |
719 | show_displacement, displacement, | 871 | |
720 | true, session_total); | 872 | if (size == 0 || size > sizeof(bf)) |
873 | size = sizeof(bf); | ||
874 | |||
875 | ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists, | ||
876 | show_displacement, displacement, | ||
877 | true, session_total); | ||
878 | hist_entry__snprintf(he, bf + ret, size - ret, hists); | ||
721 | return fprintf(fp, "%s\n", bf); | 879 | return fprintf(fp, "%s\n", bf); |
722 | } | 880 | } |
723 | 881 | ||
@@ -738,8 +896,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, | |||
738 | left_margin); | 896 | left_margin); |
739 | } | 897 | } |
740 | 898 | ||
741 | size_t hists__fprintf(struct hists *self, struct hists *pair, | 899 | size_t hists__fprintf(struct hists *hists, struct hists *pair, |
742 | bool show_displacement, FILE *fp) | 900 | bool show_displacement, bool show_header, int max_rows, |
901 | int max_cols, FILE *fp) | ||
743 | { | 902 | { |
744 | struct sort_entry *se; | 903 | struct sort_entry *se; |
745 | struct rb_node *nd; | 904 | struct rb_node *nd; |
@@ -749,9 +908,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
749 | unsigned int width; | 908 | unsigned int width; |
750 | const char *sep = symbol_conf.field_sep; | 909 | const char *sep = symbol_conf.field_sep; |
751 | const char *col_width = symbol_conf.col_width_list_str; | 910 | const char *col_width = symbol_conf.col_width_list_str; |
911 | int nr_rows = 0; | ||
752 | 912 | ||
753 | init_rem_hits(); | 913 | init_rem_hits(); |
754 | 914 | ||
915 | if (!show_header) | ||
916 | goto print_entries; | ||
917 | |||
755 | fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); | 918 | fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); |
756 | 919 | ||
757 | if (symbol_conf.show_nr_samples) { | 920 | if (symbol_conf.show_nr_samples) { |
@@ -761,6 +924,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
761 | fputs(" Samples ", fp); | 924 | fputs(" Samples ", fp); |
762 | } | 925 | } |
763 | 926 | ||
927 | if (symbol_conf.show_total_period) { | ||
928 | if (sep) | ||
929 | ret += fprintf(fp, "%cPeriod", *sep); | ||
930 | else | ||
931 | ret += fprintf(fp, " Period "); | ||
932 | } | ||
933 | |||
764 | if (symbol_conf.show_cpu_utilization) { | 934 | if (symbol_conf.show_cpu_utilization) { |
765 | if (sep) { | 935 | if (sep) { |
766 | ret += fprintf(fp, "%csys", *sep); | 936 | ret += fprintf(fp, "%csys", *sep); |
@@ -803,18 +973,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
803 | width = strlen(se->se_header); | 973 | width = strlen(se->se_header); |
804 | if (symbol_conf.col_width_list_str) { | 974 | if (symbol_conf.col_width_list_str) { |
805 | if (col_width) { | 975 | if (col_width) { |
806 | hists__set_col_len(self, se->se_width_idx, | 976 | hists__set_col_len(hists, se->se_width_idx, |
807 | atoi(col_width)); | 977 | atoi(col_width)); |
808 | col_width = strchr(col_width, ','); | 978 | col_width = strchr(col_width, ','); |
809 | if (col_width) | 979 | if (col_width) |
810 | ++col_width; | 980 | ++col_width; |
811 | } | 981 | } |
812 | } | 982 | } |
813 | if (!hists__new_col_len(self, se->se_width_idx, width)) | 983 | if (!hists__new_col_len(hists, se->se_width_idx, width)) |
814 | width = hists__col_len(self, se->se_width_idx); | 984 | width = hists__col_len(hists, se->se_width_idx); |
815 | fprintf(fp, " %*s", width, se->se_header); | 985 | fprintf(fp, " %*s", width, se->se_header); |
816 | } | 986 | } |
987 | |||
817 | fprintf(fp, "\n"); | 988 | fprintf(fp, "\n"); |
989 | if (max_rows && ++nr_rows >= max_rows) | ||
990 | goto out; | ||
818 | 991 | ||
819 | if (sep) | 992 | if (sep) |
820 | goto print_entries; | 993 | goto print_entries; |
@@ -822,6 +995,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
822 | fprintf(fp, "# ........"); | 995 | fprintf(fp, "# ........"); |
823 | if (symbol_conf.show_nr_samples) | 996 | if (symbol_conf.show_nr_samples) |
824 | fprintf(fp, " .........."); | 997 | fprintf(fp, " .........."); |
998 | if (symbol_conf.show_total_period) | ||
999 | fprintf(fp, " ............"); | ||
825 | if (pair) { | 1000 | if (pair) { |
826 | fprintf(fp, " .........."); | 1001 | fprintf(fp, " .........."); |
827 | if (show_displacement) | 1002 | if (show_displacement) |
@@ -834,17 +1009,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
834 | continue; | 1009 | continue; |
835 | 1010 | ||
836 | fprintf(fp, " "); | 1011 | fprintf(fp, " "); |
837 | width = hists__col_len(self, se->se_width_idx); | 1012 | width = hists__col_len(hists, se->se_width_idx); |
838 | if (width == 0) | 1013 | if (width == 0) |
839 | width = strlen(se->se_header); | 1014 | width = strlen(se->se_header); |
840 | for (i = 0; i < width; i++) | 1015 | for (i = 0; i < width; i++) |
841 | fprintf(fp, "."); | 1016 | fprintf(fp, "."); |
842 | } | 1017 | } |
843 | 1018 | ||
844 | fprintf(fp, "\n#\n"); | 1019 | fprintf(fp, "\n"); |
1020 | if (max_rows && ++nr_rows >= max_rows) | ||
1021 | goto out; | ||
1022 | |||
1023 | fprintf(fp, "#\n"); | ||
1024 | if (max_rows && ++nr_rows >= max_rows) | ||
1025 | goto out; | ||
845 | 1026 | ||
846 | print_entries: | 1027 | print_entries: |
847 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 1028 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
848 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 1029 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
849 | 1030 | ||
850 | if (h->filtered) | 1031 | if (h->filtered) |
@@ -858,19 +1039,22 @@ print_entries: | |||
858 | displacement = 0; | 1039 | displacement = 0; |
859 | ++position; | 1040 | ++position; |
860 | } | 1041 | } |
861 | ret += hist_entry__fprintf(h, self, pair, show_displacement, | 1042 | ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement, |
862 | displacement, fp, self->stats.total_period); | 1043 | displacement, fp, hists->stats.total_period); |
863 | 1044 | ||
864 | if (symbol_conf.use_callchain) | 1045 | if (symbol_conf.use_callchain) |
865 | ret += hist_entry__fprintf_callchain(h, self, fp, | 1046 | ret += hist_entry__fprintf_callchain(h, hists, fp, |
866 | self->stats.total_period); | 1047 | hists->stats.total_period); |
1048 | if (max_rows && ++nr_rows >= max_rows) | ||
1049 | goto out; | ||
1050 | |||
867 | if (h->ms.map == NULL && verbose > 1) { | 1051 | if (h->ms.map == NULL && verbose > 1) { |
868 | __map_groups__fprintf_maps(&h->thread->mg, | 1052 | __map_groups__fprintf_maps(&h->thread->mg, |
869 | MAP__FUNCTION, verbose, fp); | 1053 | MAP__FUNCTION, verbose, fp); |
870 | fprintf(fp, "%.10s end\n", graph_dotted_line); | 1054 | fprintf(fp, "%.10s end\n", graph_dotted_line); |
871 | } | 1055 | } |
872 | } | 1056 | } |
873 | 1057 | out: | |
874 | free(rem_sq_bracket); | 1058 | free(rem_sq_bracket); |
875 | 1059 | ||
876 | return ret; | 1060 | return ret; |
@@ -879,7 +1063,7 @@ print_entries: | |||
879 | /* | 1063 | /* |
880 | * See hists__fprintf to match the column widths | 1064 | * See hists__fprintf to match the column widths |
881 | */ | 1065 | */ |
882 | unsigned int hists__sort_list_width(struct hists *self) | 1066 | unsigned int hists__sort_list_width(struct hists *hists) |
883 | { | 1067 | { |
884 | struct sort_entry *se; | 1068 | struct sort_entry *se; |
885 | int ret = 9; /* total % */ | 1069 | int ret = 9; /* total % */ |
@@ -896,9 +1080,12 @@ unsigned int hists__sort_list_width(struct hists *self) | |||
896 | if (symbol_conf.show_nr_samples) | 1080 | if (symbol_conf.show_nr_samples) |
897 | ret += 11; | 1081 | ret += 11; |
898 | 1082 | ||
1083 | if (symbol_conf.show_total_period) | ||
1084 | ret += 13; | ||
1085 | |||
899 | list_for_each_entry(se, &hist_entry__sort_list, list) | 1086 | list_for_each_entry(se, &hist_entry__sort_list, list) |
900 | if (!se->elide) | 1087 | if (!se->elide) |
901 | ret += 2 + hists__col_len(self, se->se_width_idx); | 1088 | ret += 2 + hists__col_len(hists, se->se_width_idx); |
902 | 1089 | ||
903 | if (verbose) /* Addr + origin */ | 1090 | if (verbose) /* Addr + origin */ |
904 | ret += 3 + BITS_PER_LONG / 4; | 1091 | ret += 3 + BITS_PER_LONG / 4; |
@@ -906,63 +1093,84 @@ unsigned int hists__sort_list_width(struct hists *self) | |||
906 | return ret; | 1093 | return ret; |
907 | } | 1094 | } |
908 | 1095 | ||
909 | static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h, | 1096 | static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, |
910 | enum hist_filter filter) | 1097 | enum hist_filter filter) |
911 | { | 1098 | { |
912 | h->filtered &= ~(1 << filter); | 1099 | h->filtered &= ~(1 << filter); |
913 | if (h->filtered) | 1100 | if (h->filtered) |
914 | return; | 1101 | return; |
915 | 1102 | ||
916 | ++self->nr_entries; | 1103 | ++hists->nr_entries; |
917 | if (h->ms.unfolded) | 1104 | if (h->ms.unfolded) |
918 | self->nr_entries += h->nr_rows; | 1105 | hists->nr_entries += h->nr_rows; |
919 | h->row_offset = 0; | 1106 | h->row_offset = 0; |
920 | self->stats.total_period += h->period; | 1107 | hists->stats.total_period += h->period; |
921 | self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; | 1108 | hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; |
922 | 1109 | ||
923 | hists__calc_col_len(self, h); | 1110 | hists__calc_col_len(hists, h); |
924 | } | 1111 | } |
925 | 1112 | ||
926 | void hists__filter_by_dso(struct hists *self, const struct dso *dso) | 1113 | |
1114 | static bool hists__filter_entry_by_dso(struct hists *hists, | ||
1115 | struct hist_entry *he) | ||
1116 | { | ||
1117 | if (hists->dso_filter != NULL && | ||
1118 | (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) { | ||
1119 | he->filtered |= (1 << HIST_FILTER__DSO); | ||
1120 | return true; | ||
1121 | } | ||
1122 | |||
1123 | return false; | ||
1124 | } | ||
1125 | |||
1126 | void hists__filter_by_dso(struct hists *hists) | ||
927 | { | 1127 | { |
928 | struct rb_node *nd; | 1128 | struct rb_node *nd; |
929 | 1129 | ||
930 | self->nr_entries = self->stats.total_period = 0; | 1130 | hists->nr_entries = hists->stats.total_period = 0; |
931 | self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; | 1131 | hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; |
932 | hists__reset_col_len(self); | 1132 | hists__reset_col_len(hists); |
933 | 1133 | ||
934 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 1134 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
935 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 1135 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
936 | 1136 | ||
937 | if (symbol_conf.exclude_other && !h->parent) | 1137 | if (symbol_conf.exclude_other && !h->parent) |
938 | continue; | 1138 | continue; |
939 | 1139 | ||
940 | if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { | 1140 | if (hists__filter_entry_by_dso(hists, h)) |
941 | h->filtered |= (1 << HIST_FILTER__DSO); | ||
942 | continue; | 1141 | continue; |
943 | } | ||
944 | 1142 | ||
945 | hists__remove_entry_filter(self, h, HIST_FILTER__DSO); | 1143 | hists__remove_entry_filter(hists, h, HIST_FILTER__DSO); |
946 | } | 1144 | } |
947 | } | 1145 | } |
948 | 1146 | ||
949 | void hists__filter_by_thread(struct hists *self, const struct thread *thread) | 1147 | static bool hists__filter_entry_by_thread(struct hists *hists, |
1148 | struct hist_entry *he) | ||
1149 | { | ||
1150 | if (hists->thread_filter != NULL && | ||
1151 | he->thread != hists->thread_filter) { | ||
1152 | he->filtered |= (1 << HIST_FILTER__THREAD); | ||
1153 | return true; | ||
1154 | } | ||
1155 | |||
1156 | return false; | ||
1157 | } | ||
1158 | |||
1159 | void hists__filter_by_thread(struct hists *hists) | ||
950 | { | 1160 | { |
951 | struct rb_node *nd; | 1161 | struct rb_node *nd; |
952 | 1162 | ||
953 | self->nr_entries = self->stats.total_period = 0; | 1163 | hists->nr_entries = hists->stats.total_period = 0; |
954 | self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; | 1164 | hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; |
955 | hists__reset_col_len(self); | 1165 | hists__reset_col_len(hists); |
956 | 1166 | ||
957 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 1167 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
958 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 1168 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
959 | 1169 | ||
960 | if (thread != NULL && h->thread != thread) { | 1170 | if (hists__filter_entry_by_thread(hists, h)) |
961 | h->filtered |= (1 << HIST_FILTER__THREAD); | ||
962 | continue; | 1171 | continue; |
963 | } | ||
964 | 1172 | ||
965 | hists__remove_entry_filter(self, h, HIST_FILTER__THREAD); | 1173 | hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD); |
966 | } | 1174 | } |
967 | } | 1175 | } |
968 | 1176 | ||
@@ -976,13 +1184,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) | |||
976 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | 1184 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); |
977 | } | 1185 | } |
978 | 1186 | ||
979 | void hists__inc_nr_events(struct hists *self, u32 type) | 1187 | void hists__inc_nr_events(struct hists *hists, u32 type) |
980 | { | 1188 | { |
981 | ++self->stats.nr_events[0]; | 1189 | ++hists->stats.nr_events[0]; |
982 | ++self->stats.nr_events[type]; | 1190 | ++hists->stats.nr_events[type]; |
983 | } | 1191 | } |
984 | 1192 | ||
985 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | 1193 | size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) |
986 | { | 1194 | { |
987 | int i; | 1195 | int i; |
988 | size_t ret = 0; | 1196 | size_t ret = 0; |
@@ -990,7 +1198,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | |||
990 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 1198 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
991 | const char *name; | 1199 | const char *name; |
992 | 1200 | ||
993 | if (self->stats.nr_events[i] == 0) | 1201 | if (hists->stats.nr_events[i] == 0) |
994 | continue; | 1202 | continue; |
995 | 1203 | ||
996 | name = perf_event__name(i); | 1204 | name = perf_event__name(i); |
@@ -998,8 +1206,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | |||
998 | continue; | 1206 | continue; |
999 | 1207 | ||
1000 | ret += fprintf(fp, "%16s events: %10d\n", name, | 1208 | ret += fprintf(fp, "%16s events: %10d\n", name, |
1001 | self->stats.nr_events[i]); | 1209 | hists->stats.nr_events[i]); |
1002 | } | 1210 | } |
1003 | 1211 | ||
1004 | return ret; | 1212 | return ret; |
1005 | } | 1213 | } |
1214 | |||
1215 | void hists__init(struct hists *hists) | ||
1216 | { | ||
1217 | memset(hists, 0, sizeof(*hists)); | ||
1218 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; | ||
1219 | hists->entries_in = &hists->entries_in_array[0]; | ||
1220 | hists->entries_collapsed = RB_ROOT; | ||
1221 | hists->entries = RB_ROOT; | ||
1222 | pthread_mutex_init(&hists->lock, NULL); | ||
1223 | } | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 3beb97c4d822..c86c1d27bd1e 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __PERF_HIST_H | 2 | #define __PERF_HIST_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <pthread.h> | ||
5 | #include "callchain.h" | 6 | #include "callchain.h" |
6 | 7 | ||
7 | extern struct callchain_param callchain_param; | 8 | extern struct callchain_param callchain_param; |
@@ -27,6 +28,7 @@ struct events_stats { | |||
27 | u64 total_lost; | 28 | u64 total_lost; |
28 | u64 total_invalid_chains; | 29 | u64 total_invalid_chains; |
29 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 30 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
31 | u32 nr_lost_warned; | ||
30 | u32 nr_unknown_events; | 32 | u32 nr_unknown_events; |
31 | u32 nr_invalid_chains; | 33 | u32 nr_invalid_chains; |
32 | u32 nr_unknown_id; | 34 | u32 nr_unknown_id; |
@@ -42,9 +44,18 @@ enum hist_column { | |||
42 | HISTC_NR_COLS, /* Last entry */ | 44 | HISTC_NR_COLS, /* Last entry */ |
43 | }; | 45 | }; |
44 | 46 | ||
47 | struct thread; | ||
48 | struct dso; | ||
49 | |||
45 | struct hists { | 50 | struct hists { |
51 | struct rb_root entries_in_array[2]; | ||
52 | struct rb_root *entries_in; | ||
46 | struct rb_root entries; | 53 | struct rb_root entries; |
54 | struct rb_root entries_collapsed; | ||
47 | u64 nr_entries; | 55 | u64 nr_entries; |
56 | const struct thread *thread_filter; | ||
57 | const struct dso *dso_filter; | ||
58 | pthread_mutex_t lock; | ||
48 | struct events_stats stats; | 59 | struct events_stats stats; |
49 | u64 event_stream; | 60 | u64 event_stream; |
50 | u16 col_len[HISTC_NR_COLS]; | 61 | u16 col_len[HISTC_NR_COLS]; |
@@ -52,34 +63,42 @@ struct hists { | |||
52 | struct callchain_cursor callchain_cursor; | 63 | struct callchain_cursor callchain_cursor; |
53 | }; | 64 | }; |
54 | 65 | ||
66 | void hists__init(struct hists *hists); | ||
67 | |||
55 | struct hist_entry *__hists__add_entry(struct hists *self, | 68 | struct hist_entry *__hists__add_entry(struct hists *self, |
56 | struct addr_location *al, | 69 | struct addr_location *al, |
57 | struct symbol *parent, u64 period); | 70 | struct symbol *parent, u64 period); |
58 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | 71 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); |
59 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 72 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
60 | int hist_entry__fprintf(struct hist_entry *self, struct hists *hists, | 73 | int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, |
61 | struct hists *pair_hists, bool show_displacement, | 74 | struct hists *pair_hists, bool show_displacement, |
62 | long displacement, FILE *fp, u64 total); | 75 | long displacement, FILE *fp, u64 session_total); |
63 | int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, | 76 | int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, |
64 | struct hists *hists, struct hists *pair_hists, | 77 | struct hists *hists); |
65 | bool show_displacement, long displacement, | ||
66 | bool color, u64 total); | ||
67 | void hist_entry__free(struct hist_entry *); | 78 | void hist_entry__free(struct hist_entry *); |
68 | 79 | ||
69 | void hists__output_resort(struct hists *self); | 80 | void hists__output_resort(struct hists *self); |
81 | void hists__output_resort_threaded(struct hists *hists); | ||
70 | void hists__collapse_resort(struct hists *self); | 82 | void hists__collapse_resort(struct hists *self); |
83 | void hists__collapse_resort_threaded(struct hists *hists); | ||
84 | |||
85 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); | ||
86 | void hists__decay_entries_threaded(struct hists *hists, bool zap_user, | ||
87 | bool zap_kernel); | ||
88 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | ||
71 | 89 | ||
72 | void hists__inc_nr_events(struct hists *self, u32 type); | 90 | void hists__inc_nr_events(struct hists *self, u32 type); |
73 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 91 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); |
74 | 92 | ||
75 | size_t hists__fprintf(struct hists *self, struct hists *pair, | 93 | size_t hists__fprintf(struct hists *self, struct hists *pair, |
76 | bool show_displacement, FILE *fp); | 94 | bool show_displacement, bool show_header, |
95 | int max_rows, int max_cols, FILE *fp); | ||
77 | 96 | ||
78 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); | 97 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); |
79 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); | 98 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); |
80 | 99 | ||
81 | void hists__filter_by_dso(struct hists *self, const struct dso *dso); | 100 | void hists__filter_by_dso(struct hists *hists); |
82 | void hists__filter_by_thread(struct hists *self, const struct thread *thread); | 101 | void hists__filter_by_thread(struct hists *hists); |
83 | 102 | ||
84 | u16 hists__col_len(struct hists *self, enum hist_column col); | 103 | u16 hists__col_len(struct hists *self, enum hist_column col); |
85 | void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); | 104 | void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); |
@@ -90,26 +109,33 @@ struct perf_evlist; | |||
90 | #ifdef NO_NEWT_SUPPORT | 109 | #ifdef NO_NEWT_SUPPORT |
91 | static inline | 110 | static inline |
92 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, | 111 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, |
93 | const char *help __used) | 112 | const char *help __used, |
113 | void(*timer)(void *arg) __used, | ||
114 | void *arg __used, | ||
115 | int refresh __used) | ||
94 | { | 116 | { |
95 | return 0; | 117 | return 0; |
96 | } | 118 | } |
97 | 119 | ||
98 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, | 120 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, |
99 | int evidx __used) | 121 | int evidx __used, |
122 | int nr_events __used, | ||
123 | void(*timer)(void *arg) __used, | ||
124 | void *arg __used, | ||
125 | int delay_secs __used) | ||
100 | { | 126 | { |
101 | return 0; | 127 | return 0; |
102 | } | 128 | } |
103 | #define KEY_LEFT -1 | 129 | #define K_LEFT -1 |
104 | #define KEY_RIGHT -2 | 130 | #define K_RIGHT -2 |
105 | #else | 131 | #else |
106 | #include <newt.h> | 132 | #include "ui/keysyms.h" |
107 | int hist_entry__tui_annotate(struct hist_entry *self, int evidx); | 133 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, |
108 | 134 | void(*timer)(void *arg), void *arg, int delay_secs); | |
109 | #define KEY_LEFT NEWT_KEY_LEFT | ||
110 | #define KEY_RIGHT NEWT_KEY_RIGHT | ||
111 | 135 | ||
112 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help); | 136 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
137 | void(*timer)(void *arg), void *arg, | ||
138 | int refresh); | ||
113 | #endif | 139 | #endif |
114 | 140 | ||
115 | unsigned int hists__sort_list_width(struct hists *self); | 141 | unsigned int hists__sort_list_width(struct hists *self); |
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h index 791f9dd27ebf..547628e97f3d 100644 --- a/tools/perf/util/include/linux/compiler.h +++ b/tools/perf/util/include/linux/compiler.h | |||
@@ -5,7 +5,9 @@ | |||
5 | #define __always_inline inline | 5 | #define __always_inline inline |
6 | #endif | 6 | #endif |
7 | #define __user | 7 | #define __user |
8 | #ifndef __attribute_const__ | ||
8 | #define __attribute_const__ | 9 | #define __attribute_const__ |
10 | #endif | ||
9 | 11 | ||
10 | #define __used __attribute__((__unused__)) | 12 | #define __used __attribute__((__unused__)) |
11 | 13 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index a16ecab5229d..78284b13e808 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -18,6 +18,13 @@ static inline int is_anon_memory(const char *filename) | |||
18 | return strcmp(filename, "//anon") == 0; | 18 | return strcmp(filename, "//anon") == 0; |
19 | } | 19 | } |
20 | 20 | ||
21 | static inline int is_no_dso_memory(const char *filename) | ||
22 | { | ||
23 | return !strcmp(filename, "[stack]") || | ||
24 | !strcmp(filename, "[vdso]") || | ||
25 | !strcmp(filename, "[heap]"); | ||
26 | } | ||
27 | |||
21 | void map__init(struct map *self, enum map_type type, | 28 | void map__init(struct map *self, enum map_type type, |
22 | u64 start, u64 end, u64 pgoff, struct dso *dso) | 29 | u64 start, u64 end, u64 pgoff, struct dso *dso) |
23 | { | 30 | { |
@@ -42,9 +49,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
42 | if (self != NULL) { | 49 | if (self != NULL) { |
43 | char newfilename[PATH_MAX]; | 50 | char newfilename[PATH_MAX]; |
44 | struct dso *dso; | 51 | struct dso *dso; |
45 | int anon; | 52 | int anon, no_dso; |
46 | 53 | ||
47 | anon = is_anon_memory(filename); | 54 | anon = is_anon_memory(filename); |
55 | no_dso = is_no_dso_memory(filename); | ||
48 | 56 | ||
49 | if (anon) { | 57 | if (anon) { |
50 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); | 58 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); |
@@ -57,12 +65,16 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
57 | 65 | ||
58 | map__init(self, type, start, start + len, pgoff, dso); | 66 | map__init(self, type, start, start + len, pgoff, dso); |
59 | 67 | ||
60 | if (anon) { | 68 | if (anon || no_dso) { |
61 | set_identity: | ||
62 | self->map_ip = self->unmap_ip = identity__map_ip; | 69 | self->map_ip = self->unmap_ip = identity__map_ip; |
63 | } else if (strcmp(filename, "[vdso]") == 0) { | 70 | |
64 | dso__set_loaded(dso, self->type); | 71 | /* |
65 | goto set_identity; | 72 | * Set memory without DSO as loaded. All map__find_* |
73 | * functions still return NULL, and we avoid the | ||
74 | * unnecessary map__load warning. | ||
75 | */ | ||
76 | if (no_dso) | ||
77 | dso__set_loaded(dso, self->type); | ||
66 | } | 78 | } |
67 | } | 79 | } |
68 | return self; | 80 | return self; |
@@ -127,8 +139,8 @@ int map__load(struct map *self, symbol_filter_t filter) | |||
127 | 139 | ||
128 | if (len > sizeof(DSO__DELETED) && | 140 | if (len > sizeof(DSO__DELETED) && |
129 | strcmp(name + real_len + 1, DSO__DELETED) == 0) { | 141 | strcmp(name + real_len + 1, DSO__DELETED) == 0) { |
130 | pr_warning("%.*s was updated, restart the long " | 142 | pr_warning("%.*s was updated (is prelink enabled?). " |
131 | "running apps that use it!\n", | 143 | "Restart the long running apps that use it!\n", |
132 | (int)real_len, name); | 144 | (int)real_len, name); |
133 | } else { | 145 | } else { |
134 | pr_warning("no symbols found in %s, maybe install " | 146 | pr_warning("no symbols found in %s, maybe install " |
@@ -220,55 +232,55 @@ u64 map__objdump_2ip(struct map *map, u64 addr) | |||
220 | return ip; | 232 | return ip; |
221 | } | 233 | } |
222 | 234 | ||
223 | void map_groups__init(struct map_groups *self) | 235 | void map_groups__init(struct map_groups *mg) |
224 | { | 236 | { |
225 | int i; | 237 | int i; |
226 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 238 | for (i = 0; i < MAP__NR_TYPES; ++i) { |
227 | self->maps[i] = RB_ROOT; | 239 | mg->maps[i] = RB_ROOT; |
228 | INIT_LIST_HEAD(&self->removed_maps[i]); | 240 | INIT_LIST_HEAD(&mg->removed_maps[i]); |
229 | } | 241 | } |
230 | self->machine = NULL; | 242 | mg->machine = NULL; |
231 | } | 243 | } |
232 | 244 | ||
233 | static void maps__delete(struct rb_root *self) | 245 | static void maps__delete(struct rb_root *maps) |
234 | { | 246 | { |
235 | struct rb_node *next = rb_first(self); | 247 | struct rb_node *next = rb_first(maps); |
236 | 248 | ||
237 | while (next) { | 249 | while (next) { |
238 | struct map *pos = rb_entry(next, struct map, rb_node); | 250 | struct map *pos = rb_entry(next, struct map, rb_node); |
239 | 251 | ||
240 | next = rb_next(&pos->rb_node); | 252 | next = rb_next(&pos->rb_node); |
241 | rb_erase(&pos->rb_node, self); | 253 | rb_erase(&pos->rb_node, maps); |
242 | map__delete(pos); | 254 | map__delete(pos); |
243 | } | 255 | } |
244 | } | 256 | } |
245 | 257 | ||
246 | static void maps__delete_removed(struct list_head *self) | 258 | static void maps__delete_removed(struct list_head *maps) |
247 | { | 259 | { |
248 | struct map *pos, *n; | 260 | struct map *pos, *n; |
249 | 261 | ||
250 | list_for_each_entry_safe(pos, n, self, node) { | 262 | list_for_each_entry_safe(pos, n, maps, node) { |
251 | list_del(&pos->node); | 263 | list_del(&pos->node); |
252 | map__delete(pos); | 264 | map__delete(pos); |
253 | } | 265 | } |
254 | } | 266 | } |
255 | 267 | ||
256 | void map_groups__exit(struct map_groups *self) | 268 | void map_groups__exit(struct map_groups *mg) |
257 | { | 269 | { |
258 | int i; | 270 | int i; |
259 | 271 | ||
260 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 272 | for (i = 0; i < MAP__NR_TYPES; ++i) { |
261 | maps__delete(&self->maps[i]); | 273 | maps__delete(&mg->maps[i]); |
262 | maps__delete_removed(&self->removed_maps[i]); | 274 | maps__delete_removed(&mg->removed_maps[i]); |
263 | } | 275 | } |
264 | } | 276 | } |
265 | 277 | ||
266 | void map_groups__flush(struct map_groups *self) | 278 | void map_groups__flush(struct map_groups *mg) |
267 | { | 279 | { |
268 | int type; | 280 | int type; |
269 | 281 | ||
270 | for (type = 0; type < MAP__NR_TYPES; type++) { | 282 | for (type = 0; type < MAP__NR_TYPES; type++) { |
271 | struct rb_root *root = &self->maps[type]; | 283 | struct rb_root *root = &mg->maps[type]; |
272 | struct rb_node *next = rb_first(root); | 284 | struct rb_node *next = rb_first(root); |
273 | 285 | ||
274 | while (next) { | 286 | while (next) { |
@@ -280,17 +292,17 @@ void map_groups__flush(struct map_groups *self) | |||
280 | * instance in some hist_entry instances, so | 292 | * instance in some hist_entry instances, so |
281 | * just move them to a separate list. | 293 | * just move them to a separate list. |
282 | */ | 294 | */ |
283 | list_add_tail(&pos->node, &self->removed_maps[pos->type]); | 295 | list_add_tail(&pos->node, &mg->removed_maps[pos->type]); |
284 | } | 296 | } |
285 | } | 297 | } |
286 | } | 298 | } |
287 | 299 | ||
288 | struct symbol *map_groups__find_symbol(struct map_groups *self, | 300 | struct symbol *map_groups__find_symbol(struct map_groups *mg, |
289 | enum map_type type, u64 addr, | 301 | enum map_type type, u64 addr, |
290 | struct map **mapp, | 302 | struct map **mapp, |
291 | symbol_filter_t filter) | 303 | symbol_filter_t filter) |
292 | { | 304 | { |
293 | struct map *map = map_groups__find(self, type, addr); | 305 | struct map *map = map_groups__find(mg, type, addr); |
294 | 306 | ||
295 | if (map != NULL) { | 307 | if (map != NULL) { |
296 | if (mapp != NULL) | 308 | if (mapp != NULL) |
@@ -301,7 +313,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *self, | |||
301 | return NULL; | 313 | return NULL; |
302 | } | 314 | } |
303 | 315 | ||
304 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | 316 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, |
305 | enum map_type type, | 317 | enum map_type type, |
306 | const char *name, | 318 | const char *name, |
307 | struct map **mapp, | 319 | struct map **mapp, |
@@ -309,7 +321,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | |||
309 | { | 321 | { |
310 | struct rb_node *nd; | 322 | struct rb_node *nd; |
311 | 323 | ||
312 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | 324 | for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { |
313 | struct map *pos = rb_entry(nd, struct map, rb_node); | 325 | struct map *pos = rb_entry(nd, struct map, rb_node); |
314 | struct symbol *sym = map__find_symbol_by_name(pos, name, filter); | 326 | struct symbol *sym = map__find_symbol_by_name(pos, name, filter); |
315 | 327 | ||
@@ -323,13 +335,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | |||
323 | return NULL; | 335 | return NULL; |
324 | } | 336 | } |
325 | 337 | ||
326 | size_t __map_groups__fprintf_maps(struct map_groups *self, | 338 | size_t __map_groups__fprintf_maps(struct map_groups *mg, |
327 | enum map_type type, int verbose, FILE *fp) | 339 | enum map_type type, int verbose, FILE *fp) |
328 | { | 340 | { |
329 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | 341 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); |
330 | struct rb_node *nd; | 342 | struct rb_node *nd; |
331 | 343 | ||
332 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | 344 | for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { |
333 | struct map *pos = rb_entry(nd, struct map, rb_node); | 345 | struct map *pos = rb_entry(nd, struct map, rb_node); |
334 | printed += fprintf(fp, "Map:"); | 346 | printed += fprintf(fp, "Map:"); |
335 | printed += map__fprintf(pos, fp); | 347 | printed += map__fprintf(pos, fp); |
@@ -342,22 +354,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *self, | |||
342 | return printed; | 354 | return printed; |
343 | } | 355 | } |
344 | 356 | ||
345 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp) | 357 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) |
346 | { | 358 | { |
347 | size_t printed = 0, i; | 359 | size_t printed = 0, i; |
348 | for (i = 0; i < MAP__NR_TYPES; ++i) | 360 | for (i = 0; i < MAP__NR_TYPES; ++i) |
349 | printed += __map_groups__fprintf_maps(self, i, verbose, fp); | 361 | printed += __map_groups__fprintf_maps(mg, i, verbose, fp); |
350 | return printed; | 362 | return printed; |
351 | } | 363 | } |
352 | 364 | ||
353 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, | 365 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, |
354 | enum map_type type, | 366 | enum map_type type, |
355 | int verbose, FILE *fp) | 367 | int verbose, FILE *fp) |
356 | { | 368 | { |
357 | struct map *pos; | 369 | struct map *pos; |
358 | size_t printed = 0; | 370 | size_t printed = 0; |
359 | 371 | ||
360 | list_for_each_entry(pos, &self->removed_maps[type], node) { | 372 | list_for_each_entry(pos, &mg->removed_maps[type], node) { |
361 | printed += fprintf(fp, "Map:"); | 373 | printed += fprintf(fp, "Map:"); |
362 | printed += map__fprintf(pos, fp); | 374 | printed += map__fprintf(pos, fp); |
363 | if (verbose > 1) { | 375 | if (verbose > 1) { |
@@ -368,26 +380,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, | |||
368 | return printed; | 380 | return printed; |
369 | } | 381 | } |
370 | 382 | ||
371 | static size_t map_groups__fprintf_removed_maps(struct map_groups *self, | 383 | static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, |
372 | int verbose, FILE *fp) | 384 | int verbose, FILE *fp) |
373 | { | 385 | { |
374 | size_t printed = 0, i; | 386 | size_t printed = 0, i; |
375 | for (i = 0; i < MAP__NR_TYPES; ++i) | 387 | for (i = 0; i < MAP__NR_TYPES; ++i) |
376 | printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp); | 388 | printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); |
377 | return printed; | 389 | return printed; |
378 | } | 390 | } |
379 | 391 | ||
380 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp) | 392 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) |
381 | { | 393 | { |
382 | size_t printed = map_groups__fprintf_maps(self, verbose, fp); | 394 | size_t printed = map_groups__fprintf_maps(mg, verbose, fp); |
383 | printed += fprintf(fp, "Removed maps:\n"); | 395 | printed += fprintf(fp, "Removed maps:\n"); |
384 | return printed + map_groups__fprintf_removed_maps(self, verbose, fp); | 396 | return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); |
385 | } | 397 | } |
386 | 398 | ||
387 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | 399 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
388 | int verbose, FILE *fp) | 400 | int verbose, FILE *fp) |
389 | { | 401 | { |
390 | struct rb_root *root = &self->maps[map->type]; | 402 | struct rb_root *root = &mg->maps[map->type]; |
391 | struct rb_node *next = rb_first(root); | 403 | struct rb_node *next = rb_first(root); |
392 | int err = 0; | 404 | int err = 0; |
393 | 405 | ||
@@ -418,7 +430,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | |||
418 | } | 430 | } |
419 | 431 | ||
420 | before->end = map->start - 1; | 432 | before->end = map->start - 1; |
421 | map_groups__insert(self, before); | 433 | map_groups__insert(mg, before); |
422 | if (verbose >= 2) | 434 | if (verbose >= 2) |
423 | map__fprintf(before, fp); | 435 | map__fprintf(before, fp); |
424 | } | 436 | } |
@@ -432,7 +444,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | |||
432 | } | 444 | } |
433 | 445 | ||
434 | after->start = map->end + 1; | 446 | after->start = map->end + 1; |
435 | map_groups__insert(self, after); | 447 | map_groups__insert(mg, after); |
436 | if (verbose >= 2) | 448 | if (verbose >= 2) |
437 | map__fprintf(after, fp); | 449 | map__fprintf(after, fp); |
438 | } | 450 | } |
@@ -441,7 +453,7 @@ move_map: | |||
441 | * If we have references, just move them to a separate list. | 453 | * If we have references, just move them to a separate list. |
442 | */ | 454 | */ |
443 | if (pos->referenced) | 455 | if (pos->referenced) |
444 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | 456 | list_add_tail(&pos->node, &mg->removed_maps[map->type]); |
445 | else | 457 | else |
446 | map__delete(pos); | 458 | map__delete(pos); |
447 | 459 | ||
@@ -455,7 +467,7 @@ move_map: | |||
455 | /* | 467 | /* |
456 | * XXX This should not really _copy_ te maps, but refcount them. | 468 | * XXX This should not really _copy_ te maps, but refcount them. |
457 | */ | 469 | */ |
458 | int map_groups__clone(struct map_groups *self, | 470 | int map_groups__clone(struct map_groups *mg, |
459 | struct map_groups *parent, enum map_type type) | 471 | struct map_groups *parent, enum map_type type) |
460 | { | 472 | { |
461 | struct rb_node *nd; | 473 | struct rb_node *nd; |
@@ -464,7 +476,7 @@ int map_groups__clone(struct map_groups *self, | |||
464 | struct map *new = map__clone(map); | 476 | struct map *new = map__clone(map); |
465 | if (new == NULL) | 477 | if (new == NULL) |
466 | return -ENOMEM; | 478 | return -ENOMEM; |
467 | map_groups__insert(self, new); | 479 | map_groups__insert(mg, new); |
468 | } | 480 | } |
469 | return 0; | 481 | return 0; |
470 | } | 482 | } |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b397c0383728..890d85545d0f 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -123,17 +123,17 @@ void map__fixup_end(struct map *self); | |||
123 | 123 | ||
124 | void map__reloc_vmlinux(struct map *self); | 124 | void map__reloc_vmlinux(struct map *self); |
125 | 125 | ||
126 | size_t __map_groups__fprintf_maps(struct map_groups *self, | 126 | size_t __map_groups__fprintf_maps(struct map_groups *mg, |
127 | enum map_type type, int verbose, FILE *fp); | 127 | enum map_type type, int verbose, FILE *fp); |
128 | void maps__insert(struct rb_root *maps, struct map *map); | 128 | void maps__insert(struct rb_root *maps, struct map *map); |
129 | void maps__remove(struct rb_root *self, struct map *map); | 129 | void maps__remove(struct rb_root *maps, struct map *map); |
130 | struct map *maps__find(struct rb_root *maps, u64 addr); | 130 | struct map *maps__find(struct rb_root *maps, u64 addr); |
131 | void map_groups__init(struct map_groups *self); | 131 | void map_groups__init(struct map_groups *mg); |
132 | void map_groups__exit(struct map_groups *self); | 132 | void map_groups__exit(struct map_groups *mg); |
133 | int map_groups__clone(struct map_groups *self, | 133 | int map_groups__clone(struct map_groups *mg, |
134 | struct map_groups *parent, enum map_type type); | 134 | struct map_groups *parent, enum map_type type); |
135 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); | 135 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); |
136 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); | 136 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); |
137 | 137 | ||
138 | typedef void (*machine__process_t)(struct machine *self, void *data); | 138 | typedef void (*machine__process_t)(struct machine *self, void *data); |
139 | 139 | ||
@@ -162,29 +162,29 @@ static inline bool machine__is_host(struct machine *self) | |||
162 | return self ? self->pid == HOST_KERNEL_ID : false; | 162 | return self ? self->pid == HOST_KERNEL_ID : false; |
163 | } | 163 | } |
164 | 164 | ||
165 | static inline void map_groups__insert(struct map_groups *self, struct map *map) | 165 | static inline void map_groups__insert(struct map_groups *mg, struct map *map) |
166 | { | 166 | { |
167 | maps__insert(&self->maps[map->type], map); | 167 | maps__insert(&mg->maps[map->type], map); |
168 | map->groups = self; | 168 | map->groups = mg; |
169 | } | 169 | } |
170 | 170 | ||
171 | static inline void map_groups__remove(struct map_groups *self, struct map *map) | 171 | static inline void map_groups__remove(struct map_groups *mg, struct map *map) |
172 | { | 172 | { |
173 | maps__remove(&self->maps[map->type], map); | 173 | maps__remove(&mg->maps[map->type], map); |
174 | } | 174 | } |
175 | 175 | ||
176 | static inline struct map *map_groups__find(struct map_groups *self, | 176 | static inline struct map *map_groups__find(struct map_groups *mg, |
177 | enum map_type type, u64 addr) | 177 | enum map_type type, u64 addr) |
178 | { | 178 | { |
179 | return maps__find(&self->maps[type], addr); | 179 | return maps__find(&mg->maps[type], addr); |
180 | } | 180 | } |
181 | 181 | ||
182 | struct symbol *map_groups__find_symbol(struct map_groups *self, | 182 | struct symbol *map_groups__find_symbol(struct map_groups *mg, |
183 | enum map_type type, u64 addr, | 183 | enum map_type type, u64 addr, |
184 | struct map **mapp, | 184 | struct map **mapp, |
185 | symbol_filter_t filter); | 185 | symbol_filter_t filter); |
186 | 186 | ||
187 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | 187 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, |
188 | enum map_type type, | 188 | enum map_type type, |
189 | const char *name, | 189 | const char *name, |
190 | struct map **mapp, | 190 | struct map **mapp, |
@@ -208,11 +208,11 @@ struct symbol *machine__find_kernel_function(struct machine *self, u64 addr, | |||
208 | } | 208 | } |
209 | 209 | ||
210 | static inline | 210 | static inline |
211 | struct symbol *map_groups__find_function_by_name(struct map_groups *self, | 211 | struct symbol *map_groups__find_function_by_name(struct map_groups *mg, |
212 | const char *name, struct map **mapp, | 212 | const char *name, struct map **mapp, |
213 | symbol_filter_t filter) | 213 | symbol_filter_t filter) |
214 | { | 214 | { |
215 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); | 215 | return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); |
216 | } | 216 | } |
217 | 217 | ||
218 | static inline | 218 | static inline |
@@ -225,13 +225,13 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *self, | |||
225 | filter); | 225 | filter); |
226 | } | 226 | } |
227 | 227 | ||
228 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | 228 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
229 | int verbose, FILE *fp); | 229 | int verbose, FILE *fp); |
230 | 230 | ||
231 | struct map *map_groups__find_by_name(struct map_groups *self, | 231 | struct map *map_groups__find_by_name(struct map_groups *mg, |
232 | enum map_type type, const char *name); | 232 | enum map_type type, const char *name); |
233 | struct map *machine__new_module(struct machine *self, u64 start, const char *filename); | 233 | struct map *machine__new_module(struct machine *self, u64 start, const char *filename); |
234 | 234 | ||
235 | void map_groups__flush(struct map_groups *self); | 235 | void map_groups__flush(struct map_groups *mg); |
236 | 236 | ||
237 | #endif /* __PERF_MAP_H */ | 237 | #endif /* __PERF_MAP_H */ |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4ea7e19f5251..928918b796b2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -697,7 +697,11 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr) | |||
697 | return EVT_FAILED; | 697 | return EVT_FAILED; |
698 | n = hex2u64(str + 1, &config); | 698 | n = hex2u64(str + 1, &config); |
699 | if (n > 0) { | 699 | if (n > 0) { |
700 | *strp = str + n + 1; | 700 | const char *end = str + n + 1; |
701 | if (*end != '\0' && *end != ',' && *end != ':') | ||
702 | return EVT_FAILED; | ||
703 | |||
704 | *strp = end; | ||
701 | attr->type = PERF_TYPE_RAW; | 705 | attr->type = PERF_TYPE_RAW; |
702 | attr->config = config; | 706 | attr->config = config; |
703 | return EVT_HANDLED; | 707 | return EVT_HANDLED; |
@@ -1097,6 +1101,4 @@ void print_events(const char *event_glob) | |||
1097 | printf("\n"); | 1101 | printf("\n"); |
1098 | 1102 | ||
1099 | print_tracepoint_events(NULL, NULL); | 1103 | print_tracepoint_events(NULL, NULL); |
1100 | |||
1101 | exit(129); | ||
1102 | } | 1104 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b82d54fa2c56..eb25900e2211 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1820 | ret = -ENOMEM; | 1820 | ret = -ENOMEM; |
1821 | goto error; | 1821 | goto error; |
1822 | } | 1822 | } |
1823 | tev->point.module = strdup(module); | 1823 | |
1824 | if (tev->point.module == NULL) { | 1824 | if (module) { |
1825 | ret = -ENOMEM; | 1825 | tev->point.module = strdup(module); |
1826 | goto error; | 1826 | if (tev->point.module == NULL) { |
1827 | ret = -ENOMEM; | ||
1828 | goto error; | ||
1829 | } | ||
1827 | } | 1830 | } |
1831 | |||
1828 | tev->point.offset = pev->point.offset; | 1832 | tev->point.offset = pev->point.offset; |
1829 | tev->point.retprobe = pev->point.retprobe; | 1833 | tev->point.retprobe = pev->point.retprobe; |
1830 | tev->nargs = pev->nargs; | 1834 | tev->nargs = pev->nargs; |
@@ -1952,8 +1956,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) | |||
1952 | 1956 | ||
1953 | pr_debug("Writing event: %s\n", buf); | 1957 | pr_debug("Writing event: %s\n", buf); |
1954 | ret = write(fd, buf, strlen(buf)); | 1958 | ret = write(fd, buf, strlen(buf)); |
1955 | if (ret < 0) | 1959 | if (ret < 0) { |
1960 | ret = -errno; | ||
1956 | goto error; | 1961 | goto error; |
1962 | } | ||
1957 | 1963 | ||
1958 | printf("Remove event: %s\n", ent->s); | 1964 | printf("Remove event: %s\n", ent->s); |
1959 | return 0; | 1965 | return 0; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e44a3e36519..5d732621a462 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
612 | return ret; | 612 | return ret; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* Find a variable in a subprogram die */ | 615 | /* Find a variable in a scope DIE */ |
616 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
617 | { | 617 | { |
618 | Dwarf_Die vr_die, *scopes; | 618 | Dwarf_Die vr_die; |
619 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
620 | int ret, nscopes; | 620 | int ret = 0; |
621 | 621 | ||
622 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
623 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
652 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
653 | return -ENOMEM; | 653 | return -ENOMEM; |
654 | 654 | ||
655 | pr_debug("Searching '%s' variable in context.\n", | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
656 | pf->pvar->var); | ||
657 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
658 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
659 | ret = convert_variable(&vr_die, pf); | 658 | /* Search again in global variables */ |
660 | else { | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
661 | /* Search upper class */ | 660 | ret = -ENOENT; |
662 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | ||
663 | while (nscopes-- > 1) { | ||
664 | pr_debug("Searching variables in %s\n", | ||
665 | dwarf_diename(&scopes[nscopes])); | ||
666 | /* We should check this scope, so give dummy address */ | ||
667 | if (die_find_variable_at(&scopes[nscopes], | ||
668 | pf->pvar->var, 0, | ||
669 | &vr_die)) { | ||
670 | ret = convert_variable(&vr_die, pf); | ||
671 | goto found; | ||
672 | } | ||
673 | } | ||
674 | if (scopes) | ||
675 | free(scopes); | ||
676 | ret = -ENOENT; | ||
677 | } | 661 | } |
678 | found: | 662 | if (ret >= 0) |
663 | ret = convert_variable(&vr_die, pf); | ||
664 | |||
679 | if (ret < 0) | 665 | if (ret < 0) |
680 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
681 | pf->pvar->var); | 667 | pf->pvar->var); |
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | |||
718 | return 0; | 704 | return 0; |
719 | } | 705 | } |
720 | 706 | ||
721 | /* Call probe_finder callback with real subprogram DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
722 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
723 | { | 709 | { |
724 | Dwarf_Die die_mem; | ||
725 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
726 | size_t nops; | 711 | size_t nops; |
727 | int ret; | 712 | int ret; |
728 | 713 | ||
729 | /* If no real subprogram, find a real one */ | 714 | if (!sc_die) { |
730 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
731 | sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); | 716 | return -EINVAL; |
732 | if (!sp_die) { | 717 | } |
718 | |||
719 | /* If not a real subprogram, find a real one */ | ||
720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | ||
721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | ||
733 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
734 | "functions.\n"); | 723 | "functions.\n"); |
735 | return -ENOENT; | 724 | return -ENOENT; |
736 | } | 725 | } |
737 | } | 726 | } else |
727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | ||
738 | 728 | ||
739 | /* Get the frame base attribute/ops */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
740 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
741 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
742 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
743 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
755 | } | 745 | } |
756 | 746 | ||
757 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
758 | ret = pf->callback(sp_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
759 | 749 | ||
760 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
761 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
763 | return ret; | 753 | return ret; |
764 | } | 754 | } |
765 | 755 | ||
756 | struct find_scope_param { | ||
757 | const char *function; | ||
758 | const char *file; | ||
759 | int line; | ||
760 | int diff; | ||
761 | Dwarf_Die *die_mem; | ||
762 | bool found; | ||
763 | }; | ||
764 | |||
765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | ||
766 | { | ||
767 | struct find_scope_param *fsp = data; | ||
768 | const char *file; | ||
769 | int lno; | ||
770 | |||
771 | /* Skip if declared file name does not match */ | ||
772 | if (fsp->file) { | ||
773 | file = dwarf_decl_file(fn_die); | ||
774 | if (!file || strcmp(fsp->file, file) != 0) | ||
775 | return 0; | ||
776 | } | ||
777 | /* If the function name is given, that's what user expects */ | ||
778 | if (fsp->function) { | ||
779 | if (die_compare_name(fn_die, fsp->function)) { | ||
780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
781 | fsp->found = true; | ||
782 | return 1; | ||
783 | } | ||
784 | } else { | ||
785 | /* With the line number, find the nearest declared DIE */ | ||
786 | dwarf_decl_line(fn_die, &lno); | ||
787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | ||
788 | /* Keep a candidate and continue */ | ||
789 | fsp->diff = fsp->line - lno; | ||
790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
791 | fsp->found = true; | ||
792 | } | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | /* Find an appropriate scope fits to given conditions */ | ||
798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | ||
799 | { | ||
800 | struct find_scope_param fsp = { | ||
801 | .function = pf->pev->point.function, | ||
802 | .file = pf->fname, | ||
803 | .line = pf->lno, | ||
804 | .diff = INT_MAX, | ||
805 | .die_mem = die_mem, | ||
806 | .found = false, | ||
807 | }; | ||
808 | |||
809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | ||
810 | |||
811 | return fsp.found ? die_mem : NULL; | ||
812 | } | ||
813 | |||
766 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
767 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
768 | { | 816 | { |
769 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
818 | Dwarf_Die *sc_die, die_mem; | ||
770 | int ret; | 819 | int ret; |
771 | 820 | ||
772 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
773 | return 0; | 822 | return 0; |
774 | 823 | ||
775 | pf->addr = addr; | 824 | pf->addr = addr; |
776 | ret = call_probe_finder(NULL, pf); | 825 | sc_die = find_best_scope(pf, &die_mem); |
826 | if (!sc_die) { | ||
827 | pr_warning("Failed to find scope of probe point.\n"); | ||
828 | return -ENOENT; | ||
829 | } | ||
830 | |||
831 | ret = call_probe_finder(sc_die, pf); | ||
777 | 832 | ||
778 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
779 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
827 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
828 | { | 883 | { |
829 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
885 | Dwarf_Die *sc_die, die_mem; | ||
830 | int ret; | 886 | int ret; |
831 | 887 | ||
832 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
836 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
837 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
838 | pf->addr = addr; | 894 | pf->addr = addr; |
839 | ret = call_probe_finder(NULL, pf); | 895 | pf->lno = lineno; |
896 | sc_die = find_best_scope(pf, &die_mem); | ||
897 | if (!sc_die) { | ||
898 | pr_warning("Failed to find scope of probe point.\n"); | ||
899 | return -ENOENT; | ||
900 | } | ||
901 | |||
902 | ret = call_probe_finder(sc_die, pf); | ||
840 | 903 | ||
841 | /* | 904 | /* |
842 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
861 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
862 | } | 925 | } |
863 | 926 | ||
864 | /* Callback parameter with return value */ | ||
865 | struct dwarf_callback_param { | ||
866 | void *data; | ||
867 | int retval; | ||
868 | }; | ||
869 | |||
870 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
871 | { | 928 | { |
872 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
873 | struct probe_finder *pf = param->data; | ||
874 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
875 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
932 | int ret; | ||
876 | 933 | ||
877 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
878 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
879 | else { | 936 | else { |
880 | /* Get probe address */ | 937 | /* Get probe address */ |
881 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
882 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
883 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
884 | param->retval = -ENOENT; | 941 | return -ENOENT; |
885 | return DWARF_CB_ABORT; | ||
886 | } | 942 | } |
887 | pf->addr = addr; | 943 | pf->addr = addr; |
888 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
889 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
890 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
891 | 947 | ||
892 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
893 | if (param->retval < 0) | ||
894 | return DWARF_CB_ABORT; | ||
895 | } | 949 | } |
896 | 950 | ||
897 | return DWARF_CB_OK; | 951 | return ret; |
898 | } | 952 | } |
899 | 953 | ||
954 | /* Callback parameter with return value for libdw */ | ||
955 | struct dwarf_callback_param { | ||
956 | void *data; | ||
957 | int retval; | ||
958 | }; | ||
959 | |||
900 | /* Search function from function name */ | 960 | /* Search function from function name */ |
901 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
902 | { | 962 | { |
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
933 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
934 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
935 | } | 995 | } |
936 | } else { | 996 | } else |
937 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
938 | .retval = 0}; | ||
939 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
940 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
941 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
942 | param->retval = _param.retval; | ||
943 | } | ||
944 | 1000 | ||
945 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
946 | } | 1002 | } |
@@ -1060,7 +1116,7 @@ found: | |||
1060 | } | 1116 | } |
1061 | 1117 | ||
1062 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
1063 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1064 | { | 1120 | { |
1065 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
1066 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1075 | } | 1131 | } |
1076 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
1077 | 1133 | ||
1078 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1134 | /* Trace point should be converted from subprogram DIE */ |
1079 | &tev->point); | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1136 | pf->pev->point.retprobe, &tev->point); | ||
1080 | if (ret < 0) | 1137 | if (ret < 0) |
1081 | return ret; | 1138 | return ret; |
1082 | 1139 | ||
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1091 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
1092 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
1093 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
1094 | ret = find_variable(sp_die, pf); | 1151 | /* Variable should be found from scope DIE */ |
1152 | ret = find_variable(sc_die, pf); | ||
1095 | if (ret != 0) | 1153 | if (ret != 0) |
1096 | return ret; | 1154 | return ret; |
1097 | } | 1155 | } |
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1159 | } | 1217 | } |
1160 | 1218 | ||
1161 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
1162 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
1163 | { | 1221 | { |
1164 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
1165 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
1166 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
1167 | Dwarf_Die die_mem, *scopes = NULL; | 1225 | Dwarf_Die die_mem; |
1168 | int ret, nscopes; | 1226 | int ret; |
1169 | 1227 | ||
1170 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
1171 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1174 | } | 1232 | } |
1175 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
1176 | 1234 | ||
1177 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1235 | /* Trace point should be converted from subprogram DIE */ |
1178 | &vl->point); | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1237 | pf->pev->point.retprobe, &vl->point); | ||
1179 | if (ret < 0) | 1238 | if (ret < 0) |
1180 | return ret; | 1239 | return ret; |
1181 | 1240 | ||
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1187 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
1188 | return -ENOMEM; | 1247 | return -ENOMEM; |
1189 | af->child = true; | 1248 | af->child = true; |
1190 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
1191 | 1250 | ||
1192 | /* Find external variables */ | 1251 | /* Find external variables */ |
1193 | if (!af->externs) | 1252 | if (!af->externs) |
1194 | goto out; | 1253 | goto out; |
1195 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
1196 | af->child = false; | 1255 | af->child = false; |
1197 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
1198 | while (nscopes-- > 1) | ||
1199 | die_find_child(&scopes[nscopes], collect_variables_cb, | ||
1200 | (void *)af, &die_mem); | ||
1201 | if (scopes) | ||
1202 | free(scopes); | ||
1203 | 1257 | ||
1204 | out: | 1258 | out: |
1205 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1391 | 1445 | ||
1392 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1393 | { | 1447 | { |
1394 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
1395 | 1449 | ||
1396 | param->retval = find_line_range_by_line(in_die, param->data); | 1450 | /* |
1397 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1451 | * We have to check all instances of inlined function, because |
1452 | * some execution paths can be optimized out depends on the | ||
1453 | * function argument of instances | ||
1454 | */ | ||
1455 | return 0; | ||
1398 | } | 1456 | } |
1399 | 1457 | ||
1400 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1422 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1423 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
1424 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
1425 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
1426 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
1427 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
1428 | _param.retval = 0; | 1486 | else |
1429 | dwarf_func_inline_instances(sp_die, | ||
1430 | line_range_inline_cb, | ||
1431 | &_param); | ||
1432 | param->retval = _param.retval; | ||
1433 | } else | ||
1434 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1435 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
1436 | } | 1489 | } |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index c478b42a2473..1132c8f0ce89 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -57,7 +57,7 @@ struct probe_finder { | |||
57 | struct perf_probe_event *pev; /* Target probe event */ | 57 | struct perf_probe_event *pev; /* Target probe event */ |
58 | 58 | ||
59 | /* Callback when a probe point is found */ | 59 | /* Callback when a probe point is found */ |
60 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); | 60 | int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf); |
61 | 61 | ||
62 | /* For function searching */ | 62 | /* For function searching */ |
63 | int lno; /* Line number */ | 63 | int lno; /* Line number */ |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 8e0b5a39d8a7..9dd47a4f2596 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -187,16 +187,119 @@ static PyTypeObject pyrf_throttle_event__type = { | |||
187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, | 187 | .tp_repr = (reprfunc)pyrf_throttle_event__repr, |
188 | }; | 188 | }; |
189 | 189 | ||
190 | static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); | ||
191 | |||
192 | static PyMemberDef pyrf_lost_event__members[] = { | ||
193 | sample_members | ||
194 | member_def(lost_event, id, T_ULONGLONG, "event id"), | ||
195 | member_def(lost_event, lost, T_ULONGLONG, "number of lost events"), | ||
196 | { .name = NULL, }, | ||
197 | }; | ||
198 | |||
199 | static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) | ||
200 | { | ||
201 | PyObject *ret; | ||
202 | char *s; | ||
203 | |||
204 | if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", " | ||
205 | "lost: %#" PRIx64 " }", | ||
206 | pevent->event.lost.id, pevent->event.lost.lost) < 0) { | ||
207 | ret = PyErr_NoMemory(); | ||
208 | } else { | ||
209 | ret = PyString_FromString(s); | ||
210 | free(s); | ||
211 | } | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | static PyTypeObject pyrf_lost_event__type = { | ||
216 | PyVarObject_HEAD_INIT(NULL, 0) | ||
217 | .tp_name = "perf.lost_event", | ||
218 | .tp_basicsize = sizeof(struct pyrf_event), | ||
219 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
220 | .tp_doc = pyrf_lost_event__doc, | ||
221 | .tp_members = pyrf_lost_event__members, | ||
222 | .tp_repr = (reprfunc)pyrf_lost_event__repr, | ||
223 | }; | ||
224 | |||
225 | static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); | ||
226 | |||
227 | static PyMemberDef pyrf_read_event__members[] = { | ||
228 | sample_members | ||
229 | member_def(read_event, pid, T_UINT, "event pid"), | ||
230 | member_def(read_event, tid, T_UINT, "event tid"), | ||
231 | { .name = NULL, }, | ||
232 | }; | ||
233 | |||
234 | static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent) | ||
235 | { | ||
236 | return PyString_FromFormat("{ type: read, pid: %u, tid: %u }", | ||
237 | pevent->event.read.pid, | ||
238 | pevent->event.read.tid); | ||
239 | /* | ||
240 | * FIXME: return the array of read values, | ||
241 | * making this method useful ;-) | ||
242 | */ | ||
243 | } | ||
244 | |||
245 | static PyTypeObject pyrf_read_event__type = { | ||
246 | PyVarObject_HEAD_INIT(NULL, 0) | ||
247 | .tp_name = "perf.read_event", | ||
248 | .tp_basicsize = sizeof(struct pyrf_event), | ||
249 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
250 | .tp_doc = pyrf_read_event__doc, | ||
251 | .tp_members = pyrf_read_event__members, | ||
252 | .tp_repr = (reprfunc)pyrf_read_event__repr, | ||
253 | }; | ||
254 | |||
255 | static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object."); | ||
256 | |||
257 | static PyMemberDef pyrf_sample_event__members[] = { | ||
258 | sample_members | ||
259 | member_def(perf_event_header, type, T_UINT, "event type"), | ||
260 | { .name = NULL, }, | ||
261 | }; | ||
262 | |||
263 | static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) | ||
264 | { | ||
265 | PyObject *ret; | ||
266 | char *s; | ||
267 | |||
268 | if (asprintf(&s, "{ type: sample }") < 0) { | ||
269 | ret = PyErr_NoMemory(); | ||
270 | } else { | ||
271 | ret = PyString_FromString(s); | ||
272 | free(s); | ||
273 | } | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static PyTypeObject pyrf_sample_event__type = { | ||
278 | PyVarObject_HEAD_INIT(NULL, 0) | ||
279 | .tp_name = "perf.sample_event", | ||
280 | .tp_basicsize = sizeof(struct pyrf_event), | ||
281 | .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | ||
282 | .tp_doc = pyrf_sample_event__doc, | ||
283 | .tp_members = pyrf_sample_event__members, | ||
284 | .tp_repr = (reprfunc)pyrf_sample_event__repr, | ||
285 | }; | ||
286 | |||
190 | static int pyrf_event__setup_types(void) | 287 | static int pyrf_event__setup_types(void) |
191 | { | 288 | { |
192 | int err; | 289 | int err; |
193 | pyrf_mmap_event__type.tp_new = | 290 | pyrf_mmap_event__type.tp_new = |
194 | pyrf_task_event__type.tp_new = | 291 | pyrf_task_event__type.tp_new = |
195 | pyrf_comm_event__type.tp_new = | 292 | pyrf_comm_event__type.tp_new = |
293 | pyrf_lost_event__type.tp_new = | ||
294 | pyrf_read_event__type.tp_new = | ||
295 | pyrf_sample_event__type.tp_new = | ||
196 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; | 296 | pyrf_throttle_event__type.tp_new = PyType_GenericNew; |
197 | err = PyType_Ready(&pyrf_mmap_event__type); | 297 | err = PyType_Ready(&pyrf_mmap_event__type); |
198 | if (err < 0) | 298 | if (err < 0) |
199 | goto out; | 299 | goto out; |
300 | err = PyType_Ready(&pyrf_lost_event__type); | ||
301 | if (err < 0) | ||
302 | goto out; | ||
200 | err = PyType_Ready(&pyrf_task_event__type); | 303 | err = PyType_Ready(&pyrf_task_event__type); |
201 | if (err < 0) | 304 | if (err < 0) |
202 | goto out; | 305 | goto out; |
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void) | |||
206 | err = PyType_Ready(&pyrf_throttle_event__type); | 309 | err = PyType_Ready(&pyrf_throttle_event__type); |
207 | if (err < 0) | 310 | if (err < 0) |
208 | goto out; | 311 | goto out; |
312 | err = PyType_Ready(&pyrf_read_event__type); | ||
313 | if (err < 0) | ||
314 | goto out; | ||
315 | err = PyType_Ready(&pyrf_sample_event__type); | ||
316 | if (err < 0) | ||
317 | goto out; | ||
209 | out: | 318 | out: |
210 | return err; | 319 | return err; |
211 | } | 320 | } |
212 | 321 | ||
213 | static PyTypeObject *pyrf_event__type[] = { | 322 | static PyTypeObject *pyrf_event__type[] = { |
214 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, | 323 | [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, |
215 | [PERF_RECORD_LOST] = &pyrf_mmap_event__type, | 324 | [PERF_RECORD_LOST] = &pyrf_lost_event__type, |
216 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, | 325 | [PERF_RECORD_COMM] = &pyrf_comm_event__type, |
217 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, | 326 | [PERF_RECORD_EXIT] = &pyrf_task_event__type, |
218 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, | 327 | [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, |
219 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, | 328 | [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, |
220 | [PERF_RECORD_FORK] = &pyrf_task_event__type, | 329 | [PERF_RECORD_FORK] = &pyrf_task_event__type, |
221 | [PERF_RECORD_READ] = &pyrf_mmap_event__type, | 330 | [PERF_RECORD_READ] = &pyrf_read_event__type, |
222 | [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, | 331 | [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type, |
223 | }; | 332 | }; |
224 | 333 | ||
225 | static PyObject *pyrf_event__new(union perf_event *event) | 334 | static PyObject *pyrf_event__new(union perf_event *event) |
@@ -514,7 +623,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, | |||
514 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; | 623 | cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; |
515 | 624 | ||
516 | evsel->attr.inherit = inherit; | 625 | evsel->attr.inherit = inherit; |
517 | if (perf_evsel__open(evsel, cpus, threads, group) < 0) { | 626 | /* |
627 | * This will group just the fds for this single evsel, to group | ||
628 | * multiple events, use evlist.open(). | ||
629 | */ | ||
630 | if (perf_evsel__open(evsel, cpus, threads, group, NULL) < 0) { | ||
518 | PyErr_SetFromErrno(PyExc_OSError); | 631 | PyErr_SetFromErrno(PyExc_OSError); |
519 | return NULL; | 632 | return NULL; |
520 | } | 633 | } |
@@ -694,7 +807,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
694 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 807 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
695 | err = perf_event__parse_sample(event, first->attr.sample_type, | 808 | err = perf_event__parse_sample(event, first->attr.sample_type, |
696 | perf_evsel__sample_size(first), | 809 | perf_evsel__sample_size(first), |
697 | sample_id_all, &pevent->sample); | 810 | sample_id_all, &pevent->sample, false); |
698 | if (err) | 811 | if (err) |
699 | return PyErr_Format(PyExc_OSError, | 812 | return PyErr_Format(PyExc_OSError, |
700 | "perf: can't parse sample, err=%d", err); | 813 | "perf: can't parse sample, err=%d", err); |
@@ -705,6 +818,25 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
705 | return Py_None; | 818 | return Py_None; |
706 | } | 819 | } |
707 | 820 | ||
821 | static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, | ||
822 | PyObject *args, PyObject *kwargs) | ||
823 | { | ||
824 | struct perf_evlist *evlist = &pevlist->evlist; | ||
825 | int group = 0; | ||
826 | static char *kwlist[] = { "group", NULL }; | ||
827 | |||
828 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group)) | ||
829 | return NULL; | ||
830 | |||
831 | if (perf_evlist__open(evlist, group) < 0) { | ||
832 | PyErr_SetFromErrno(PyExc_OSError); | ||
833 | return NULL; | ||
834 | } | ||
835 | |||
836 | Py_INCREF(Py_None); | ||
837 | return Py_None; | ||
838 | } | ||
839 | |||
708 | static PyMethodDef pyrf_evlist__methods[] = { | 840 | static PyMethodDef pyrf_evlist__methods[] = { |
709 | { | 841 | { |
710 | .ml_name = "mmap", | 842 | .ml_name = "mmap", |
@@ -713,6 +845,12 @@ static PyMethodDef pyrf_evlist__methods[] = { | |||
713 | .ml_doc = PyDoc_STR("mmap the file descriptor table.") | 845 | .ml_doc = PyDoc_STR("mmap the file descriptor table.") |
714 | }, | 846 | }, |
715 | { | 847 | { |
848 | .ml_name = "open", | ||
849 | .ml_meth = (PyCFunction)pyrf_evlist__open, | ||
850 | .ml_flags = METH_VARARGS | METH_KEYWORDS, | ||
851 | .ml_doc = PyDoc_STR("open the file descriptors.") | ||
852 | }, | ||
853 | { | ||
716 | .ml_name = "poll", | 854 | .ml_name = "poll", |
717 | .ml_meth = (PyCFunction)pyrf_evlist__poll, | 855 | .ml_meth = (PyCFunction)pyrf_evlist__poll, |
718 | .ml_flags = METH_VARARGS | METH_KEYWORDS, | 856 | .ml_flags = METH_VARARGS | METH_KEYWORDS, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 72458d9da5b1..85c1e6b76f0a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -502,6 +502,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
502 | struct perf_sample sample; | 502 | struct perf_sample sample; |
503 | u64 limit = os->next_flush; | 503 | u64 limit = os->next_flush; |
504 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 504 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
505 | unsigned idx = 0, progress_next = os->nr_samples / 16; | ||
505 | int ret; | 506 | int ret; |
506 | 507 | ||
507 | if (!ops->ordered_samples || !limit) | 508 | if (!ops->ordered_samples || !limit) |
@@ -521,6 +522,11 @@ static void flush_sample_queue(struct perf_session *s, | |||
521 | os->last_flush = iter->timestamp; | 522 | os->last_flush = iter->timestamp; |
522 | list_del(&iter->list); | 523 | list_del(&iter->list); |
523 | list_add(&iter->list, &os->sample_cache); | 524 | list_add(&iter->list, &os->sample_cache); |
525 | if (++idx >= progress_next) { | ||
526 | progress_next += os->nr_samples / 16; | ||
527 | ui_progress__update(idx, os->nr_samples, | ||
528 | "Processing time ordered events..."); | ||
529 | } | ||
524 | } | 530 | } |
525 | 531 | ||
526 | if (list_empty(head)) { | 532 | if (list_empty(head)) { |
@@ -529,6 +535,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
529 | os->last_sample = | 535 | os->last_sample = |
530 | list_entry(head->prev, struct sample_queue, list); | 536 | list_entry(head->prev, struct sample_queue, list); |
531 | } | 537 | } |
538 | |||
539 | os->nr_samples = 0; | ||
532 | } | 540 | } |
533 | 541 | ||
534 | /* | 542 | /* |
@@ -588,6 +596,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
588 | u64 timestamp = new->timestamp; | 596 | u64 timestamp = new->timestamp; |
589 | struct list_head *p; | 597 | struct list_head *p; |
590 | 598 | ||
599 | ++os->nr_samples; | ||
591 | os->last_sample = new; | 600 | os->last_sample = new; |
592 | 601 | ||
593 | if (!sample) { | 602 | if (!sample) { |
@@ -738,10 +747,27 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
738 | 747 | ||
739 | dump_event(session, event, file_offset, sample); | 748 | dump_event(session, event, file_offset, sample); |
740 | 749 | ||
750 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
751 | if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) { | ||
752 | /* | ||
753 | * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here | ||
754 | * because the tools right now may apply filters, discarding | ||
755 | * some of the samples. For consistency, in the future we | ||
756 | * should have something like nr_filtered_samples and remove | ||
757 | * the sample->period from total_sample_period, etc, KISS for | ||
758 | * now tho. | ||
759 | * | ||
760 | * Also testing against NULL allows us to handle files without | ||
761 | * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the | ||
762 | * future probably it'll be a good idea to restrict event | ||
763 | * processing via perf_session to files with both set. | ||
764 | */ | ||
765 | hists__inc_nr_events(&evsel->hists, event->header.type); | ||
766 | } | ||
767 | |||
741 | switch (event->header.type) { | 768 | switch (event->header.type) { |
742 | case PERF_RECORD_SAMPLE: | 769 | case PERF_RECORD_SAMPLE: |
743 | dump_sample(session, event, sample); | 770 | dump_sample(session, event, sample); |
744 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
745 | if (evsel == NULL) { | 771 | if (evsel == NULL) { |
746 | ++session->hists.stats.nr_unknown_id; | 772 | ++session->hists.stats.nr_unknown_id; |
747 | return -1; | 773 | return -1; |
@@ -874,11 +900,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
874 | const struct perf_event_ops *ops) | 900 | const struct perf_event_ops *ops) |
875 | { | 901 | { |
876 | if (ops->lost == perf_event__process_lost && | 902 | if (ops->lost == perf_event__process_lost && |
877 | session->hists.stats.total_lost != 0) { | 903 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { |
878 | ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 | 904 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
879 | "!\n\nCheck IO/CPU overload!\n\n", | 905 | "Check IO/CPU overload!\n\n", |
880 | session->hists.stats.total_period, | 906 | session->hists.stats.nr_events[0], |
881 | session->hists.stats.total_lost); | 907 | session->hists.stats.nr_events[PERF_RECORD_LOST]); |
882 | } | 908 | } |
883 | 909 | ||
884 | if (session->hists.stats.nr_unknown_events != 0) { | 910 | if (session->hists.stats.nr_unknown_events != 0) { |
@@ -1012,7 +1038,6 @@ int __perf_session__process_events(struct perf_session *session, | |||
1012 | { | 1038 | { |
1013 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1039 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1014 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1040 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1015 | struct ui_progress *progress; | ||
1016 | size_t page_size, mmap_size; | 1041 | size_t page_size, mmap_size; |
1017 | char *buf, *mmaps[8]; | 1042 | char *buf, *mmaps[8]; |
1018 | union perf_event *event; | 1043 | union perf_event *event; |
@@ -1030,9 +1055,6 @@ int __perf_session__process_events(struct perf_session *session, | |||
1030 | file_size = data_offset + data_size; | 1055 | file_size = data_offset + data_size; |
1031 | 1056 | ||
1032 | progress_next = file_size / 16; | 1057 | progress_next = file_size / 16; |
1033 | progress = ui_progress__new("Processing events...", file_size); | ||
1034 | if (progress == NULL) | ||
1035 | return -1; | ||
1036 | 1058 | ||
1037 | mmap_size = session->mmap_window; | 1059 | mmap_size = session->mmap_window; |
1038 | if (mmap_size > file_size) | 1060 | if (mmap_size > file_size) |
@@ -1095,7 +1117,8 @@ more: | |||
1095 | 1117 | ||
1096 | if (file_pos >= progress_next) { | 1118 | if (file_pos >= progress_next) { |
1097 | progress_next += file_size / 16; | 1119 | progress_next += file_size / 16; |
1098 | ui_progress__update(progress, file_pos); | 1120 | ui_progress__update(file_pos, file_size, |
1121 | "Processing events..."); | ||
1099 | } | 1122 | } |
1100 | 1123 | ||
1101 | if (file_pos < file_size) | 1124 | if (file_pos < file_size) |
@@ -1106,7 +1129,6 @@ more: | |||
1106 | session->ordered_samples.next_flush = ULLONG_MAX; | 1129 | session->ordered_samples.next_flush = ULLONG_MAX; |
1107 | flush_sample_queue(session, ops); | 1130 | flush_sample_queue(session, ops); |
1108 | out_err: | 1131 | out_err: |
1109 | ui_progress__delete(progress); | ||
1110 | perf_session__warn_about_errors(session, ops); | 1132 | perf_session__warn_about_errors(session, ops); |
1111 | perf_session_free_sample_buffers(session); | 1133 | perf_session_free_sample_buffers(session); |
1112 | return err; | 1134 | return err; |
@@ -1326,3 +1348,22 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
1326 | 1348 | ||
1327 | return 0; | 1349 | return 0; |
1328 | } | 1350 | } |
1351 | |||
1352 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, | ||
1353 | bool full) | ||
1354 | { | ||
1355 | struct stat st; | ||
1356 | int ret; | ||
1357 | |||
1358 | if (session == NULL || fp == NULL) | ||
1359 | return; | ||
1360 | |||
1361 | ret = fstat(session->fd, &st); | ||
1362 | if (ret == -1) | ||
1363 | return; | ||
1364 | |||
1365 | fprintf(fp, "# ========\n"); | ||
1366 | fprintf(fp, "# captured on: %s", ctime(&st.st_ctime)); | ||
1367 | perf_header__fprintf_info(session, fp, full); | ||
1368 | fprintf(fp, "# ========\n#\n"); | ||
1369 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 170601e67d6b..6e393c98eb34 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -23,6 +23,7 @@ struct ordered_samples { | |||
23 | struct sample_queue *sample_buffer; | 23 | struct sample_queue *sample_buffer; |
24 | struct sample_queue *last_sample; | 24 | struct sample_queue *last_sample; |
25 | int sample_buffer_idx; | 25 | int sample_buffer_idx; |
26 | unsigned int nr_samples; | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | struct perf_session { | 29 | struct perf_session { |
@@ -162,7 +163,8 @@ static inline int perf_session__parse_sample(struct perf_session *session, | |||
162 | { | 163 | { |
163 | return perf_event__parse_sample(event, session->sample_type, | 164 | return perf_event__parse_sample(event, session->sample_type, |
164 | session->sample_size, | 165 | session->sample_size, |
165 | session->sample_id_all, sample); | 166 | session->sample_id_all, sample, |
167 | session->header.needs_swap); | ||
166 | } | 168 | } |
167 | 169 | ||
168 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 170 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
@@ -176,4 +178,5 @@ void perf_session__print_ip(union perf_event *event, | |||
176 | int perf_session__cpu_bitmap(struct perf_session *session, | 178 | int perf_session__cpu_bitmap(struct perf_session *session, |
177 | const char *cpu_list, unsigned long *cpu_bitmap); | 179 | const char *cpu_list, unsigned long *cpu_bitmap); |
178 | 180 | ||
181 | void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); | ||
179 | #endif /* __PERF_SESSION_H */ | 182 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index bbc982f5dd8b..95d370074928 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -3,9 +3,27 @@ | |||
3 | from distutils.core import setup, Extension | 3 | from distutils.core import setup, Extension |
4 | from os import getenv | 4 | from os import getenv |
5 | 5 | ||
6 | from distutils.command.build_ext import build_ext as _build_ext | ||
7 | from distutils.command.install_lib import install_lib as _install_lib | ||
8 | |||
9 | class build_ext(_build_ext): | ||
10 | def finalize_options(self): | ||
11 | _build_ext.finalize_options(self) | ||
12 | self.build_lib = build_lib | ||
13 | self.build_temp = build_tmp | ||
14 | |||
15 | class install_lib(_install_lib): | ||
16 | def finalize_options(self): | ||
17 | _install_lib.finalize_options(self) | ||
18 | self.build_dir = build_lib | ||
19 | |||
20 | |||
6 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] | 21 | cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] |
7 | cflags += getenv('CFLAGS', '').split() | 22 | cflags += getenv('CFLAGS', '').split() |
8 | 23 | ||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | ||
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | ||
26 | |||
9 | perf = Extension('perf', | 27 | perf = Extension('perf', |
10 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', | 28 | sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', |
11 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', | 29 | 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', |
@@ -21,4 +39,5 @@ setup(name='perf', | |||
21 | author_email='acme@redhat.com', | 39 | author_email='acme@redhat.com', |
22 | license='GPLv2', | 40 | license='GPLv2', |
23 | url='http://perf.wiki.kernel.org', | 41 | url='http://perf.wiki.kernel.org', |
24 | ext_modules=[perf]) | 42 | ext_modules=[perf], |
43 | cmdclass={'build_ext': build_ext, 'install_lib': install_lib}) | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 401e220566fd..16da30d8d765 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
151 | { | 151 | { |
152 | u64 ip_l, ip_r; | 152 | u64 ip_l, ip_r; |
153 | 153 | ||
154 | if (!left->ms.sym && !right->ms.sym) | ||
155 | return right->level - left->level; | ||
156 | |||
157 | if (!left->ms.sym || !right->ms.sym) | ||
158 | return cmp_null(left->ms.sym, right->ms.sym); | ||
159 | |||
154 | if (left->ms.sym == right->ms.sym) | 160 | if (left->ms.sym == right->ms.sym) |
155 | return 0; | 161 | return 0; |
156 | 162 | ||
157 | ip_l = left->ms.sym ? left->ms.sym->start : left->ip; | 163 | ip_l = left->ms.sym->start; |
158 | ip_r = right->ms.sym ? right->ms.sym->start : right->ip; | 164 | ip_r = right->ms.sym->start; |
159 | 165 | ||
160 | return (int64_t)(ip_r - ip_l); | 166 | return (int64_t)(ip_r - ip_l); |
161 | } | 167 | } |
@@ -171,7 +177,9 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |||
171 | BITS_PER_LONG / 4, self->ip, o); | 177 | BITS_PER_LONG / 4, self->ip, o); |
172 | } | 178 | } |
173 | 179 | ||
174 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); | 180 | if (!sort_dso.elide) |
181 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); | ||
182 | |||
175 | if (self->ms.sym) | 183 | if (self->ms.sym) |
176 | ret += repsep_snprintf(bf + ret, size - ret, "%s", | 184 | ret += repsep_snprintf(bf + ret, size - ret, "%s", |
177 | self->ms.sym->name); | 185 | self->ms.sym->name); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 77d0388ad415..3f67ae395752 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension; | |||
45 | * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding | 45 | * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding |
46 | */ | 46 | */ |
47 | struct hist_entry { | 47 | struct hist_entry { |
48 | struct rb_node rb_node_in; | ||
48 | struct rb_node rb_node; | 49 | struct rb_node rb_node; |
49 | u64 period; | 50 | u64 period; |
50 | u64 period_sys; | 51 | u64 period_sys; |
@@ -63,6 +64,7 @@ struct hist_entry { | |||
63 | 64 | ||
64 | bool init_have_children; | 65 | bool init_have_children; |
65 | char level; | 66 | char level; |
67 | bool used; | ||
66 | u8 filtered; | 68 | u8 filtered; |
67 | struct symbol *parent; | 69 | struct symbol *parent; |
68 | union { | 70 | union { |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index eec196329fd9..632b50c7bc26 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <sys/utsname.h> | 24 | #include <sys/utsname.h> |
25 | 25 | ||
26 | #ifndef KSYM_NAME_LEN | 26 | #ifndef KSYM_NAME_LEN |
27 | #define KSYM_NAME_LEN 128 | 27 | #define KSYM_NAME_LEN 256 |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #ifndef NT_GNU_BUILD_ID | 30 | #ifndef NT_GNU_BUILD_ID |
@@ -46,6 +46,7 @@ struct symbol_conf symbol_conf = { | |||
46 | .exclude_other = true, | 46 | .exclude_other = true, |
47 | .use_modules = true, | 47 | .use_modules = true, |
48 | .try_vmlinux_path = true, | 48 | .try_vmlinux_path = true, |
49 | .annotate_src = true, | ||
49 | .symfs = "", | 50 | .symfs = "", |
50 | }; | 51 | }; |
51 | 52 | ||
@@ -74,16 +75,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | |||
74 | 75 | ||
75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 76 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
76 | { | 77 | { |
78 | symbol_type = toupper(symbol_type); | ||
79 | |||
77 | switch (map_type) { | 80 | switch (map_type) { |
78 | case MAP__FUNCTION: | 81 | case MAP__FUNCTION: |
79 | return symbol_type == 'T' || symbol_type == 'W'; | 82 | return symbol_type == 'T' || symbol_type == 'W'; |
80 | case MAP__VARIABLE: | 83 | case MAP__VARIABLE: |
81 | return symbol_type == 'D' || symbol_type == 'd'; | 84 | return symbol_type == 'D'; |
82 | default: | 85 | default: |
83 | return false; | 86 | return false; |
84 | } | 87 | } |
85 | } | 88 | } |
86 | 89 | ||
90 | static int prefix_underscores_count(const char *str) | ||
91 | { | ||
92 | const char *tail = str; | ||
93 | |||
94 | while (*tail == '_') | ||
95 | tail++; | ||
96 | |||
97 | return tail - str; | ||
98 | } | ||
99 | |||
100 | #define SYMBOL_A 0 | ||
101 | #define SYMBOL_B 1 | ||
102 | |||
103 | static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | ||
104 | { | ||
105 | s64 a; | ||
106 | s64 b; | ||
107 | |||
108 | /* Prefer a symbol with non zero length */ | ||
109 | a = syma->end - syma->start; | ||
110 | b = symb->end - symb->start; | ||
111 | if ((b == 0) && (a > 0)) | ||
112 | return SYMBOL_A; | ||
113 | else if ((a == 0) && (b > 0)) | ||
114 | return SYMBOL_B; | ||
115 | |||
116 | /* Prefer a non weak symbol over a weak one */ | ||
117 | a = syma->binding == STB_WEAK; | ||
118 | b = symb->binding == STB_WEAK; | ||
119 | if (b && !a) | ||
120 | return SYMBOL_A; | ||
121 | if (a && !b) | ||
122 | return SYMBOL_B; | ||
123 | |||
124 | /* Prefer a global symbol over a non global one */ | ||
125 | a = syma->binding == STB_GLOBAL; | ||
126 | b = symb->binding == STB_GLOBAL; | ||
127 | if (a && !b) | ||
128 | return SYMBOL_A; | ||
129 | if (b && !a) | ||
130 | return SYMBOL_B; | ||
131 | |||
132 | /* Prefer a symbol with less underscores */ | ||
133 | a = prefix_underscores_count(syma->name); | ||
134 | b = prefix_underscores_count(symb->name); | ||
135 | if (b > a) | ||
136 | return SYMBOL_A; | ||
137 | else if (a > b) | ||
138 | return SYMBOL_B; | ||
139 | |||
140 | /* If all else fails, choose the symbol with the longest name */ | ||
141 | if (strlen(syma->name) >= strlen(symb->name)) | ||
142 | return SYMBOL_A; | ||
143 | else | ||
144 | return SYMBOL_B; | ||
145 | } | ||
146 | |||
147 | static void symbols__fixup_duplicate(struct rb_root *symbols) | ||
148 | { | ||
149 | struct rb_node *nd; | ||
150 | struct symbol *curr, *next; | ||
151 | |||
152 | nd = rb_first(symbols); | ||
153 | |||
154 | while (nd) { | ||
155 | curr = rb_entry(nd, struct symbol, rb_node); | ||
156 | again: | ||
157 | nd = rb_next(&curr->rb_node); | ||
158 | next = rb_entry(nd, struct symbol, rb_node); | ||
159 | |||
160 | if (!nd) | ||
161 | break; | ||
162 | |||
163 | if (curr->start != next->start) | ||
164 | continue; | ||
165 | |||
166 | if (choose_best_symbol(curr, next) == SYMBOL_A) { | ||
167 | rb_erase(&next->rb_node, symbols); | ||
168 | goto again; | ||
169 | } else { | ||
170 | nd = rb_next(&curr->rb_node); | ||
171 | rb_erase(&curr->rb_node, symbols); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
87 | static void symbols__fixup_end(struct rb_root *symbols) | 176 | static void symbols__fixup_end(struct rb_root *symbols) |
88 | { | 177 | { |
89 | struct rb_node *nd, *prevnd = rb_first(symbols); | 178 | struct rb_node *nd, *prevnd = rb_first(symbols); |
@@ -438,18 +527,11 @@ int kallsyms__parse(const char *filename, void *arg, | |||
438 | char *line = NULL; | 527 | char *line = NULL; |
439 | size_t n; | 528 | size_t n; |
440 | int err = -1; | 529 | int err = -1; |
441 | u64 prev_start = 0; | ||
442 | char prev_symbol_type = 0; | ||
443 | char *prev_symbol_name; | ||
444 | FILE *file = fopen(filename, "r"); | 530 | FILE *file = fopen(filename, "r"); |
445 | 531 | ||
446 | if (file == NULL) | 532 | if (file == NULL) |
447 | goto out_failure; | 533 | goto out_failure; |
448 | 534 | ||
449 | prev_symbol_name = malloc(KSYM_NAME_LEN); | ||
450 | if (prev_symbol_name == NULL) | ||
451 | goto out_close; | ||
452 | |||
453 | err = 0; | 535 | err = 0; |
454 | 536 | ||
455 | while (!feof(file)) { | 537 | while (!feof(file)) { |
@@ -470,7 +552,7 @@ int kallsyms__parse(const char *filename, void *arg, | |||
470 | if (len + 2 >= line_len) | 552 | if (len + 2 >= line_len) |
471 | continue; | 553 | continue; |
472 | 554 | ||
473 | symbol_type = toupper(line[len]); | 555 | symbol_type = line[len]; |
474 | len += 2; | 556 | len += 2; |
475 | symbol_name = line + len; | 557 | symbol_name = line + len; |
476 | len = line_len - len; | 558 | len = line_len - len; |
@@ -480,24 +562,18 @@ int kallsyms__parse(const char *filename, void *arg, | |||
480 | break; | 562 | break; |
481 | } | 563 | } |
482 | 564 | ||
483 | if (prev_symbol_type) { | 565 | /* |
484 | u64 end = start; | 566 | * module symbols are not sorted so we add all |
485 | if (end != prev_start) | 567 | * symbols with zero length and rely on |
486 | --end; | 568 | * symbols__fixup_end() to fix it up. |
487 | err = process_symbol(arg, prev_symbol_name, | 569 | */ |
488 | prev_symbol_type, prev_start, end); | 570 | err = process_symbol(arg, symbol_name, |
489 | if (err) | 571 | symbol_type, start, start); |
490 | break; | 572 | if (err) |
491 | } | 573 | break; |
492 | |||
493 | memcpy(prev_symbol_name, symbol_name, len + 1); | ||
494 | prev_symbol_type = symbol_type; | ||
495 | prev_start = start; | ||
496 | } | 574 | } |
497 | 575 | ||
498 | free(prev_symbol_name); | ||
499 | free(line); | 576 | free(line); |
500 | out_close: | ||
501 | fclose(file); | 577 | fclose(file); |
502 | return err; | 578 | return err; |
503 | 579 | ||
@@ -703,6 +779,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
703 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 779 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
704 | return -1; | 780 | return -1; |
705 | 781 | ||
782 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
783 | symbols__fixup_end(&dso->symbols[map->type]); | ||
784 | |||
706 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 785 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
707 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; | 786 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; |
708 | else | 787 | else |
@@ -1092,8 +1171,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1092 | if (dso->has_build_id) { | 1171 | if (dso->has_build_id) { |
1093 | u8 build_id[BUILD_ID_SIZE]; | 1172 | u8 build_id[BUILD_ID_SIZE]; |
1094 | 1173 | ||
1095 | if (elf_read_build_id(elf, build_id, | 1174 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) |
1096 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | ||
1097 | goto out_elf_end; | 1175 | goto out_elf_end; |
1098 | 1176 | ||
1099 | if (!dso__build_id_equal(dso, build_id)) | 1177 | if (!dso__build_id_equal(dso, build_id)) |
@@ -1111,6 +1189,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1111 | } | 1189 | } |
1112 | 1190 | ||
1113 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | 1191 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); |
1192 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1193 | opdsec = NULL; | ||
1114 | if (opdsec) | 1194 | if (opdsec) |
1115 | opddata = elf_rawdata(opdsec, NULL); | 1195 | opddata = elf_rawdata(opdsec, NULL); |
1116 | 1196 | ||
@@ -1276,6 +1356,7 @@ new_symbol: | |||
1276 | * For misannotated, zeroed, ASM function sizes. | 1356 | * For misannotated, zeroed, ASM function sizes. |
1277 | */ | 1357 | */ |
1278 | if (nr > 0) { | 1358 | if (nr > 0) { |
1359 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1279 | symbols__fixup_end(&dso->symbols[map->type]); | 1360 | symbols__fixup_end(&dso->symbols[map->type]); |
1280 | if (kmap) { | 1361 | if (kmap) { |
1281 | /* | 1362 | /* |
@@ -1362,8 +1443,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1362 | ptr = data->d_buf; | 1443 | ptr = data->d_buf; |
1363 | while (ptr < (data->d_buf + data->d_size)) { | 1444 | while (ptr < (data->d_buf + data->d_size)) { |
1364 | GElf_Nhdr *nhdr = ptr; | 1445 | GElf_Nhdr *nhdr = ptr; |
1365 | int namesz = NOTE_ALIGN(nhdr->n_namesz), | 1446 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), |
1366 | descsz = NOTE_ALIGN(nhdr->n_descsz); | 1447 | descsz = NOTE_ALIGN(nhdr->n_descsz); |
1367 | const char *name; | 1448 | const char *name; |
1368 | 1449 | ||
1369 | ptr += sizeof(*nhdr); | 1450 | ptr += sizeof(*nhdr); |
@@ -1372,8 +1453,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1372 | if (nhdr->n_type == NT_GNU_BUILD_ID && | 1453 | if (nhdr->n_type == NT_GNU_BUILD_ID && |
1373 | nhdr->n_namesz == sizeof("GNU")) { | 1454 | nhdr->n_namesz == sizeof("GNU")) { |
1374 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | 1455 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { |
1375 | memcpy(bf, ptr, BUILD_ID_SIZE); | 1456 | size_t sz = min(size, descsz); |
1376 | err = BUILD_ID_SIZE; | 1457 | memcpy(bf, ptr, sz); |
1458 | memset(bf + sz, 0, size - sz); | ||
1459 | err = descsz; | ||
1377 | break; | 1460 | break; |
1378 | } | 1461 | } |
1379 | } | 1462 | } |
@@ -1425,7 +1508,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1425 | while (1) { | 1508 | while (1) { |
1426 | char bf[BUFSIZ]; | 1509 | char bf[BUFSIZ]; |
1427 | GElf_Nhdr nhdr; | 1510 | GElf_Nhdr nhdr; |
1428 | int namesz, descsz; | 1511 | size_t namesz, descsz; |
1429 | 1512 | ||
1430 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | 1513 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) |
1431 | break; | 1514 | break; |
@@ -1434,15 +1517,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1434 | descsz = NOTE_ALIGN(nhdr.n_descsz); | 1517 | descsz = NOTE_ALIGN(nhdr.n_descsz); |
1435 | if (nhdr.n_type == NT_GNU_BUILD_ID && | 1518 | if (nhdr.n_type == NT_GNU_BUILD_ID && |
1436 | nhdr.n_namesz == sizeof("GNU")) { | 1519 | nhdr.n_namesz == sizeof("GNU")) { |
1437 | if (read(fd, bf, namesz) != namesz) | 1520 | if (read(fd, bf, namesz) != (ssize_t)namesz) |
1438 | break; | 1521 | break; |
1439 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | 1522 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { |
1440 | if (read(fd, build_id, | 1523 | size_t sz = min(descsz, size); |
1441 | BUILD_ID_SIZE) == BUILD_ID_SIZE) { | 1524 | if (read(fd, build_id, sz) == (ssize_t)sz) { |
1525 | memset(build_id + sz, 0, size - sz); | ||
1442 | err = 0; | 1526 | err = 0; |
1443 | break; | 1527 | break; |
1444 | } | 1528 | } |
1445 | } else if (read(fd, bf, descsz) != descsz) | 1529 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) |
1446 | break; | 1530 | break; |
1447 | } else { | 1531 | } else { |
1448 | int n = namesz + descsz; | 1532 | int n = namesz + descsz; |
@@ -1504,6 +1588,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1504 | dso->adjust_symbols = 0; | 1588 | dso->adjust_symbols = 0; |
1505 | 1589 | ||
1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 1590 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
1591 | struct stat st; | ||
1592 | |||
1593 | if (lstat(dso->name, &st) < 0) | ||
1594 | return -1; | ||
1595 | |||
1596 | if (st.st_uid && (st.st_uid != geteuid())) { | ||
1597 | pr_warning("File %s not owned by current user or root, " | ||
1598 | "ignoring it.\n", dso->name); | ||
1599 | return -1; | ||
1600 | } | ||
1601 | |||
1507 | ret = dso__load_perf_map(dso, map, filter); | 1602 | ret = dso__load_perf_map(dso, map, filter); |
1508 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : | 1603 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : |
1509 | SYMTAB__NOT_FOUND; | 1604 | SYMTAB__NOT_FOUND; |
@@ -2170,27 +2265,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
2170 | return ret; | 2265 | return ret; |
2171 | } | 2266 | } |
2172 | 2267 | ||
2173 | struct dso *dso__new_kernel(const char *name) | 2268 | static struct dso* |
2269 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
2270 | const char *short_name, int dso_type) | ||
2174 | { | 2271 | { |
2175 | struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); | 2272 | /* |
2176 | 2273 | * The kernel dso could be created by build_id processing. | |
2177 | if (dso != NULL) { | 2274 | */ |
2178 | dso__set_short_name(dso, "[kernel]"); | 2275 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); |
2179 | dso->kernel = DSO_TYPE_KERNEL; | ||
2180 | } | ||
2181 | |||
2182 | return dso; | ||
2183 | } | ||
2184 | 2276 | ||
2185 | static struct dso *dso__new_guest_kernel(struct machine *machine, | 2277 | /* |
2186 | const char *name) | 2278 | * We need to run this in all cases, since during the build_id |
2187 | { | 2279 | * processing we had no idea this was the kernel dso. |
2188 | char bf[PATH_MAX]; | 2280 | */ |
2189 | struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, | ||
2190 | sizeof(bf))); | ||
2191 | if (dso != NULL) { | 2281 | if (dso != NULL) { |
2192 | dso__set_short_name(dso, "[guest.kernel]"); | 2282 | dso__set_short_name(dso, short_name); |
2193 | dso->kernel = DSO_TYPE_GUEST_KERNEL; | 2283 | dso->kernel = dso_type; |
2194 | } | 2284 | } |
2195 | 2285 | ||
2196 | return dso; | 2286 | return dso; |
@@ -2208,24 +2298,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | |||
2208 | dso->has_build_id = true; | 2298 | dso->has_build_id = true; |
2209 | } | 2299 | } |
2210 | 2300 | ||
2211 | static struct dso *machine__create_kernel(struct machine *machine) | 2301 | static struct dso *machine__get_kernel(struct machine *machine) |
2212 | { | 2302 | { |
2213 | const char *vmlinux_name = NULL; | 2303 | const char *vmlinux_name = NULL; |
2214 | struct dso *kernel; | 2304 | struct dso *kernel; |
2215 | 2305 | ||
2216 | if (machine__is_host(machine)) { | 2306 | if (machine__is_host(machine)) { |
2217 | vmlinux_name = symbol_conf.vmlinux_name; | 2307 | vmlinux_name = symbol_conf.vmlinux_name; |
2218 | kernel = dso__new_kernel(vmlinux_name); | 2308 | if (!vmlinux_name) |
2309 | vmlinux_name = "[kernel.kallsyms]"; | ||
2310 | |||
2311 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2312 | "[kernel]", | ||
2313 | DSO_TYPE_KERNEL); | ||
2219 | } else { | 2314 | } else { |
2315 | char bf[PATH_MAX]; | ||
2316 | |||
2220 | if (machine__is_default_guest(machine)) | 2317 | if (machine__is_default_guest(machine)) |
2221 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 2318 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
2222 | kernel = dso__new_guest_kernel(machine, vmlinux_name); | 2319 | if (!vmlinux_name) |
2320 | vmlinux_name = machine__mmap_name(machine, bf, | ||
2321 | sizeof(bf)); | ||
2322 | |||
2323 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2324 | "[guest.kernel]", | ||
2325 | DSO_TYPE_GUEST_KERNEL); | ||
2223 | } | 2326 | } |
2224 | 2327 | ||
2225 | if (kernel != NULL) { | 2328 | if (kernel != NULL && (!kernel->has_build_id)) |
2226 | dso__read_running_kernel_build_id(kernel, machine); | 2329 | dso__read_running_kernel_build_id(kernel, machine); |
2227 | dsos__add(&machine->kernel_dsos, kernel); | 2330 | |
2228 | } | ||
2229 | return kernel; | 2331 | return kernel; |
2230 | } | 2332 | } |
2231 | 2333 | ||
@@ -2329,7 +2431,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
2329 | 2431 | ||
2330 | int machine__create_kernel_maps(struct machine *machine) | 2432 | int machine__create_kernel_maps(struct machine *machine) |
2331 | { | 2433 | { |
2332 | struct dso *kernel = machine__create_kernel(machine); | 2434 | struct dso *kernel = machine__get_kernel(machine); |
2333 | 2435 | ||
2334 | if (kernel == NULL || | 2436 | if (kernel == NULL || |
2335 | __machine__create_kernel_maps(machine, kernel) < 0) | 2437 | __machine__create_kernel_maps(machine, kernel) < 0) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 325ee36a9d29..29f8d742e92f 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -72,11 +72,14 @@ struct symbol_conf { | |||
72 | use_modules, | 72 | use_modules, |
73 | sort_by_name, | 73 | sort_by_name, |
74 | show_nr_samples, | 74 | show_nr_samples, |
75 | show_total_period, | ||
75 | use_callchain, | 76 | use_callchain, |
76 | exclude_other, | 77 | exclude_other, |
77 | show_cpu_utilization, | 78 | show_cpu_utilization, |
78 | initialized, | 79 | initialized, |
79 | kptr_restrict; | 80 | kptr_restrict, |
81 | annotate_asm_raw, | ||
82 | annotate_src; | ||
80 | const char *vmlinux_name, | 83 | const char *vmlinux_name, |
81 | *kallsyms_name, | 84 | *kallsyms_name, |
82 | *source_prefix, | 85 | *source_prefix, |
@@ -155,7 +158,6 @@ struct dso { | |||
155 | }; | 158 | }; |
156 | 159 | ||
157 | struct dso *dso__new(const char *name); | 160 | struct dso *dso__new(const char *name); |
158 | struct dso *dso__new_kernel(const char *name); | ||
159 | void dso__delete(struct dso *dso); | 161 | void dso__delete(struct dso *dso); |
160 | 162 | ||
161 | int dso__name_len(const struct dso *dso); | 163 | int dso__name_len(const struct dso *dso); |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index a11f60735a18..500471dffa4f 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -15,52 +15,6 @@ | |||
15 | #include "top.h" | 15 | #include "top.h" |
16 | #include <inttypes.h> | 16 | #include <inttypes.h> |
17 | 17 | ||
18 | /* | ||
19 | * Ordering weight: count-1 * count-2 * ... / count-n | ||
20 | */ | ||
21 | static double sym_weight(const struct sym_entry *sym, struct perf_top *top) | ||
22 | { | ||
23 | double weight = sym->snap_count; | ||
24 | int counter; | ||
25 | |||
26 | if (!top->display_weighted) | ||
27 | return weight; | ||
28 | |||
29 | for (counter = 1; counter < top->evlist->nr_entries - 1; counter++) | ||
30 | weight *= sym->count[counter]; | ||
31 | |||
32 | weight /= (sym->count[counter] + 1); | ||
33 | |||
34 | return weight; | ||
35 | } | ||
36 | |||
37 | static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme) | ||
38 | { | ||
39 | pthread_mutex_lock(&top->active_symbols_lock); | ||
40 | list_del_init(&syme->node); | ||
41 | pthread_mutex_unlock(&top->active_symbols_lock); | ||
42 | } | ||
43 | |||
44 | static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | ||
45 | { | ||
46 | struct rb_node **p = &tree->rb_node; | ||
47 | struct rb_node *parent = NULL; | ||
48 | struct sym_entry *iter; | ||
49 | |||
50 | while (*p != NULL) { | ||
51 | parent = *p; | ||
52 | iter = rb_entry(parent, struct sym_entry, rb_node); | ||
53 | |||
54 | if (se->weight > iter->weight) | ||
55 | p = &(*p)->rb_left; | ||
56 | else | ||
57 | p = &(*p)->rb_right; | ||
58 | } | ||
59 | |||
60 | rb_link_node(&se->rb_node, parent, p); | ||
61 | rb_insert_color(&se->rb_node, tree); | ||
62 | } | ||
63 | |||
64 | #define SNPRINTF(buf, size, fmt, args...) \ | 18 | #define SNPRINTF(buf, size, fmt, args...) \ |
65 | ({ \ | 19 | ({ \ |
66 | size_t r = snprintf(buf, size, fmt, ## args); \ | 20 | size_t r = snprintf(buf, size, fmt, ## args); \ |
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | |||
69 | 23 | ||
70 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | 24 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) |
71 | { | 25 | { |
72 | struct perf_evsel *counter; | ||
73 | float samples_per_sec = top->samples / top->delay_secs; | 26 | float samples_per_sec = top->samples / top->delay_secs; |
74 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; | 27 | float ksamples_per_sec = top->kernel_samples / top->delay_secs; |
75 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; | 28 | float esamples_percent = (100.0 * top->exact_samples) / top->samples; |
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
104 | esamples_percent); | 57 | esamples_percent); |
105 | } | 58 | } |
106 | 59 | ||
107 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | 60 | if (top->evlist->nr_entries == 1) { |
108 | struct perf_evsel *first; | 61 | struct perf_evsel *first; |
109 | first = list_entry(top->evlist->entries.next, struct perf_evsel, node); | 62 | first = list_entry(top->evlist->entries.next, struct perf_evsel, node); |
110 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", | 63 | ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", |
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
112 | top->freq ? "Hz" : ""); | 65 | top->freq ? "Hz" : ""); |
113 | } | 66 | } |
114 | 67 | ||
115 | if (!top->display_weighted) { | 68 | ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel)); |
116 | ret += SNPRINTF(bf + ret, size - ret, "%s", | ||
117 | event_name(top->sym_evsel)); | ||
118 | } else { | ||
119 | /* | ||
120 | * Don't let events eat all the space. Leaving 30 bytes | ||
121 | * for the rest should be enough. | ||
122 | */ | ||
123 | size_t last_pos = size - 30; | ||
124 | |||
125 | list_for_each_entry(counter, &top->evlist->entries, node) { | ||
126 | ret += SNPRINTF(bf + ret, size - ret, "%s%s", | ||
127 | counter->idx ? "/" : "", | ||
128 | event_name(counter)); | ||
129 | if (ret > last_pos) { | ||
130 | sprintf(bf + last_pos - 3, ".."); | ||
131 | ret = last_pos - 1; | ||
132 | break; | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | 69 | ||
137 | ret += SNPRINTF(bf + ret, size - ret, "], "); | 70 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
138 | 71 | ||
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top) | |||
166 | top->exact_samples = top->guest_kernel_samples = | 99 | top->exact_samples = top->guest_kernel_samples = |
167 | top->guest_us_samples = 0; | 100 | top->guest_us_samples = 0; |
168 | } | 101 | } |
169 | |||
170 | float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) | ||
171 | { | ||
172 | struct sym_entry *syme, *n; | ||
173 | float sum_ksamples = 0.0; | ||
174 | int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j; | ||
175 | |||
176 | /* Sort the active symbols */ | ||
177 | pthread_mutex_lock(&top->active_symbols_lock); | ||
178 | syme = list_entry(top->active_symbols.next, struct sym_entry, node); | ||
179 | pthread_mutex_unlock(&top->active_symbols_lock); | ||
180 | |||
181 | top->rb_entries = 0; | ||
182 | list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) { | ||
183 | syme->snap_count = syme->count[snap]; | ||
184 | if (syme->snap_count != 0) { | ||
185 | |||
186 | if ((top->hide_user_symbols && | ||
187 | syme->map->dso->kernel == DSO_TYPE_USER) || | ||
188 | (top->hide_kernel_symbols && | ||
189 | syme->map->dso->kernel == DSO_TYPE_KERNEL)) { | ||
190 | perf_top__remove_active_sym(top, syme); | ||
191 | continue; | ||
192 | } | ||
193 | syme->weight = sym_weight(syme, top); | ||
194 | |||
195 | if ((int)syme->snap_count >= top->count_filter) { | ||
196 | rb_insert_active_sym(root, syme); | ||
197 | ++top->rb_entries; | ||
198 | } | ||
199 | sum_ksamples += syme->snap_count; | ||
200 | |||
201 | for (j = 0; j < top->evlist->nr_entries; j++) | ||
202 | syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8; | ||
203 | } else | ||
204 | perf_top__remove_active_sym(top, syme); | ||
205 | } | ||
206 | |||
207 | return sum_ksamples; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * Find the longest symbol name that will be displayed | ||
212 | */ | ||
213 | void perf_top__find_widths(struct perf_top *top, struct rb_root *root, | ||
214 | int *dso_width, int *dso_short_width, int *sym_width) | ||
215 | { | ||
216 | struct rb_node *nd; | ||
217 | int printed = 0; | ||
218 | |||
219 | *sym_width = *dso_width = *dso_short_width = 0; | ||
220 | |||
221 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
222 | struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); | ||
223 | struct symbol *sym = sym_entry__symbol(syme); | ||
224 | |||
225 | if (++printed > top->print_entries || | ||
226 | (int)syme->snap_count < top->count_filter) | ||
227 | continue; | ||
228 | |||
229 | if (syme->map->dso->long_name_len > *dso_width) | ||
230 | *dso_width = syme->map->dso->long_name_len; | ||
231 | |||
232 | if (syme->map->dso->short_name_len > *dso_short_width) | ||
233 | *dso_short_width = syme->map->dso->short_name_len; | ||
234 | |||
235 | if (sym->namelen > *sym_width) | ||
236 | *sym_width = sym->namelen; | ||
237 | } | ||
238 | } | ||
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index bfbf95bcc603..399650967958 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -4,26 +4,10 @@ | |||
4 | #include "types.h" | 4 | #include "types.h" |
5 | #include "../perf.h" | 5 | #include "../perf.h" |
6 | #include <stddef.h> | 6 | #include <stddef.h> |
7 | #include <pthread.h> | ||
8 | #include <linux/list.h> | ||
9 | #include <linux/rbtree.h> | ||
10 | 7 | ||
11 | struct perf_evlist; | 8 | struct perf_evlist; |
12 | struct perf_evsel; | 9 | struct perf_evsel; |
13 | 10 | struct perf_session; | |
14 | struct sym_entry { | ||
15 | struct rb_node rb_node; | ||
16 | struct list_head node; | ||
17 | unsigned long snap_count; | ||
18 | double weight; | ||
19 | struct map *map; | ||
20 | unsigned long count[0]; | ||
21 | }; | ||
22 | |||
23 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) | ||
24 | { | ||
25 | return ((void *)self) + symbol_conf.priv_size; | ||
26 | } | ||
27 | 11 | ||
28 | struct perf_top { | 12 | struct perf_top { |
29 | struct perf_evlist *evlist; | 13 | struct perf_evlist *evlist; |
@@ -31,34 +15,20 @@ struct perf_top { | |||
31 | * Symbols will be added here in perf_event__process_sample and will | 15 | * Symbols will be added here in perf_event__process_sample and will |
32 | * get out after decayed. | 16 | * get out after decayed. |
33 | */ | 17 | */ |
34 | struct list_head active_symbols; | ||
35 | pthread_mutex_t active_symbols_lock; | ||
36 | pthread_cond_t active_symbols_cond; | ||
37 | u64 samples; | 18 | u64 samples; |
38 | u64 kernel_samples, us_samples; | 19 | u64 kernel_samples, us_samples; |
39 | u64 exact_samples; | 20 | u64 exact_samples; |
40 | u64 guest_us_samples, guest_kernel_samples; | 21 | u64 guest_us_samples, guest_kernel_samples; |
41 | int print_entries, count_filter, delay_secs; | 22 | int print_entries, count_filter, delay_secs; |
42 | int display_weighted, freq, rb_entries; | 23 | int freq; |
43 | pid_t target_pid, target_tid; | 24 | pid_t target_pid, target_tid; |
44 | bool hide_kernel_symbols, hide_user_symbols, zero; | 25 | bool hide_kernel_symbols, hide_user_symbols, zero; |
45 | const char *cpu_list; | 26 | const char *cpu_list; |
46 | struct sym_entry *sym_filter_entry; | 27 | struct hist_entry *sym_filter_entry; |
47 | struct perf_evsel *sym_evsel; | 28 | struct perf_evsel *sym_evsel; |
29 | struct perf_session *session; | ||
48 | }; | 30 | }; |
49 | 31 | ||
50 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); | 32 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); |
51 | void perf_top__reset_sample_counters(struct perf_top *top); | 33 | void perf_top__reset_sample_counters(struct perf_top *top); |
52 | float perf_top__decay_samples(struct perf_top *top, struct rb_root *root); | ||
53 | void perf_top__find_widths(struct perf_top *top, struct rb_root *root, | ||
54 | int *dso_width, int *dso_short_width, int *sym_width); | ||
55 | |||
56 | #ifdef NO_NEWT_SUPPORT | ||
57 | static inline int perf_top__tui_browser(struct perf_top *top __used) | ||
58 | { | ||
59 | return 0; | ||
60 | } | ||
61 | #else | ||
62 | int perf_top__tui_browser(struct perf_top *top); | ||
63 | #endif | ||
64 | #endif /* __PERF_TOP_H */ | 34 | #endif /* __PERF_TOP_H */ |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 3403f814ad72..d2655f08bcc0 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -80,7 +80,7 @@ static void die(const char *fmt, ...) | |||
80 | int ret = errno; | 80 | int ret = errno; |
81 | 81 | ||
82 | if (errno) | 82 | if (errno) |
83 | perror("trace-cmd"); | 83 | perror("perf"); |
84 | else | 84 | else |
85 | ret = -1; | 85 | ret = -1; |
86 | 86 | ||
@@ -196,7 +196,8 @@ static void record_file(const char *file, size_t hdr_sz) | |||
196 | die("Can't read '%s'", file); | 196 | die("Can't read '%s'", file); |
197 | 197 | ||
198 | /* put in zeros for file size, then fill true size later */ | 198 | /* put in zeros for file size, then fill true size later */ |
199 | write_or_die(&size, hdr_sz); | 199 | if (hdr_sz) |
200 | write_or_die(&size, hdr_sz); | ||
200 | 201 | ||
201 | do { | 202 | do { |
202 | r = read(fd, buf, BUFSIZ); | 203 | r = read(fd, buf, BUFSIZ); |
@@ -212,7 +213,7 @@ static void record_file(const char *file, size_t hdr_sz) | |||
212 | if (bigendian()) | 213 | if (bigendian()) |
213 | sizep += sizeof(u64) - hdr_sz; | 214 | sizep += sizeof(u64) - hdr_sz; |
214 | 215 | ||
215 | if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) | 216 | if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) |
216 | die("writing to %s", output_file); | 217 | die("writing to %s", output_file); |
217 | } | 218 | } |
218 | 219 | ||
@@ -428,6 +429,19 @@ get_tracepoints_path(struct list_head *pattrs) | |||
428 | return nr_tracepoints > 0 ? path.next : NULL; | 429 | return nr_tracepoints > 0 ? path.next : NULL; |
429 | } | 430 | } |
430 | 431 | ||
432 | static void | ||
433 | put_tracepoints_path(struct tracepoint_path *tps) | ||
434 | { | ||
435 | while (tps) { | ||
436 | struct tracepoint_path *t = tps; | ||
437 | |||
438 | tps = tps->next; | ||
439 | free(t->name); | ||
440 | free(t->system); | ||
441 | free(t); | ||
442 | } | ||
443 | } | ||
444 | |||
431 | bool have_tracepoints(struct list_head *pattrs) | 445 | bool have_tracepoints(struct list_head *pattrs) |
432 | { | 446 | { |
433 | struct perf_evsel *pos; | 447 | struct perf_evsel *pos; |
@@ -439,19 +453,11 @@ bool have_tracepoints(struct list_head *pattrs) | |||
439 | return false; | 453 | return false; |
440 | } | 454 | } |
441 | 455 | ||
442 | int read_tracing_data(int fd, struct list_head *pattrs) | 456 | static void tracing_data_header(void) |
443 | { | 457 | { |
444 | char buf[BUFSIZ]; | 458 | char buf[20]; |
445 | struct tracepoint_path *tps = get_tracepoints_path(pattrs); | ||
446 | |||
447 | /* | ||
448 | * What? No tracepoints? No sense writing anything here, bail out. | ||
449 | */ | ||
450 | if (tps == NULL) | ||
451 | return -1; | ||
452 | |||
453 | output_fd = fd; | ||
454 | 459 | ||
460 | /* just guessing this is someone's birthday.. ;) */ | ||
455 | buf[0] = 23; | 461 | buf[0] = 23; |
456 | buf[1] = 8; | 462 | buf[1] = 8; |
457 | buf[2] = 68; | 463 | buf[2] = 68; |
@@ -476,28 +482,86 @@ int read_tracing_data(int fd, struct list_head *pattrs) | |||
476 | /* save page_size */ | 482 | /* save page_size */ |
477 | page_size = sysconf(_SC_PAGESIZE); | 483 | page_size = sysconf(_SC_PAGESIZE); |
478 | write_or_die(&page_size, 4); | 484 | write_or_die(&page_size, 4); |
485 | } | ||
486 | |||
487 | struct tracing_data *tracing_data_get(struct list_head *pattrs, | ||
488 | int fd, bool temp) | ||
489 | { | ||
490 | struct tracepoint_path *tps; | ||
491 | struct tracing_data *tdata; | ||
492 | |||
493 | output_fd = fd; | ||
494 | |||
495 | tps = get_tracepoints_path(pattrs); | ||
496 | if (!tps) | ||
497 | return NULL; | ||
479 | 498 | ||
499 | tdata = malloc_or_die(sizeof(*tdata)); | ||
500 | tdata->temp = temp; | ||
501 | tdata->size = 0; | ||
502 | |||
503 | if (temp) { | ||
504 | int temp_fd; | ||
505 | |||
506 | snprintf(tdata->temp_file, sizeof(tdata->temp_file), | ||
507 | "/tmp/perf-XXXXXX"); | ||
508 | if (!mkstemp(tdata->temp_file)) | ||
509 | die("Can't make temp file"); | ||
510 | |||
511 | temp_fd = open(tdata->temp_file, O_RDWR); | ||
512 | if (temp_fd < 0) | ||
513 | die("Can't read '%s'", tdata->temp_file); | ||
514 | |||
515 | /* | ||
516 | * Set the temp file the default output, so all the | ||
517 | * tracing data are stored into it. | ||
518 | */ | ||
519 | output_fd = temp_fd; | ||
520 | } | ||
521 | |||
522 | tracing_data_header(); | ||
480 | read_header_files(); | 523 | read_header_files(); |
481 | read_ftrace_files(tps); | 524 | read_ftrace_files(tps); |
482 | read_event_files(tps); | 525 | read_event_files(tps); |
483 | read_proc_kallsyms(); | 526 | read_proc_kallsyms(); |
484 | read_ftrace_printk(); | 527 | read_ftrace_printk(); |
485 | 528 | ||
486 | return 0; | 529 | /* |
530 | * All tracing data are stored by now, we can restore | ||
531 | * the default output file in case we used temp file. | ||
532 | */ | ||
533 | if (temp) { | ||
534 | tdata->size = lseek(output_fd, 0, SEEK_CUR); | ||
535 | close(output_fd); | ||
536 | output_fd = fd; | ||
537 | } | ||
538 | |||
539 | put_tracepoints_path(tps); | ||
540 | return tdata; | ||
487 | } | 541 | } |
488 | 542 | ||
489 | ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) | 543 | void tracing_data_put(struct tracing_data *tdata) |
490 | { | 544 | { |
491 | ssize_t size; | 545 | if (tdata->temp) { |
492 | int err = 0; | 546 | record_file(tdata->temp_file, 0); |
547 | unlink(tdata->temp_file); | ||
548 | } | ||
493 | 549 | ||
494 | calc_data_size = 1; | 550 | free(tdata); |
495 | err = read_tracing_data(fd, pattrs); | 551 | } |
496 | size = calc_data_size - 1; | ||
497 | calc_data_size = 0; | ||
498 | 552 | ||
499 | if (err < 0) | 553 | int read_tracing_data(int fd, struct list_head *pattrs) |
500 | return err; | 554 | { |
555 | struct tracing_data *tdata; | ||
501 | 556 | ||
502 | return size; | 557 | /* |
558 | * We work over the real file, so we can write data | ||
559 | * directly, no temp file is needed. | ||
560 | */ | ||
561 | tdata = tracing_data_get(pattrs, fd, false); | ||
562 | if (!tdata) | ||
563 | return -ENOMEM; | ||
564 | |||
565 | tracing_data_put(tdata); | ||
566 | return 0; | ||
503 | } | 567 | } |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index f674dda3363b..a84100817649 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -263,7 +263,18 @@ void *raw_field_ptr(struct event *event, const char *name, void *data); | |||
263 | unsigned long long eval_flag(const char *flag); | 263 | unsigned long long eval_flag(const char *flag); |
264 | 264 | ||
265 | int read_tracing_data(int fd, struct list_head *pattrs); | 265 | int read_tracing_data(int fd, struct list_head *pattrs); |
266 | ssize_t read_tracing_data_size(int fd, struct list_head *pattrs); | 266 | |
267 | struct tracing_data { | ||
268 | /* size is only valid if temp is 'true' */ | ||
269 | ssize_t size; | ||
270 | bool temp; | ||
271 | char temp_file[50]; | ||
272 | }; | ||
273 | |||
274 | struct tracing_data *tracing_data_get(struct list_head *pattrs, | ||
275 | int fd, bool temp); | ||
276 | void tracing_data_put(struct tracing_data *tdata); | ||
277 | |||
267 | 278 | ||
268 | /* taken from kernel/trace/trace.h */ | 279 | /* taken from kernel/trace/trace.h */ |
269 | enum trace_flag_type { | 280 | enum trace_flag_type { |
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 611219f80680..556829124b02 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c | |||
@@ -1,5 +1,10 @@ | |||
1 | #include "../util.h" | ||
2 | #include "../cache.h" | ||
3 | #include "../../perf.h" | ||
1 | #include "libslang.h" | 4 | #include "libslang.h" |
5 | #include <newt.h> | ||
2 | #include "ui.h" | 6 | #include "ui.h" |
7 | #include "util.h" | ||
3 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
4 | #include <linux/list.h> | 9 | #include <linux/list.h> |
5 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
@@ -7,13 +12,13 @@ | |||
7 | #include <sys/ttydefaults.h> | 12 | #include <sys/ttydefaults.h> |
8 | #include "browser.h" | 13 | #include "browser.h" |
9 | #include "helpline.h" | 14 | #include "helpline.h" |
15 | #include "keysyms.h" | ||
10 | #include "../color.h" | 16 | #include "../color.h" |
11 | #include "../util.h" | ||
12 | #include <stdio.h> | ||
13 | 17 | ||
14 | static int ui_browser__percent_color(double percent, bool current) | 18 | static int ui_browser__percent_color(struct ui_browser *browser, |
19 | double percent, bool current) | ||
15 | { | 20 | { |
16 | if (current) | 21 | if (current && (!browser->use_navkeypressed || browser->navkeypressed)) |
17 | return HE_COLORSET_SELECTED; | 22 | return HE_COLORSET_SELECTED; |
18 | if (percent >= MIN_RED) | 23 | if (percent >= MIN_RED) |
19 | return HE_COLORSET_TOP; | 24 | return HE_COLORSET_TOP; |
@@ -30,7 +35,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color) | |||
30 | void ui_browser__set_percent_color(struct ui_browser *self, | 35 | void ui_browser__set_percent_color(struct ui_browser *self, |
31 | double percent, bool current) | 36 | double percent, bool current) |
32 | { | 37 | { |
33 | int color = ui_browser__percent_color(percent, current); | 38 | int color = ui_browser__percent_color(self, percent, current); |
34 | ui_browser__set_color(self, color); | 39 | ui_browser__set_color(self, color); |
35 | } | 40 | } |
36 | 41 | ||
@@ -39,31 +44,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x) | |||
39 | SLsmg_gotorc(self->y + y, self->x + x); | 44 | SLsmg_gotorc(self->y + y, self->x + x); |
40 | } | 45 | } |
41 | 46 | ||
47 | static struct list_head * | ||
48 | ui_browser__list_head_filter_entries(struct ui_browser *browser, | ||
49 | struct list_head *pos) | ||
50 | { | ||
51 | do { | ||
52 | if (!browser->filter || !browser->filter(browser, pos)) | ||
53 | return pos; | ||
54 | pos = pos->next; | ||
55 | } while (pos != browser->entries); | ||
56 | |||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | static struct list_head * | ||
61 | ui_browser__list_head_filter_prev_entries(struct ui_browser *browser, | ||
62 | struct list_head *pos) | ||
63 | { | ||
64 | do { | ||
65 | if (!browser->filter || !browser->filter(browser, pos)) | ||
66 | return pos; | ||
67 | pos = pos->prev; | ||
68 | } while (pos != browser->entries); | ||
69 | |||
70 | return NULL; | ||
71 | } | ||
72 | |||
42 | void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) | 73 | void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) |
43 | { | 74 | { |
44 | struct list_head *head = self->entries; | 75 | struct list_head *head = self->entries; |
45 | struct list_head *pos; | 76 | struct list_head *pos; |
46 | 77 | ||
78 | if (self->nr_entries == 0) | ||
79 | return; | ||
80 | |||
47 | switch (whence) { | 81 | switch (whence) { |
48 | case SEEK_SET: | 82 | case SEEK_SET: |
49 | pos = head->next; | 83 | pos = ui_browser__list_head_filter_entries(self, head->next); |
50 | break; | 84 | break; |
51 | case SEEK_CUR: | 85 | case SEEK_CUR: |
52 | pos = self->top; | 86 | pos = self->top; |
53 | break; | 87 | break; |
54 | case SEEK_END: | 88 | case SEEK_END: |
55 | pos = head->prev; | 89 | pos = ui_browser__list_head_filter_prev_entries(self, head->prev); |
56 | break; | 90 | break; |
57 | default: | 91 | default: |
58 | return; | 92 | return; |
59 | } | 93 | } |
60 | 94 | ||
95 | assert(pos != NULL); | ||
96 | |||
61 | if (offset > 0) { | 97 | if (offset > 0) { |
62 | while (offset-- != 0) | 98 | while (offset-- != 0) |
63 | pos = pos->next; | 99 | pos = ui_browser__list_head_filter_entries(self, pos->next); |
64 | } else { | 100 | } else { |
65 | while (offset++ != 0) | 101 | while (offset++ != 0) |
66 | pos = pos->prev; | 102 | pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); |
67 | } | 103 | } |
68 | 104 | ||
69 | self->top = pos; | 105 | self->top = pos; |
@@ -127,41 +163,76 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | |||
127 | 163 | ||
128 | void ui_browser__refresh_dimensions(struct ui_browser *self) | 164 | void ui_browser__refresh_dimensions(struct ui_browser *self) |
129 | { | 165 | { |
130 | int cols, rows; | 166 | self->width = SLtt_Screen_Cols - 1; |
131 | newtGetScreenSize(&cols, &rows); | 167 | self->height = SLtt_Screen_Rows - 2; |
132 | |||
133 | self->width = cols - 1; | ||
134 | self->height = rows - 2; | ||
135 | self->y = 1; | 168 | self->y = 1; |
136 | self->x = 0; | 169 | self->x = 0; |
137 | } | 170 | } |
138 | 171 | ||
139 | void ui_browser__reset_index(struct ui_browser *self) | 172 | void ui_browser__handle_resize(struct ui_browser *browser) |
140 | { | 173 | { |
141 | self->index = self->top_idx = 0; | 174 | ui__refresh_dimensions(false); |
142 | self->seek(self, 0, SEEK_SET); | 175 | ui_browser__show(browser, browser->title, ui_helpline__current); |
176 | ui_browser__refresh(browser); | ||
143 | } | 177 | } |
144 | 178 | ||
145 | void ui_browser__add_exit_key(struct ui_browser *self, int key) | 179 | int ui_browser__warning(struct ui_browser *browser, int timeout, |
180 | const char *format, ...) | ||
146 | { | 181 | { |
147 | newtFormAddHotKey(self->form, key); | 182 | va_list args; |
183 | char *text; | ||
184 | int key = 0, err; | ||
185 | |||
186 | va_start(args, format); | ||
187 | err = vasprintf(&text, format, args); | ||
188 | va_end(args); | ||
189 | |||
190 | if (err < 0) { | ||
191 | va_start(args, format); | ||
192 | ui_helpline__vpush(format, args); | ||
193 | va_end(args); | ||
194 | } else { | ||
195 | while ((key == ui__question_window("Warning!", text, | ||
196 | "Press any key...", | ||
197 | timeout)) == K_RESIZE) | ||
198 | ui_browser__handle_resize(browser); | ||
199 | free(text); | ||
200 | } | ||
201 | |||
202 | return key; | ||
148 | } | 203 | } |
149 | 204 | ||
150 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) | 205 | int ui_browser__help_window(struct ui_browser *browser, const char *text) |
151 | { | 206 | { |
152 | int i = 0; | 207 | int key; |
153 | 208 | ||
154 | while (keys[i] && i < 64) { | 209 | while ((key = ui__help_window(text)) == K_RESIZE) |
155 | ui_browser__add_exit_key(self, keys[i]); | 210 | ui_browser__handle_resize(browser); |
156 | ++i; | 211 | |
157 | } | 212 | return key; |
213 | } | ||
214 | |||
215 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text) | ||
216 | { | ||
217 | int key; | ||
218 | |||
219 | while ((key = ui__dialog_yesno(text)) == K_RESIZE) | ||
220 | ui_browser__handle_resize(browser); | ||
221 | |||
222 | return key == K_ENTER || toupper(key) == 'Y'; | ||
223 | } | ||
224 | |||
225 | void ui_browser__reset_index(struct ui_browser *self) | ||
226 | { | ||
227 | self->index = self->top_idx = 0; | ||
228 | self->seek(self, 0, SEEK_SET); | ||
158 | } | 229 | } |
159 | 230 | ||
160 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) | 231 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) |
161 | { | 232 | { |
162 | SLsmg_gotorc(0, 0); | 233 | SLsmg_gotorc(0, 0); |
163 | ui_browser__set_color(browser, NEWT_COLORSET_ROOT); | 234 | ui_browser__set_color(browser, NEWT_COLORSET_ROOT); |
164 | slsmg_write_nstring(title, browser->width); | 235 | slsmg_write_nstring(title, browser->width + 1); |
165 | } | 236 | } |
166 | 237 | ||
167 | void ui_browser__show_title(struct ui_browser *browser, const char *title) | 238 | void ui_browser__show_title(struct ui_browser *browser, const char *title) |
@@ -174,78 +245,145 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title) | |||
174 | int ui_browser__show(struct ui_browser *self, const char *title, | 245 | int ui_browser__show(struct ui_browser *self, const char *title, |
175 | const char *helpline, ...) | 246 | const char *helpline, ...) |
176 | { | 247 | { |
248 | int err; | ||
177 | va_list ap; | 249 | va_list ap; |
178 | int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP, | ||
179 | NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ', | ||
180 | NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 }; | ||
181 | |||
182 | if (self->form != NULL) | ||
183 | newtFormDestroy(self->form); | ||
184 | 250 | ||
185 | ui_browser__refresh_dimensions(self); | 251 | ui_browser__refresh_dimensions(self); |
186 | self->form = newtForm(NULL, NULL, 0); | ||
187 | if (self->form == NULL) | ||
188 | return -1; | ||
189 | |||
190 | self->sb = newtVerticalScrollbar(self->width, 1, self->height, | ||
191 | HE_COLORSET_NORMAL, | ||
192 | HE_COLORSET_SELECTED); | ||
193 | if (self->sb == NULL) | ||
194 | return -1; | ||
195 | 252 | ||
196 | pthread_mutex_lock(&ui__lock); | 253 | pthread_mutex_lock(&ui__lock); |
197 | __ui_browser__show_title(self, title); | 254 | __ui_browser__show_title(self, title); |
198 | 255 | ||
199 | ui_browser__add_exit_keys(self, keys); | 256 | self->title = title; |
200 | newtFormAddComponent(self->form, self->sb); | 257 | free(self->helpline); |
258 | self->helpline = NULL; | ||
201 | 259 | ||
202 | va_start(ap, helpline); | 260 | va_start(ap, helpline); |
203 | ui_helpline__vpush(helpline, ap); | 261 | err = vasprintf(&self->helpline, helpline, ap); |
204 | va_end(ap); | 262 | va_end(ap); |
263 | if (err > 0) | ||
264 | ui_helpline__push(self->helpline); | ||
205 | pthread_mutex_unlock(&ui__lock); | 265 | pthread_mutex_unlock(&ui__lock); |
206 | return 0; | 266 | return err ? 0 : -1; |
207 | } | 267 | } |
208 | 268 | ||
209 | void ui_browser__hide(struct ui_browser *self) | 269 | void ui_browser__hide(struct ui_browser *browser __used) |
210 | { | 270 | { |
211 | pthread_mutex_lock(&ui__lock); | 271 | pthread_mutex_lock(&ui__lock); |
212 | newtFormDestroy(self->form); | ||
213 | self->form = NULL; | ||
214 | ui_helpline__pop(); | 272 | ui_helpline__pop(); |
215 | pthread_mutex_unlock(&ui__lock); | 273 | pthread_mutex_unlock(&ui__lock); |
216 | } | 274 | } |
217 | 275 | ||
218 | int ui_browser__refresh(struct ui_browser *self) | 276 | static void ui_browser__scrollbar_set(struct ui_browser *browser) |
277 | { | ||
278 | int height = browser->height, h = 0, pct = 0, | ||
279 | col = browser->width, | ||
280 | row = browser->y - 1; | ||
281 | |||
282 | if (browser->nr_entries > 1) { | ||
283 | pct = ((browser->index * (browser->height - 1)) / | ||
284 | (browser->nr_entries - 1)); | ||
285 | } | ||
286 | |||
287 | SLsmg_set_char_set(1); | ||
288 | |||
289 | while (h < height) { | ||
290 | ui_browser__gotorc(browser, row++, col); | ||
291 | SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR); | ||
292 | ++h; | ||
293 | } | ||
294 | |||
295 | SLsmg_set_char_set(0); | ||
296 | } | ||
297 | |||
298 | static int __ui_browser__refresh(struct ui_browser *browser) | ||
219 | { | 299 | { |
220 | int row; | 300 | int row; |
301 | int width = browser->width; | ||
302 | |||
303 | row = browser->refresh(browser); | ||
304 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); | ||
305 | |||
306 | if (!browser->use_navkeypressed || browser->navkeypressed) | ||
307 | ui_browser__scrollbar_set(browser); | ||
308 | else | ||
309 | width += 1; | ||
310 | |||
311 | SLsmg_fill_region(browser->y + row, browser->x, | ||
312 | browser->height - row, width, ' '); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
221 | 316 | ||
317 | int ui_browser__refresh(struct ui_browser *browser) | ||
318 | { | ||
222 | pthread_mutex_lock(&ui__lock); | 319 | pthread_mutex_lock(&ui__lock); |
223 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | 320 | __ui_browser__refresh(browser); |
224 | row = self->refresh(self); | ||
225 | ui_browser__set_color(self, HE_COLORSET_NORMAL); | ||
226 | SLsmg_fill_region(self->y + row, self->x, | ||
227 | self->height - row, self->width, ' '); | ||
228 | pthread_mutex_unlock(&ui__lock); | 321 | pthread_mutex_unlock(&ui__lock); |
229 | 322 | ||
230 | return 0; | 323 | return 0; |
231 | } | 324 | } |
232 | 325 | ||
233 | int ui_browser__run(struct ui_browser *self) | 326 | /* |
327 | * Here we're updating nr_entries _after_ we started browsing, i.e. we have to | ||
328 | * forget about any reference to any entry in the underlying data structure, | ||
329 | * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser | ||
330 | * after an output_resort and hist decay. | ||
331 | */ | ||
332 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) | ||
234 | { | 333 | { |
235 | struct newtExitStruct es; | 334 | off_t offset = nr_entries - browser->nr_entries; |
335 | |||
336 | browser->nr_entries = nr_entries; | ||
236 | 337 | ||
237 | if (ui_browser__refresh(self) < 0) | 338 | if (offset < 0) { |
238 | return -1; | 339 | if (browser->top_idx < (u64)-offset) |
340 | offset = -browser->top_idx; | ||
341 | |||
342 | browser->index += offset; | ||
343 | browser->top_idx += offset; | ||
344 | } | ||
345 | |||
346 | browser->top = NULL; | ||
347 | browser->seek(browser, browser->top_idx, SEEK_SET); | ||
348 | } | ||
349 | |||
350 | int ui_browser__run(struct ui_browser *self, int delay_secs) | ||
351 | { | ||
352 | int err, key; | ||
239 | 353 | ||
240 | while (1) { | 354 | while (1) { |
241 | off_t offset; | 355 | off_t offset; |
242 | 356 | ||
243 | newtFormRun(self->form, &es); | 357 | pthread_mutex_lock(&ui__lock); |
244 | 358 | err = __ui_browser__refresh(self); | |
245 | if (es.reason != NEWT_EXIT_HOTKEY) | 359 | SLsmg_refresh(); |
360 | pthread_mutex_unlock(&ui__lock); | ||
361 | if (err < 0) | ||
246 | break; | 362 | break; |
247 | switch (es.u.key) { | 363 | |
248 | case NEWT_KEY_DOWN: | 364 | key = ui__getch(delay_secs); |
365 | |||
366 | if (key == K_RESIZE) { | ||
367 | ui__refresh_dimensions(false); | ||
368 | ui_browser__refresh_dimensions(self); | ||
369 | __ui_browser__show_title(self, self->title); | ||
370 | ui_helpline__puts(self->helpline); | ||
371 | continue; | ||
372 | } | ||
373 | |||
374 | if (self->use_navkeypressed && !self->navkeypressed) { | ||
375 | if (key == K_DOWN || key == K_UP || | ||
376 | key == K_PGDN || key == K_PGUP || | ||
377 | key == K_HOME || key == K_END || | ||
378 | key == ' ') { | ||
379 | self->navkeypressed = true; | ||
380 | continue; | ||
381 | } else | ||
382 | return key; | ||
383 | } | ||
384 | |||
385 | switch (key) { | ||
386 | case K_DOWN: | ||
249 | if (self->index == self->nr_entries - 1) | 387 | if (self->index == self->nr_entries - 1) |
250 | break; | 388 | break; |
251 | ++self->index; | 389 | ++self->index; |
@@ -254,7 +392,7 @@ int ui_browser__run(struct ui_browser *self) | |||
254 | self->seek(self, +1, SEEK_CUR); | 392 | self->seek(self, +1, SEEK_CUR); |
255 | } | 393 | } |
256 | break; | 394 | break; |
257 | case NEWT_KEY_UP: | 395 | case K_UP: |
258 | if (self->index == 0) | 396 | if (self->index == 0) |
259 | break; | 397 | break; |
260 | --self->index; | 398 | --self->index; |
@@ -263,7 +401,7 @@ int ui_browser__run(struct ui_browser *self) | |||
263 | self->seek(self, -1, SEEK_CUR); | 401 | self->seek(self, -1, SEEK_CUR); |
264 | } | 402 | } |
265 | break; | 403 | break; |
266 | case NEWT_KEY_PGDN: | 404 | case K_PGDN: |
267 | case ' ': | 405 | case ' ': |
268 | if (self->top_idx + self->height > self->nr_entries - 1) | 406 | if (self->top_idx + self->height > self->nr_entries - 1) |
269 | break; | 407 | break; |
@@ -275,7 +413,7 @@ int ui_browser__run(struct ui_browser *self) | |||
275 | self->top_idx += offset; | 413 | self->top_idx += offset; |
276 | self->seek(self, +offset, SEEK_CUR); | 414 | self->seek(self, +offset, SEEK_CUR); |
277 | break; | 415 | break; |
278 | case NEWT_KEY_PGUP: | 416 | case K_PGUP: |
279 | if (self->top_idx == 0) | 417 | if (self->top_idx == 0) |
280 | break; | 418 | break; |
281 | 419 | ||
@@ -288,10 +426,10 @@ int ui_browser__run(struct ui_browser *self) | |||
288 | self->top_idx -= offset; | 426 | self->top_idx -= offset; |
289 | self->seek(self, -offset, SEEK_CUR); | 427 | self->seek(self, -offset, SEEK_CUR); |
290 | break; | 428 | break; |
291 | case NEWT_KEY_HOME: | 429 | case K_HOME: |
292 | ui_browser__reset_index(self); | 430 | ui_browser__reset_index(self); |
293 | break; | 431 | break; |
294 | case NEWT_KEY_END: | 432 | case K_END: |
295 | offset = self->height - 1; | 433 | offset = self->height - 1; |
296 | if (offset >= self->nr_entries) | 434 | if (offset >= self->nr_entries) |
297 | offset = self->nr_entries - 1; | 435 | offset = self->nr_entries - 1; |
@@ -301,10 +439,8 @@ int ui_browser__run(struct ui_browser *self) | |||
301 | self->seek(self, -offset, SEEK_END); | 439 | self->seek(self, -offset, SEEK_END); |
302 | break; | 440 | break; |
303 | default: | 441 | default: |
304 | return es.u.key; | 442 | return key; |
305 | } | 443 | } |
306 | if (ui_browser__refresh(self) < 0) | ||
307 | return -1; | ||
308 | } | 444 | } |
309 | return -1; | 445 | return -1; |
310 | } | 446 | } |
@@ -316,41 +452,146 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self) | |||
316 | int row = 0; | 452 | int row = 0; |
317 | 453 | ||
318 | if (self->top == NULL || self->top == self->entries) | 454 | if (self->top == NULL || self->top == self->entries) |
319 | self->top = head->next; | 455 | self->top = ui_browser__list_head_filter_entries(self, head->next); |
320 | 456 | ||
321 | pos = self->top; | 457 | pos = self->top; |
322 | 458 | ||
323 | list_for_each_from(pos, head) { | 459 | list_for_each_from(pos, head) { |
324 | ui_browser__gotorc(self, row, 0); | 460 | if (!self->filter || !self->filter(self, pos)) { |
325 | self->write(self, pos, row); | 461 | ui_browser__gotorc(self, row, 0); |
326 | if (++row == self->height) | 462 | self->write(self, pos, row); |
327 | break; | 463 | if (++row == self->height) |
464 | break; | ||
465 | } | ||
328 | } | 466 | } |
329 | 467 | ||
330 | return row; | 468 | return row; |
331 | } | 469 | } |
332 | 470 | ||
333 | static struct newtPercentTreeColors { | 471 | static struct ui_browser__colorset { |
334 | const char *topColorFg, *topColorBg; | 472 | const char *name, *fg, *bg; |
335 | const char *mediumColorFg, *mediumColorBg; | 473 | int colorset; |
336 | const char *normalColorFg, *normalColorBg; | 474 | } ui_browser__colorsets[] = { |
337 | const char *selColorFg, *selColorBg; | 475 | { |
338 | const char *codeColorFg, *codeColorBg; | 476 | .colorset = HE_COLORSET_TOP, |
339 | } defaultPercentTreeColors = { | 477 | .name = "top", |
340 | "red", "lightgray", | 478 | .fg = "red", |
341 | "green", "lightgray", | 479 | .bg = "default", |
342 | "black", "lightgray", | 480 | }, |
343 | "lightgray", "magenta", | 481 | { |
344 | "blue", "lightgray", | 482 | .colorset = HE_COLORSET_MEDIUM, |
483 | .name = "medium", | ||
484 | .fg = "green", | ||
485 | .bg = "default", | ||
486 | }, | ||
487 | { | ||
488 | .colorset = HE_COLORSET_NORMAL, | ||
489 | .name = "normal", | ||
490 | .fg = "default", | ||
491 | .bg = "default", | ||
492 | }, | ||
493 | { | ||
494 | .colorset = HE_COLORSET_SELECTED, | ||
495 | .name = "selected", | ||
496 | .fg = "black", | ||
497 | .bg = "lightgray", | ||
498 | }, | ||
499 | { | ||
500 | .colorset = HE_COLORSET_CODE, | ||
501 | .name = "code", | ||
502 | .fg = "blue", | ||
503 | .bg = "default", | ||
504 | }, | ||
505 | { | ||
506 | .name = NULL, | ||
507 | } | ||
345 | }; | 508 | }; |
346 | 509 | ||
510 | |||
511 | static int ui_browser__color_config(const char *var, const char *value, | ||
512 | void *data __used) | ||
513 | { | ||
514 | char *fg = NULL, *bg; | ||
515 | int i; | ||
516 | |||
517 | /* same dir for all commands */ | ||
518 | if (prefixcmp(var, "colors.") != 0) | ||
519 | return 0; | ||
520 | |||
521 | for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) { | ||
522 | const char *name = var + 7; | ||
523 | |||
524 | if (strcmp(ui_browser__colorsets[i].name, name) != 0) | ||
525 | continue; | ||
526 | |||
527 | fg = strdup(value); | ||
528 | if (fg == NULL) | ||
529 | break; | ||
530 | |||
531 | bg = strchr(fg, ','); | ||
532 | if (bg == NULL) | ||
533 | break; | ||
534 | |||
535 | *bg = '\0'; | ||
536 | while (isspace(*++bg)); | ||
537 | ui_browser__colorsets[i].bg = bg; | ||
538 | ui_browser__colorsets[i].fg = fg; | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | free(fg); | ||
543 | return -1; | ||
544 | } | ||
545 | |||
546 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence) | ||
547 | { | ||
548 | switch (whence) { | ||
549 | case SEEK_SET: | ||
550 | browser->top = browser->entries; | ||
551 | break; | ||
552 | case SEEK_CUR: | ||
553 | browser->top = browser->top + browser->top_idx + offset; | ||
554 | break; | ||
555 | case SEEK_END: | ||
556 | browser->top = browser->top + browser->nr_entries + offset; | ||
557 | break; | ||
558 | default: | ||
559 | return; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser) | ||
564 | { | ||
565 | unsigned int row = 0, idx = browser->top_idx; | ||
566 | char **pos; | ||
567 | |||
568 | if (browser->top == NULL) | ||
569 | browser->top = browser->entries; | ||
570 | |||
571 | pos = (char **)browser->top; | ||
572 | while (idx < browser->nr_entries) { | ||
573 | if (!browser->filter || !browser->filter(browser, *pos)) { | ||
574 | ui_browser__gotorc(browser, row, 0); | ||
575 | browser->write(browser, pos, row); | ||
576 | if (++row == browser->height) | ||
577 | break; | ||
578 | } | ||
579 | |||
580 | ++idx; | ||
581 | ++pos; | ||
582 | } | ||
583 | |||
584 | return row; | ||
585 | } | ||
586 | |||
347 | void ui_browser__init(void) | 587 | void ui_browser__init(void) |
348 | { | 588 | { |
349 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; | 589 | int i = 0; |
590 | |||
591 | perf_config(ui_browser__color_config, NULL); | ||
350 | 592 | ||
351 | sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); | 593 | while (ui_browser__colorsets[i].name) { |
352 | sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); | 594 | struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; |
353 | sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); | 595 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); |
354 | sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); | 596 | } |
355 | sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg); | ||
356 | } | 597 | } |
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index fc63dda10910..84d761b730c1 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define _PERF_UI_BROWSER_H_ 1 | 2 | #define _PERF_UI_BROWSER_H_ 1 |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <newt.h> | ||
6 | #include <sys/types.h> | 5 | #include <sys/types.h> |
7 | #include "../types.h" | 6 | #include "../types.h" |
8 | 7 | ||
@@ -13,15 +12,19 @@ | |||
13 | #define HE_COLORSET_CODE 54 | 12 | #define HE_COLORSET_CODE 54 |
14 | 13 | ||
15 | struct ui_browser { | 14 | struct ui_browser { |
16 | newtComponent form, sb; | ||
17 | u64 index, top_idx; | 15 | u64 index, top_idx; |
18 | void *top, *entries; | 16 | void *top, *entries; |
19 | u16 y, x, width, height; | 17 | u16 y, x, width, height; |
20 | void *priv; | 18 | void *priv; |
19 | const char *title; | ||
20 | char *helpline; | ||
21 | unsigned int (*refresh)(struct ui_browser *self); | 21 | unsigned int (*refresh)(struct ui_browser *self); |
22 | void (*write)(struct ui_browser *self, void *entry, int row); | 22 | void (*write)(struct ui_browser *self, void *entry, int row); |
23 | void (*seek)(struct ui_browser *self, off_t offset, int whence); | 23 | void (*seek)(struct ui_browser *self, off_t offset, int whence); |
24 | bool (*filter)(struct ui_browser *self, void *entry); | ||
24 | u32 nr_entries; | 25 | u32 nr_entries; |
26 | bool navkeypressed; | ||
27 | bool use_navkeypressed; | ||
25 | }; | 28 | }; |
26 | 29 | ||
27 | void ui_browser__set_color(struct ui_browser *self, int color); | 30 | void ui_browser__set_color(struct ui_browser *self, int color); |
@@ -32,15 +35,23 @@ void ui_browser__refresh_dimensions(struct ui_browser *self); | |||
32 | void ui_browser__reset_index(struct ui_browser *self); | 35 | void ui_browser__reset_index(struct ui_browser *self); |
33 | 36 | ||
34 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); | 37 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); |
35 | void ui_browser__add_exit_key(struct ui_browser *self, int key); | ||
36 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); | ||
37 | void __ui_browser__show_title(struct ui_browser *browser, const char *title); | 38 | void __ui_browser__show_title(struct ui_browser *browser, const char *title); |
38 | void ui_browser__show_title(struct ui_browser *browser, const char *title); | 39 | void ui_browser__show_title(struct ui_browser *browser, const char *title); |
39 | int ui_browser__show(struct ui_browser *self, const char *title, | 40 | int ui_browser__show(struct ui_browser *self, const char *title, |
40 | const char *helpline, ...); | 41 | const char *helpline, ...); |
41 | void ui_browser__hide(struct ui_browser *self); | 42 | void ui_browser__hide(struct ui_browser *self); |
42 | int ui_browser__refresh(struct ui_browser *self); | 43 | int ui_browser__refresh(struct ui_browser *self); |
43 | int ui_browser__run(struct ui_browser *self); | 44 | int ui_browser__run(struct ui_browser *browser, int delay_secs); |
45 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); | ||
46 | void ui_browser__handle_resize(struct ui_browser *browser); | ||
47 | |||
48 | int ui_browser__warning(struct ui_browser *browser, int timeout, | ||
49 | const char *format, ...); | ||
50 | int ui_browser__help_window(struct ui_browser *browser, const char *text); | ||
51 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); | ||
52 | |||
53 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); | ||
54 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser); | ||
44 | 55 | ||
45 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); | 56 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); |
46 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); | 57 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 0229723aceb3..0575905d1205 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -1,31 +1,31 @@ | |||
1 | #include "../../util.h" | ||
1 | #include "../browser.h" | 2 | #include "../browser.h" |
2 | #include "../helpline.h" | 3 | #include "../helpline.h" |
3 | #include "../libslang.h" | 4 | #include "../libslang.h" |
5 | #include "../ui.h" | ||
6 | #include "../util.h" | ||
4 | #include "../../annotate.h" | 7 | #include "../../annotate.h" |
5 | #include "../../hist.h" | 8 | #include "../../hist.h" |
6 | #include "../../sort.h" | 9 | #include "../../sort.h" |
7 | #include "../../symbol.h" | 10 | #include "../../symbol.h" |
8 | #include <pthread.h> | 11 | #include <pthread.h> |
9 | 12 | #include <newt.h> | |
10 | static void ui__error_window(const char *fmt, ...) | ||
11 | { | ||
12 | va_list ap; | ||
13 | |||
14 | va_start(ap, fmt); | ||
15 | newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap); | ||
16 | va_end(ap); | ||
17 | } | ||
18 | 13 | ||
19 | struct annotate_browser { | 14 | struct annotate_browser { |
20 | struct ui_browser b; | 15 | struct ui_browser b; |
21 | struct rb_root entries; | 16 | struct rb_root entries; |
22 | struct rb_node *curr_hot; | 17 | struct rb_node *curr_hot; |
18 | struct objdump_line *selection; | ||
19 | int nr_asm_entries; | ||
20 | int nr_entries; | ||
21 | bool hide_src_code; | ||
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct objdump_line_rb_node { | 24 | struct objdump_line_rb_node { |
26 | struct rb_node rb_node; | 25 | struct rb_node rb_node; |
27 | double percent; | 26 | double percent; |
28 | u32 idx; | 27 | u32 idx; |
28 | int idx_asm; | ||
29 | }; | 29 | }; |
30 | 30 | ||
31 | static inline | 31 | static inline |
@@ -34,9 +34,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) | |||
34 | return (struct objdump_line_rb_node *)(self + 1); | 34 | return (struct objdump_line_rb_node *)(self + 1); |
35 | } | 35 | } |
36 | 36 | ||
37 | static bool objdump_line__filter(struct ui_browser *browser, void *entry) | ||
38 | { | ||
39 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | ||
40 | |||
41 | if (ab->hide_src_code) { | ||
42 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); | ||
43 | return ol->offset == -1; | ||
44 | } | ||
45 | |||
46 | return false; | ||
47 | } | ||
48 | |||
37 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | 49 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) |
38 | { | 50 | { |
39 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); | 51 | struct annotate_browser *ab = container_of(self, struct annotate_browser, b); |
52 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); | ||
40 | bool current_entry = ui_browser__is_current_entry(self, row); | 53 | bool current_entry = ui_browser__is_current_entry(self, row); |
41 | int width = self->width; | 54 | int width = self->width; |
42 | 55 | ||
@@ -51,6 +64,11 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
51 | 64 | ||
52 | SLsmg_write_char(':'); | 65 | SLsmg_write_char(':'); |
53 | slsmg_write_nstring(" ", 8); | 66 | slsmg_write_nstring(" ", 8); |
67 | |||
68 | /* The scroll bar isn't being used */ | ||
69 | if (!self->navkeypressed) | ||
70 | width += 1; | ||
71 | |||
54 | if (!*ol->line) | 72 | if (!*ol->line) |
55 | slsmg_write_nstring(" ", width - 18); | 73 | slsmg_write_nstring(" ", width - 18); |
56 | else | 74 | else |
@@ -58,6 +76,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
58 | 76 | ||
59 | if (!current_entry) | 77 | if (!current_entry) |
60 | ui_browser__set_color(self, HE_COLORSET_CODE); | 78 | ui_browser__set_color(self, HE_COLORSET_CODE); |
79 | else | ||
80 | ab->selection = ol; | ||
61 | } | 81 | } |
62 | 82 | ||
63 | static double objdump_line__calc_percent(struct objdump_line *self, | 83 | static double objdump_line__calc_percent(struct objdump_line *self, |
@@ -141,7 +161,8 @@ static void annotate_browser__set_top(struct annotate_browser *self, | |||
141 | static void annotate_browser__calc_percent(struct annotate_browser *browser, | 161 | static void annotate_browser__calc_percent(struct annotate_browser *browser, |
142 | int evidx) | 162 | int evidx) |
143 | { | 163 | { |
144 | struct symbol *sym = browser->b.priv; | 164 | struct map_symbol *ms = browser->b.priv; |
165 | struct symbol *sym = ms->sym; | ||
145 | struct annotation *notes = symbol__annotation(sym); | 166 | struct annotation *notes = symbol__annotation(sym); |
146 | struct objdump_line *pos; | 167 | struct objdump_line *pos; |
147 | 168 | ||
@@ -163,25 +184,60 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
163 | browser->curr_hot = rb_last(&browser->entries); | 184 | browser->curr_hot = rb_last(&browser->entries); |
164 | } | 185 | } |
165 | 186 | ||
187 | static bool annotate_browser__toggle_source(struct annotate_browser *browser) | ||
188 | { | ||
189 | struct objdump_line *ol; | ||
190 | struct objdump_line_rb_node *olrb; | ||
191 | off_t offset = browser->b.index - browser->b.top_idx; | ||
192 | |||
193 | browser->b.seek(&browser->b, offset, SEEK_CUR); | ||
194 | ol = list_entry(browser->b.top, struct objdump_line, node); | ||
195 | olrb = objdump_line__rb(ol); | ||
196 | |||
197 | if (browser->hide_src_code) { | ||
198 | if (olrb->idx_asm < offset) | ||
199 | offset = olrb->idx; | ||
200 | |||
201 | browser->b.nr_entries = browser->nr_entries; | ||
202 | browser->hide_src_code = false; | ||
203 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
204 | browser->b.top_idx = olrb->idx - offset; | ||
205 | browser->b.index = olrb->idx; | ||
206 | } else { | ||
207 | if (olrb->idx_asm < 0) { | ||
208 | ui_helpline__puts("Only available for assembly lines."); | ||
209 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
210 | return false; | ||
211 | } | ||
212 | |||
213 | if (olrb->idx_asm < offset) | ||
214 | offset = olrb->idx_asm; | ||
215 | |||
216 | browser->b.nr_entries = browser->nr_asm_entries; | ||
217 | browser->hide_src_code = true; | ||
218 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
219 | browser->b.top_idx = olrb->idx_asm - offset; | ||
220 | browser->b.index = olrb->idx_asm; | ||
221 | } | ||
222 | |||
223 | return true; | ||
224 | } | ||
225 | |||
166 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | 226 | static int annotate_browser__run(struct annotate_browser *self, int evidx, |
167 | int refresh) | 227 | int nr_events, void(*timer)(void *arg), |
228 | void *arg, int delay_secs) | ||
168 | { | 229 | { |
169 | struct rb_node *nd = NULL; | 230 | struct rb_node *nd = NULL; |
170 | struct symbol *sym = self->b.priv; | 231 | struct map_symbol *ms = self->b.priv; |
171 | /* | 232 | struct symbol *sym = ms->sym; |
172 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by | 233 | const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, " |
173 | * examining the exit key for this function. | 234 | "H: Hottest, -> Line action, S -> Toggle source " |
174 | */ | 235 | "code view"; |
175 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, | ||
176 | NEWT_KEY_RIGHT, 0 }; | ||
177 | int key; | 236 | int key; |
178 | 237 | ||
179 | if (ui_browser__show(&self->b, sym->name, | 238 | if (ui_browser__show(&self->b, sym->name, help) < 0) |
180 | "<-, -> or ESC: exit, TAB/shift+TAB: " | ||
181 | "cycle hottest lines, H: Hottest") < 0) | ||
182 | return -1; | 239 | return -1; |
183 | 240 | ||
184 | ui_browser__add_exit_keys(&self->b, exit_keys); | ||
185 | annotate_browser__calc_percent(self, evidx); | 241 | annotate_browser__calc_percent(self, evidx); |
186 | 242 | ||
187 | if (self->curr_hot) | 243 | if (self->curr_hot) |
@@ -189,13 +245,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
189 | 245 | ||
190 | nd = self->curr_hot; | 246 | nd = self->curr_hot; |
191 | 247 | ||
192 | if (refresh != 0) | ||
193 | newtFormSetTimer(self->b.form, refresh); | ||
194 | |||
195 | while (1) { | 248 | while (1) { |
196 | key = ui_browser__run(&self->b); | 249 | key = ui_browser__run(&self->b, delay_secs); |
197 | 250 | ||
198 | if (refresh != 0) { | 251 | if (delay_secs != 0) { |
199 | annotate_browser__calc_percent(self, evidx); | 252 | annotate_browser__calc_percent(self, evidx); |
200 | /* | 253 | /* |
201 | * Current line focus got out of the list of most active | 254 | * Current line focus got out of the list of most active |
@@ -207,15 +260,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
207 | } | 260 | } |
208 | 261 | ||
209 | switch (key) { | 262 | switch (key) { |
210 | case -1: | 263 | case K_TIMER: |
211 | /* | 264 | if (timer != NULL) |
212 | * FIXME we need to check if it was | 265 | timer(arg); |
213 | * es.reason == NEWT_EXIT_TIMER | 266 | |
214 | */ | 267 | if (delay_secs != 0) |
215 | if (refresh != 0) | ||
216 | symbol__annotate_decay_histogram(sym, evidx); | 268 | symbol__annotate_decay_histogram(sym, evidx); |
217 | continue; | 269 | continue; |
218 | case NEWT_KEY_TAB: | 270 | case K_TAB: |
219 | if (nd != NULL) { | 271 | if (nd != NULL) { |
220 | nd = rb_prev(nd); | 272 | nd = rb_prev(nd); |
221 | if (nd == NULL) | 273 | if (nd == NULL) |
@@ -223,7 +275,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
223 | } else | 275 | } else |
224 | nd = self->curr_hot; | 276 | nd = self->curr_hot; |
225 | break; | 277 | break; |
226 | case NEWT_KEY_UNTAB: | 278 | case K_UNTAB: |
227 | if (nd != NULL) | 279 | if (nd != NULL) |
228 | nd = rb_next(nd); | 280 | nd = rb_next(nd); |
229 | if (nd == NULL) | 281 | if (nd == NULL) |
@@ -234,8 +286,68 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
234 | case 'H': | 286 | case 'H': |
235 | nd = self->curr_hot; | 287 | nd = self->curr_hot; |
236 | break; | 288 | break; |
237 | default: | 289 | case 'S': |
290 | if (annotate_browser__toggle_source(self)) | ||
291 | ui_helpline__puts(help); | ||
292 | continue; | ||
293 | case K_ENTER: | ||
294 | case K_RIGHT: | ||
295 | if (self->selection == NULL) { | ||
296 | ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); | ||
297 | continue; | ||
298 | } | ||
299 | |||
300 | if (self->selection->offset == -1) { | ||
301 | ui_helpline__puts("Actions are only available for assembly lines."); | ||
302 | continue; | ||
303 | } else { | ||
304 | char *s = strstr(self->selection->line, "callq "); | ||
305 | struct annotation *notes; | ||
306 | struct symbol *target; | ||
307 | u64 ip; | ||
308 | |||
309 | if (s == NULL) { | ||
310 | ui_helpline__puts("Actions are only available for the 'callq' instruction."); | ||
311 | continue; | ||
312 | } | ||
313 | |||
314 | s = strchr(s, ' '); | ||
315 | if (s++ == NULL) { | ||
316 | ui_helpline__puts("Invallid callq instruction."); | ||
317 | continue; | ||
318 | } | ||
319 | |||
320 | ip = strtoull(s, NULL, 16); | ||
321 | ip = ms->map->map_ip(ms->map, ip); | ||
322 | target = map__find_symbol(ms->map, ip, NULL); | ||
323 | if (target == NULL) { | ||
324 | ui_helpline__puts("The called function was not found."); | ||
325 | continue; | ||
326 | } | ||
327 | |||
328 | notes = symbol__annotation(target); | ||
329 | pthread_mutex_lock(¬es->lock); | ||
330 | |||
331 | if (notes->src == NULL && | ||
332 | symbol__alloc_hist(target, nr_events) < 0) { | ||
333 | pthread_mutex_unlock(¬es->lock); | ||
334 | ui__warning("Not enough memory for annotating '%s' symbol!\n", | ||
335 | target->name); | ||
336 | continue; | ||
337 | } | ||
338 | |||
339 | pthread_mutex_unlock(¬es->lock); | ||
340 | symbol__tui_annotate(target, ms->map, evidx, nr_events, | ||
341 | timer, arg, delay_secs); | ||
342 | } | ||
343 | continue; | ||
344 | case K_LEFT: | ||
345 | case K_ESC: | ||
346 | case 'q': | ||
347 | case CTRL('c'): | ||
238 | goto out; | 348 | goto out; |
349 | default: | ||
350 | continue; | ||
239 | } | 351 | } |
240 | 352 | ||
241 | if (nd != NULL) | 353 | if (nd != NULL) |
@@ -246,22 +358,31 @@ out: | |||
246 | return key; | 358 | return key; |
247 | } | 359 | } |
248 | 360 | ||
249 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx) | 361 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, |
362 | void(*timer)(void *arg), void *arg, int delay_secs) | ||
250 | { | 363 | { |
251 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); | 364 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, |
365 | timer, arg, delay_secs); | ||
252 | } | 366 | } |
253 | 367 | ||
254 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 368 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
255 | int refresh) | 369 | int nr_events, void(*timer)(void *arg), void *arg, |
370 | int delay_secs) | ||
256 | { | 371 | { |
257 | struct objdump_line *pos, *n; | 372 | struct objdump_line *pos, *n; |
258 | struct annotation *notes; | 373 | struct annotation *notes; |
374 | struct map_symbol ms = { | ||
375 | .map = map, | ||
376 | .sym = sym, | ||
377 | }; | ||
259 | struct annotate_browser browser = { | 378 | struct annotate_browser browser = { |
260 | .b = { | 379 | .b = { |
261 | .refresh = ui_browser__list_head_refresh, | 380 | .refresh = ui_browser__list_head_refresh, |
262 | .seek = ui_browser__list_head_seek, | 381 | .seek = ui_browser__list_head_seek, |
263 | .write = annotate_browser__write, | 382 | .write = annotate_browser__write, |
264 | .priv = sym, | 383 | .filter = objdump_line__filter, |
384 | .priv = &ms, | ||
385 | .use_navkeypressed = true, | ||
265 | }, | 386 | }, |
266 | }; | 387 | }; |
267 | int ret; | 388 | int ret; |
@@ -273,7 +394,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
273 | return -1; | 394 | return -1; |
274 | 395 | ||
275 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { | 396 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { |
276 | ui__error_window(ui_helpline__last_msg); | 397 | ui__error("%s", ui_helpline__last_msg); |
277 | return -1; | 398 | return -1; |
278 | } | 399 | } |
279 | 400 | ||
@@ -288,12 +409,18 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
288 | if (browser.b.width < line_len) | 409 | if (browser.b.width < line_len) |
289 | browser.b.width = line_len; | 410 | browser.b.width = line_len; |
290 | rbpos = objdump_line__rb(pos); | 411 | rbpos = objdump_line__rb(pos); |
291 | rbpos->idx = browser.b.nr_entries++; | 412 | rbpos->idx = browser.nr_entries++; |
413 | if (pos->offset != -1) | ||
414 | rbpos->idx_asm = browser.nr_asm_entries++; | ||
415 | else | ||
416 | rbpos->idx_asm = -1; | ||
292 | } | 417 | } |
293 | 418 | ||
419 | browser.b.nr_entries = browser.nr_entries; | ||
294 | browser.b.entries = ¬es->src->source, | 420 | browser.b.entries = ¬es->src->source, |
295 | browser.b.width += 18; /* Percentage */ | 421 | browser.b.width += 18; /* Percentage */ |
296 | ret = annotate_browser__run(&browser, evidx, refresh); | 422 | ret = annotate_browser__run(&browser, evidx, nr_events, |
423 | timer, arg, delay_secs); | ||
297 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | 424 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
298 | list_del(&pos->node); | 425 | list_del(&pos->node); |
299 | objdump_line__free(pos); | 426 | objdump_line__free(pos); |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 5d767c622dfc..d0c94b459685 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "../browser.h" | 17 | #include "../browser.h" |
18 | #include "../helpline.h" | 18 | #include "../helpline.h" |
19 | #include "../util.h" | 19 | #include "../util.h" |
20 | #include "../ui.h" | ||
20 | #include "map.h" | 21 | #include "map.h" |
21 | 22 | ||
22 | struct hist_browser { | 23 | struct hist_browser { |
@@ -24,8 +25,12 @@ struct hist_browser { | |||
24 | struct hists *hists; | 25 | struct hists *hists; |
25 | struct hist_entry *he_selection; | 26 | struct hist_entry *he_selection; |
26 | struct map_symbol *selection; | 27 | struct map_symbol *selection; |
28 | bool has_symbols; | ||
27 | }; | 29 | }; |
28 | 30 | ||
31 | static int hists__browser_title(struct hists *self, char *bf, size_t size, | ||
32 | const char *ev_name); | ||
33 | |||
29 | static void hist_browser__refresh_dimensions(struct hist_browser *self) | 34 | static void hist_browser__refresh_dimensions(struct hist_browser *self) |
30 | { | 35 | { |
31 | /* 3 == +/- toggle symbol before actual hist_entry rendering */ | 36 | /* 3 == +/- toggle symbol before actual hist_entry rendering */ |
@@ -290,28 +295,49 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold) | |||
290 | ui_browser__reset_index(&self->b); | 295 | ui_browser__reset_index(&self->b); |
291 | } | 296 | } |
292 | 297 | ||
293 | static int hist_browser__run(struct hist_browser *self, const char *title) | 298 | static void ui_browser__warn_lost_events(struct ui_browser *browser) |
299 | { | ||
300 | ui_browser__warning(browser, 4, | ||
301 | "Events are being lost, check IO/CPU overload!\n\n" | ||
302 | "You may want to run 'perf' using a RT scheduler policy:\n\n" | ||
303 | " perf top -r 80\n\n" | ||
304 | "Or reduce the sampling frequency."); | ||
305 | } | ||
306 | |||
307 | static int hist_browser__run(struct hist_browser *self, const char *ev_name, | ||
308 | void(*timer)(void *arg), void *arg, int delay_secs) | ||
294 | { | 309 | { |
295 | int key; | 310 | int key; |
296 | int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't', | 311 | char title[160]; |
297 | NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, | ||
298 | NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, }; | ||
299 | 312 | ||
300 | self->b.entries = &self->hists->entries; | 313 | self->b.entries = &self->hists->entries; |
301 | self->b.nr_entries = self->hists->nr_entries; | 314 | self->b.nr_entries = self->hists->nr_entries; |
302 | 315 | ||
303 | hist_browser__refresh_dimensions(self); | 316 | hist_browser__refresh_dimensions(self); |
317 | hists__browser_title(self->hists, title, sizeof(title), ev_name); | ||
304 | 318 | ||
305 | if (ui_browser__show(&self->b, title, | 319 | if (ui_browser__show(&self->b, title, |
306 | "Press '?' for help on key bindings") < 0) | 320 | "Press '?' for help on key bindings") < 0) |
307 | return -1; | 321 | return -1; |
308 | 322 | ||
309 | ui_browser__add_exit_keys(&self->b, exit_keys); | ||
310 | |||
311 | while (1) { | 323 | while (1) { |
312 | key = ui_browser__run(&self->b); | 324 | key = ui_browser__run(&self->b, delay_secs); |
313 | 325 | ||
314 | switch (key) { | 326 | switch (key) { |
327 | case K_TIMER: | ||
328 | timer(arg); | ||
329 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); | ||
330 | |||
331 | if (self->hists->stats.nr_lost_warned != | ||
332 | self->hists->stats.nr_events[PERF_RECORD_LOST]) { | ||
333 | self->hists->stats.nr_lost_warned = | ||
334 | self->hists->stats.nr_events[PERF_RECORD_LOST]; | ||
335 | ui_browser__warn_lost_events(&self->b); | ||
336 | } | ||
337 | |||
338 | hists__browser_title(self->hists, title, sizeof(title), ev_name); | ||
339 | ui_browser__show_title(&self->b, title); | ||
340 | continue; | ||
315 | case 'D': { /* Debug */ | 341 | case 'D': { /* Debug */ |
316 | static int seq; | 342 | static int seq; |
317 | struct hist_entry *h = rb_entry(self->b.top, | 343 | struct hist_entry *h = rb_entry(self->b.top, |
@@ -334,7 +360,7 @@ static int hist_browser__run(struct hist_browser *self, const char *title) | |||
334 | /* Expand the whole world. */ | 360 | /* Expand the whole world. */ |
335 | hist_browser__set_folding(self, true); | 361 | hist_browser__set_folding(self, true); |
336 | break; | 362 | break; |
337 | case NEWT_KEY_ENTER: | 363 | case K_ENTER: |
338 | if (hist_browser__toggle_fold(self)) | 364 | if (hist_browser__toggle_fold(self)) |
339 | break; | 365 | break; |
340 | /* fall thru */ | 366 | /* fall thru */ |
@@ -532,7 +558,7 @@ static int hist_browser__show_entry(struct hist_browser *self, | |||
532 | char s[256]; | 558 | char s[256]; |
533 | double percent; | 559 | double percent; |
534 | int printed = 0; | 560 | int printed = 0; |
535 | int color, width = self->b.width; | 561 | int width = self->b.width - 6; /* The percentage */ |
536 | char folded_sign = ' '; | 562 | char folded_sign = ' '; |
537 | bool current_entry = ui_browser__is_current_entry(&self->b, row); | 563 | bool current_entry = ui_browser__is_current_entry(&self->b, row); |
538 | off_t row_offset = entry->row_offset; | 564 | off_t row_offset = entry->row_offset; |
@@ -548,26 +574,35 @@ static int hist_browser__show_entry(struct hist_browser *self, | |||
548 | } | 574 | } |
549 | 575 | ||
550 | if (row_offset == 0) { | 576 | if (row_offset == 0) { |
551 | hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false, | 577 | hist_entry__snprintf(entry, s, sizeof(s), self->hists); |
552 | 0, false, self->hists->stats.total_period); | ||
553 | percent = (entry->period * 100.0) / self->hists->stats.total_period; | 578 | percent = (entry->period * 100.0) / self->hists->stats.total_period; |
554 | 579 | ||
555 | color = HE_COLORSET_SELECTED; | 580 | ui_browser__set_percent_color(&self->b, percent, current_entry); |
556 | if (!current_entry) { | ||
557 | if (percent >= MIN_RED) | ||
558 | color = HE_COLORSET_TOP; | ||
559 | else if (percent >= MIN_GREEN) | ||
560 | color = HE_COLORSET_MEDIUM; | ||
561 | else | ||
562 | color = HE_COLORSET_NORMAL; | ||
563 | } | ||
564 | |||
565 | ui_browser__set_color(&self->b, color); | ||
566 | ui_browser__gotorc(&self->b, row, 0); | 581 | ui_browser__gotorc(&self->b, row, 0); |
567 | if (symbol_conf.use_callchain) { | 582 | if (symbol_conf.use_callchain) { |
568 | slsmg_printf("%c ", folded_sign); | 583 | slsmg_printf("%c ", folded_sign); |
569 | width -= 2; | 584 | width -= 2; |
570 | } | 585 | } |
586 | |||
587 | slsmg_printf(" %5.2f%%", percent); | ||
588 | |||
589 | /* The scroll bar isn't being used */ | ||
590 | if (!self->b.navkeypressed) | ||
591 | width += 1; | ||
592 | |||
593 | if (!current_entry || !self->b.navkeypressed) | ||
594 | ui_browser__set_color(&self->b, HE_COLORSET_NORMAL); | ||
595 | |||
596 | if (symbol_conf.show_nr_samples) { | ||
597 | slsmg_printf(" %11u", entry->nr_events); | ||
598 | width -= 12; | ||
599 | } | ||
600 | |||
601 | if (symbol_conf.show_total_period) { | ||
602 | slsmg_printf(" %12" PRIu64, entry->period); | ||
603 | width -= 13; | ||
604 | } | ||
605 | |||
571 | slsmg_write_nstring(s, width); | 606 | slsmg_write_nstring(s, width); |
572 | ++row; | 607 | ++row; |
573 | ++printed; | 608 | ++printed; |
@@ -585,14 +620,23 @@ static int hist_browser__show_entry(struct hist_browser *self, | |||
585 | return printed; | 620 | return printed; |
586 | } | 621 | } |
587 | 622 | ||
623 | static void ui_browser__hists_init_top(struct ui_browser *browser) | ||
624 | { | ||
625 | if (browser->top == NULL) { | ||
626 | struct hist_browser *hb; | ||
627 | |||
628 | hb = container_of(browser, struct hist_browser, b); | ||
629 | browser->top = rb_first(&hb->hists->entries); | ||
630 | } | ||
631 | } | ||
632 | |||
588 | static unsigned int hist_browser__refresh(struct ui_browser *self) | 633 | static unsigned int hist_browser__refresh(struct ui_browser *self) |
589 | { | 634 | { |
590 | unsigned row = 0; | 635 | unsigned row = 0; |
591 | struct rb_node *nd; | 636 | struct rb_node *nd; |
592 | struct hist_browser *hb = container_of(self, struct hist_browser, b); | 637 | struct hist_browser *hb = container_of(self, struct hist_browser, b); |
593 | 638 | ||
594 | if (self->top == NULL) | 639 | ui_browser__hists_init_top(self); |
595 | self->top = rb_first(&hb->hists->entries); | ||
596 | 640 | ||
597 | for (nd = self->top; nd; nd = rb_next(nd)) { | 641 | for (nd = self->top; nd; nd = rb_next(nd)) { |
598 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 642 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
@@ -644,6 +688,8 @@ static void ui_browser__hists_seek(struct ui_browser *self, | |||
644 | if (self->nr_entries == 0) | 688 | if (self->nr_entries == 0) |
645 | return; | 689 | return; |
646 | 690 | ||
691 | ui_browser__hists_init_top(self); | ||
692 | |||
647 | switch (whence) { | 693 | switch (whence) { |
648 | case SEEK_SET: | 694 | case SEEK_SET: |
649 | nd = hists__filter_entries(rb_first(self->entries)); | 695 | nd = hists__filter_entries(rb_first(self->entries)); |
@@ -761,6 +807,8 @@ static struct hist_browser *hist_browser__new(struct hists *hists) | |||
761 | self->hists = hists; | 807 | self->hists = hists; |
762 | self->b.refresh = hist_browser__refresh; | 808 | self->b.refresh = hist_browser__refresh; |
763 | self->b.seek = ui_browser__hists_seek; | 809 | self->b.seek = ui_browser__hists_seek; |
810 | self->b.use_navkeypressed = true, | ||
811 | self->has_symbols = sort_sym.list.next != NULL; | ||
764 | } | 812 | } |
765 | 813 | ||
766 | return self; | 814 | return self; |
@@ -782,11 +830,12 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self) | |||
782 | } | 830 | } |
783 | 831 | ||
784 | static int hists__browser_title(struct hists *self, char *bf, size_t size, | 832 | static int hists__browser_title(struct hists *self, char *bf, size_t size, |
785 | const char *ev_name, const struct dso *dso, | 833 | const char *ev_name) |
786 | const struct thread *thread) | ||
787 | { | 834 | { |
788 | char unit; | 835 | char unit; |
789 | int printed; | 836 | int printed; |
837 | const struct dso *dso = self->dso_filter; | ||
838 | const struct thread *thread = self->thread_filter; | ||
790 | unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; | 839 | unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; |
791 | 840 | ||
792 | nr_events = convert_unit(nr_events, &unit); | 841 | nr_events = convert_unit(nr_events, &unit); |
@@ -803,16 +852,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, | |||
803 | return printed; | 852 | return printed; |
804 | } | 853 | } |
805 | 854 | ||
806 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, | 855 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
807 | const char *helpline, const char *ev_name, | 856 | const char *helpline, const char *ev_name, |
808 | bool left_exits) | 857 | bool left_exits, |
858 | void(*timer)(void *arg), void *arg, | ||
859 | int delay_secs) | ||
809 | { | 860 | { |
810 | struct hists *self = &evsel->hists; | 861 | struct hists *self = &evsel->hists; |
811 | struct hist_browser *browser = hist_browser__new(self); | 862 | struct hist_browser *browser = hist_browser__new(self); |
812 | struct pstack *fstack; | 863 | struct pstack *fstack; |
813 | const struct thread *thread_filter = NULL; | ||
814 | const struct dso *dso_filter = NULL; | ||
815 | char msg[160]; | ||
816 | int key = -1; | 864 | int key = -1; |
817 | 865 | ||
818 | if (browser == NULL) | 866 | if (browser == NULL) |
@@ -824,8 +872,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
824 | 872 | ||
825 | ui_helpline__push(helpline); | 873 | ui_helpline__push(helpline); |
826 | 874 | ||
827 | hists__browser_title(self, msg, sizeof(msg), ev_name, | ||
828 | dso_filter, thread_filter); | ||
829 | while (1) { | 875 | while (1) { |
830 | const struct thread *thread = NULL; | 876 | const struct thread *thread = NULL; |
831 | const struct dso *dso = NULL; | 877 | const struct dso *dso = NULL; |
@@ -834,7 +880,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
834 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 880 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
835 | browse_map = -2; | 881 | browse_map = -2; |
836 | 882 | ||
837 | key = hist_browser__run(browser, msg); | 883 | key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); |
838 | 884 | ||
839 | if (browser->he_selection != NULL) { | 885 | if (browser->he_selection != NULL) { |
840 | thread = hist_browser__selected_thread(browser); | 886 | thread = hist_browser__selected_thread(browser); |
@@ -842,14 +888,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
842 | } | 888 | } |
843 | 889 | ||
844 | switch (key) { | 890 | switch (key) { |
845 | case NEWT_KEY_TAB: | 891 | case K_TAB: |
846 | case NEWT_KEY_UNTAB: | 892 | case K_UNTAB: |
893 | if (nr_events == 1) | ||
894 | continue; | ||
847 | /* | 895 | /* |
848 | * Exit the browser, let hists__browser_tree | 896 | * Exit the browser, let hists__browser_tree |
849 | * go to the next or previous | 897 | * go to the next or previous |
850 | */ | 898 | */ |
851 | goto out_free_stack; | 899 | goto out_free_stack; |
852 | case 'a': | 900 | case 'a': |
901 | if (!browser->has_symbols) { | ||
902 | ui_browser__warning(&browser->b, delay_secs * 2, | ||
903 | "Annotation is only available for symbolic views, " | ||
904 | "include \"sym\" in --sort to use it."); | ||
905 | continue; | ||
906 | } | ||
907 | |||
853 | if (browser->selection == NULL || | 908 | if (browser->selection == NULL || |
854 | browser->selection->sym == NULL || | 909 | browser->selection->sym == NULL || |
855 | browser->selection->map->dso->annotate_warned) | 910 | browser->selection->map->dso->annotate_warned) |
@@ -859,25 +914,30 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
859 | goto zoom_dso; | 914 | goto zoom_dso; |
860 | case 't': | 915 | case 't': |
861 | goto zoom_thread; | 916 | goto zoom_thread; |
862 | case NEWT_KEY_F1: | 917 | case K_F1: |
863 | case 'h': | 918 | case 'h': |
864 | case '?': | 919 | case '?': |
865 | ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n" | 920 | ui_browser__help_window(&browser->b, |
866 | "<- Zoom out\n" | 921 | "h/?/F1 Show this window\n" |
867 | "a Annotate current symbol\n" | 922 | "UP/DOWN/PGUP\n" |
868 | "h/?/F1 Show this window\n" | 923 | "PGDN/SPACE Navigate\n" |
869 | "C Collapse all callchains\n" | 924 | "q/ESC/CTRL+C Exit browser\n\n" |
870 | "E Expand all callchains\n" | 925 | "For multiple event sessions:\n\n" |
871 | "d Zoom into current DSO\n" | 926 | "TAB/UNTAB Switch events\n\n" |
872 | "t Zoom into current Thread\n" | 927 | "For symbolic views (--sort has sym):\n\n" |
873 | "TAB/UNTAB Switch events\n" | 928 | "-> Zoom into DSO/Threads & Annotate current symbol\n" |
874 | "q/CTRL+C Exit browser"); | 929 | "<- Zoom out\n" |
930 | "a Annotate current symbol\n" | ||
931 | "C Collapse all callchains\n" | ||
932 | "E Expand all callchains\n" | ||
933 | "d Zoom into current DSO\n" | ||
934 | "t Zoom into current Thread"); | ||
875 | continue; | 935 | continue; |
876 | case NEWT_KEY_ENTER: | 936 | case K_ENTER: |
877 | case NEWT_KEY_RIGHT: | 937 | case K_RIGHT: |
878 | /* menu */ | 938 | /* menu */ |
879 | break; | 939 | break; |
880 | case NEWT_KEY_LEFT: { | 940 | case K_LEFT: { |
881 | const void *top; | 941 | const void *top; |
882 | 942 | ||
883 | if (pstack__empty(fstack)) { | 943 | if (pstack__empty(fstack)) { |
@@ -889,21 +949,28 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
889 | continue; | 949 | continue; |
890 | } | 950 | } |
891 | top = pstack__pop(fstack); | 951 | top = pstack__pop(fstack); |
892 | if (top == &dso_filter) | 952 | if (top == &browser->hists->dso_filter) |
893 | goto zoom_out_dso; | 953 | goto zoom_out_dso; |
894 | if (top == &thread_filter) | 954 | if (top == &browser->hists->thread_filter) |
895 | goto zoom_out_thread; | 955 | goto zoom_out_thread; |
896 | continue; | 956 | continue; |
897 | } | 957 | } |
898 | case NEWT_KEY_ESCAPE: | 958 | case K_ESC: |
899 | if (!left_exits && | 959 | if (!left_exits && |
900 | !ui__dialog_yesno("Do you really want to exit?")) | 960 | !ui_browser__dialog_yesno(&browser->b, |
961 | "Do you really want to exit?")) | ||
901 | continue; | 962 | continue; |
902 | /* Fall thru */ | 963 | /* Fall thru */ |
903 | default: | 964 | case 'q': |
965 | case CTRL('c'): | ||
904 | goto out_free_stack; | 966 | goto out_free_stack; |
967 | default: | ||
968 | continue; | ||
905 | } | 969 | } |
906 | 970 | ||
971 | if (!browser->has_symbols) | ||
972 | goto add_exit_option; | ||
973 | |||
907 | if (browser->selection != NULL && | 974 | if (browser->selection != NULL && |
908 | browser->selection->sym != NULL && | 975 | browser->selection->sym != NULL && |
909 | !browser->selection->map->dso->annotate_warned && | 976 | !browser->selection->map->dso->annotate_warned && |
@@ -913,14 +980,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
913 | 980 | ||
914 | if (thread != NULL && | 981 | if (thread != NULL && |
915 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", | 982 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", |
916 | (thread_filter ? "out of" : "into"), | 983 | (browser->hists->thread_filter ? "out of" : "into"), |
917 | (thread->comm_set ? thread->comm : ""), | 984 | (thread->comm_set ? thread->comm : ""), |
918 | thread->pid) > 0) | 985 | thread->pid) > 0) |
919 | zoom_thread = nr_options++; | 986 | zoom_thread = nr_options++; |
920 | 987 | ||
921 | if (dso != NULL && | 988 | if (dso != NULL && |
922 | asprintf(&options[nr_options], "Zoom %s %s DSO", | 989 | asprintf(&options[nr_options], "Zoom %s %s DSO", |
923 | (dso_filter ? "out of" : "into"), | 990 | (browser->hists->dso_filter ? "out of" : "into"), |
924 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) | 991 | (dso->kernel ? "the Kernel" : dso->short_name)) > 0) |
925 | zoom_dso = nr_options++; | 992 | zoom_dso = nr_options++; |
926 | 993 | ||
@@ -928,7 +995,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
928 | browser->selection->map != NULL && | 995 | browser->selection->map != NULL && |
929 | asprintf(&options[nr_options], "Browse map details") > 0) | 996 | asprintf(&options[nr_options], "Browse map details") > 0) |
930 | browse_map = nr_options++; | 997 | browse_map = nr_options++; |
931 | 998 | add_exit_option: | |
932 | options[nr_options++] = (char *)"Exit"; | 999 | options[nr_options++] = (char *)"Exit"; |
933 | 1000 | ||
934 | choice = ui__popup_menu(nr_options, options); | 1001 | choice = ui__popup_menu(nr_options, options); |
@@ -944,50 +1011,59 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, | |||
944 | 1011 | ||
945 | if (choice == annotate) { | 1012 | if (choice == annotate) { |
946 | struct hist_entry *he; | 1013 | struct hist_entry *he; |
1014 | int err; | ||
947 | do_annotate: | 1015 | do_annotate: |
948 | he = hist_browser__selected_entry(browser); | 1016 | he = hist_browser__selected_entry(browser); |
949 | if (he == NULL) | 1017 | if (he == NULL) |
950 | continue; | 1018 | continue; |
951 | 1019 | /* | |
952 | hist_entry__tui_annotate(he, evsel->idx); | 1020 | * Don't let this be freed, say, by hists__decay_entry. |
1021 | */ | ||
1022 | he->used = true; | ||
1023 | err = hist_entry__tui_annotate(he, evsel->idx, nr_events, | ||
1024 | timer, arg, delay_secs); | ||
1025 | he->used = false; | ||
1026 | ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); | ||
1027 | if (err) | ||
1028 | ui_browser__handle_resize(&browser->b); | ||
953 | } else if (choice == browse_map) | 1029 | } else if (choice == browse_map) |
954 | map__browse(browser->selection->map); | 1030 | map__browse(browser->selection->map); |
955 | else if (choice == zoom_dso) { | 1031 | else if (choice == zoom_dso) { |
956 | zoom_dso: | 1032 | zoom_dso: |
957 | if (dso_filter) { | 1033 | if (browser->hists->dso_filter) { |
958 | pstack__remove(fstack, &dso_filter); | 1034 | pstack__remove(fstack, &browser->hists->dso_filter); |
959 | zoom_out_dso: | 1035 | zoom_out_dso: |
960 | ui_helpline__pop(); | 1036 | ui_helpline__pop(); |
961 | dso_filter = NULL; | 1037 | browser->hists->dso_filter = NULL; |
1038 | sort_dso.elide = false; | ||
962 | } else { | 1039 | } else { |
963 | if (dso == NULL) | 1040 | if (dso == NULL) |
964 | continue; | 1041 | continue; |
965 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", | 1042 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", |
966 | dso->kernel ? "the Kernel" : dso->short_name); | 1043 | dso->kernel ? "the Kernel" : dso->short_name); |
967 | dso_filter = dso; | 1044 | browser->hists->dso_filter = dso; |
968 | pstack__push(fstack, &dso_filter); | 1045 | sort_dso.elide = true; |
1046 | pstack__push(fstack, &browser->hists->dso_filter); | ||
969 | } | 1047 | } |
970 | hists__filter_by_dso(self, dso_filter); | 1048 | hists__filter_by_dso(self); |
971 | hists__browser_title(self, msg, sizeof(msg), ev_name, | ||
972 | dso_filter, thread_filter); | ||
973 | hist_browser__reset(browser); | 1049 | hist_browser__reset(browser); |
974 | } else if (choice == zoom_thread) { | 1050 | } else if (choice == zoom_thread) { |
975 | zoom_thread: | 1051 | zoom_thread: |
976 | if (thread_filter) { | 1052 | if (browser->hists->thread_filter) { |
977 | pstack__remove(fstack, &thread_filter); | 1053 | pstack__remove(fstack, &browser->hists->thread_filter); |
978 | zoom_out_thread: | 1054 | zoom_out_thread: |
979 | ui_helpline__pop(); | 1055 | ui_helpline__pop(); |
980 | thread_filter = NULL; | 1056 | browser->hists->thread_filter = NULL; |
1057 | sort_thread.elide = false; | ||
981 | } else { | 1058 | } else { |
982 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", | 1059 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", |
983 | thread->comm_set ? thread->comm : "", | 1060 | thread->comm_set ? thread->comm : "", |
984 | thread->pid); | 1061 | thread->pid); |
985 | thread_filter = thread; | 1062 | browser->hists->thread_filter = thread; |
986 | pstack__push(fstack, &thread_filter); | 1063 | sort_thread.elide = true; |
1064 | pstack__push(fstack, &browser->hists->thread_filter); | ||
987 | } | 1065 | } |
988 | hists__filter_by_thread(self, thread_filter); | 1066 | hists__filter_by_thread(self); |
989 | hists__browser_title(self, msg, sizeof(msg), ev_name, | ||
990 | dso_filter, thread_filter); | ||
991 | hist_browser__reset(browser); | 1067 | hist_browser__reset(browser); |
992 | } | 1068 | } |
993 | } | 1069 | } |
@@ -1001,6 +1077,7 @@ out: | |||
1001 | struct perf_evsel_menu { | 1077 | struct perf_evsel_menu { |
1002 | struct ui_browser b; | 1078 | struct ui_browser b; |
1003 | struct perf_evsel *selection; | 1079 | struct perf_evsel *selection; |
1080 | bool lost_events, lost_events_warned; | ||
1004 | }; | 1081 | }; |
1005 | 1082 | ||
1006 | static void perf_evsel_menu__write(struct ui_browser *browser, | 1083 | static void perf_evsel_menu__write(struct ui_browser *browser, |
@@ -1013,22 +1090,38 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1013 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | 1090 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; |
1014 | const char *ev_name = event_name(evsel); | 1091 | const char *ev_name = event_name(evsel); |
1015 | char bf[256], unit; | 1092 | char bf[256], unit; |
1093 | const char *warn = " "; | ||
1094 | size_t printed; | ||
1016 | 1095 | ||
1017 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1096 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
1018 | HE_COLORSET_NORMAL); | 1097 | HE_COLORSET_NORMAL); |
1019 | 1098 | ||
1020 | nr_events = convert_unit(nr_events, &unit); | 1099 | nr_events = convert_unit(nr_events, &unit); |
1021 | snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | 1100 | printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, |
1022 | unit, unit == ' ' ? "" : " ", ev_name); | 1101 | unit, unit == ' ' ? "" : " ", ev_name); |
1023 | slsmg_write_nstring(bf, browser->width); | 1102 | slsmg_printf("%s", bf); |
1103 | |||
1104 | nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; | ||
1105 | if (nr_events != 0) { | ||
1106 | menu->lost_events = true; | ||
1107 | if (!current_entry) | ||
1108 | ui_browser__set_color(browser, HE_COLORSET_TOP); | ||
1109 | nr_events = convert_unit(nr_events, &unit); | ||
1110 | snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, | ||
1111 | unit, unit == ' ' ? "" : " "); | ||
1112 | warn = bf; | ||
1113 | } | ||
1114 | |||
1115 | slsmg_write_nstring(warn, browser->width - printed); | ||
1024 | 1116 | ||
1025 | if (current_entry) | 1117 | if (current_entry) |
1026 | menu->selection = evsel; | 1118 | menu->selection = evsel; |
1027 | } | 1119 | } |
1028 | 1120 | ||
1029 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) | 1121 | static int perf_evsel_menu__run(struct perf_evsel_menu *menu, |
1122 | int nr_events, const char *help, | ||
1123 | void(*timer)(void *arg), void *arg, int delay_secs) | ||
1030 | { | 1124 | { |
1031 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
1032 | struct perf_evlist *evlist = menu->b.priv; | 1125 | struct perf_evlist *evlist = menu->b.priv; |
1033 | struct perf_evsel *pos; | 1126 | struct perf_evsel *pos; |
1034 | const char *ev_name, *title = "Available samples"; | 1127 | const char *ev_name, *title = "Available samples"; |
@@ -1038,50 +1131,72 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help) | |||
1038 | "ESC: exit, ENTER|->: Browse histograms") < 0) | 1131 | "ESC: exit, ENTER|->: Browse histograms") < 0) |
1039 | return -1; | 1132 | return -1; |
1040 | 1133 | ||
1041 | ui_browser__add_exit_keys(&menu->b, exit_keys); | ||
1042 | |||
1043 | while (1) { | 1134 | while (1) { |
1044 | key = ui_browser__run(&menu->b); | 1135 | key = ui_browser__run(&menu->b, delay_secs); |
1045 | 1136 | ||
1046 | switch (key) { | 1137 | switch (key) { |
1047 | case NEWT_KEY_RIGHT: | 1138 | case K_TIMER: |
1048 | case NEWT_KEY_ENTER: | 1139 | timer(arg); |
1140 | |||
1141 | if (!menu->lost_events_warned && menu->lost_events) { | ||
1142 | ui_browser__warn_lost_events(&menu->b); | ||
1143 | menu->lost_events_warned = true; | ||
1144 | } | ||
1145 | continue; | ||
1146 | case K_RIGHT: | ||
1147 | case K_ENTER: | ||
1049 | if (!menu->selection) | 1148 | if (!menu->selection) |
1050 | continue; | 1149 | continue; |
1051 | pos = menu->selection; | 1150 | pos = menu->selection; |
1052 | browse_hists: | 1151 | browse_hists: |
1152 | perf_evlist__set_selected(evlist, pos); | ||
1153 | /* | ||
1154 | * Give the calling tool a chance to populate the non | ||
1155 | * default evsel resorted hists tree. | ||
1156 | */ | ||
1157 | if (timer) | ||
1158 | timer(arg); | ||
1053 | ev_name = event_name(pos); | 1159 | ev_name = event_name(pos); |
1054 | key = perf_evsel__hists_browse(pos, help, ev_name, true); | 1160 | key = perf_evsel__hists_browse(pos, nr_events, help, |
1161 | ev_name, true, timer, | ||
1162 | arg, delay_secs); | ||
1055 | ui_browser__show_title(&menu->b, title); | 1163 | ui_browser__show_title(&menu->b, title); |
1056 | break; | 1164 | switch (key) { |
1057 | case NEWT_KEY_LEFT: | 1165 | case K_TAB: |
1166 | if (pos->node.next == &evlist->entries) | ||
1167 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
1168 | else | ||
1169 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
1170 | goto browse_hists; | ||
1171 | case K_UNTAB: | ||
1172 | if (pos->node.prev == &evlist->entries) | ||
1173 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
1174 | else | ||
1175 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
1176 | goto browse_hists; | ||
1177 | case K_ESC: | ||
1178 | if (!ui_browser__dialog_yesno(&menu->b, | ||
1179 | "Do you really want to exit?")) | ||
1180 | continue; | ||
1181 | /* Fall thru */ | ||
1182 | case 'q': | ||
1183 | case CTRL('c'): | ||
1184 | goto out; | ||
1185 | default: | ||
1186 | continue; | ||
1187 | } | ||
1188 | case K_LEFT: | ||
1058 | continue; | 1189 | continue; |
1059 | case NEWT_KEY_ESCAPE: | 1190 | case K_ESC: |
1060 | if (!ui__dialog_yesno("Do you really want to exit?")) | 1191 | if (!ui_browser__dialog_yesno(&menu->b, |
1192 | "Do you really want to exit?")) | ||
1061 | continue; | 1193 | continue; |
1062 | /* Fall thru */ | 1194 | /* Fall thru */ |
1063 | default: | ||
1064 | goto out; | ||
1065 | } | ||
1066 | |||
1067 | switch (key) { | ||
1068 | case NEWT_KEY_TAB: | ||
1069 | if (pos->node.next == &evlist->entries) | ||
1070 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
1071 | else | ||
1072 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
1073 | goto browse_hists; | ||
1074 | case NEWT_KEY_UNTAB: | ||
1075 | if (pos->node.prev == &evlist->entries) | ||
1076 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
1077 | else | ||
1078 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
1079 | goto browse_hists; | ||
1080 | case 'q': | 1195 | case 'q': |
1081 | case CTRL('c'): | 1196 | case CTRL('c'): |
1082 | goto out; | 1197 | goto out; |
1083 | default: | 1198 | default: |
1084 | break; | 1199 | continue; |
1085 | } | 1200 | } |
1086 | } | 1201 | } |
1087 | 1202 | ||
@@ -1091,7 +1206,9 @@ out: | |||
1091 | } | 1206 | } |
1092 | 1207 | ||
1093 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | 1208 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, |
1094 | const char *help) | 1209 | const char *help, |
1210 | void(*timer)(void *arg), void *arg, | ||
1211 | int delay_secs) | ||
1095 | { | 1212 | { |
1096 | struct perf_evsel *pos; | 1213 | struct perf_evsel *pos; |
1097 | struct perf_evsel_menu menu = { | 1214 | struct perf_evsel_menu menu = { |
@@ -1121,18 +1238,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1121 | pos->name = strdup(ev_name); | 1238 | pos->name = strdup(ev_name); |
1122 | } | 1239 | } |
1123 | 1240 | ||
1124 | return perf_evsel_menu__run(&menu, help); | 1241 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, |
1242 | arg, delay_secs); | ||
1125 | } | 1243 | } |
1126 | 1244 | ||
1127 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help) | 1245 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
1246 | void(*timer)(void *arg), void *arg, | ||
1247 | int delay_secs) | ||
1128 | { | 1248 | { |
1129 | 1249 | ||
1130 | if (evlist->nr_entries == 1) { | 1250 | if (evlist->nr_entries == 1) { |
1131 | struct perf_evsel *first = list_entry(evlist->entries.next, | 1251 | struct perf_evsel *first = list_entry(evlist->entries.next, |
1132 | struct perf_evsel, node); | 1252 | struct perf_evsel, node); |
1133 | const char *ev_name = event_name(first); | 1253 | const char *ev_name = event_name(first); |
1134 | return perf_evsel__hists_browse(first, help, ev_name, false); | 1254 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, |
1255 | ev_name, false, timer, arg, | ||
1256 | delay_secs); | ||
1135 | } | 1257 | } |
1136 | 1258 | ||
1137 | return __perf_evlist__tui_browse_hists(evlist, help); | 1259 | return __perf_evlist__tui_browse_hists(evlist, help, |
1260 | timer, arg, delay_secs); | ||
1138 | } | 1261 | } |
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index 8462bffe20bc..6905bcc8be2d 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/util/ui/browsers/map.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "../libslang.h" | 1 | #include "../libslang.h" |
2 | #include <elf.h> | 2 | #include <elf.h> |
3 | #include <newt.h> | ||
3 | #include <inttypes.h> | 4 | #include <inttypes.h> |
4 | #include <sys/ttydefaults.h> | 5 | #include <sys/ttydefaults.h> |
5 | #include <ctype.h> | 6 | #include <ctype.h> |
@@ -108,11 +109,8 @@ static int map_browser__run(struct map_browser *self) | |||
108 | verbose ? "" : "restart with -v to use") < 0) | 109 | verbose ? "" : "restart with -v to use") < 0) |
109 | return -1; | 110 | return -1; |
110 | 111 | ||
111 | if (verbose) | ||
112 | ui_browser__add_exit_key(&self->b, '/'); | ||
113 | |||
114 | while (1) { | 112 | while (1) { |
115 | key = ui_browser__run(&self->b); | 113 | key = ui_browser__run(&self->b, 0); |
116 | 114 | ||
117 | if (verbose && key == '/') | 115 | if (verbose && key == '/') |
118 | map_browser__search(self); | 116 | map_browser__search(self); |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c deleted file mode 100644 index 5a06538532af..000000000000 --- a/tools/perf/util/ui/browsers/top.c +++ /dev/null | |||
@@ -1,213 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
3 | * | ||
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | ||
5 | * copyright notes. | ||
6 | * | ||
7 | * Released under the GPL v2. (and only v2, not any later version) | ||
8 | */ | ||
9 | #include "../browser.h" | ||
10 | #include "../../annotate.h" | ||
11 | #include "../helpline.h" | ||
12 | #include "../libslang.h" | ||
13 | #include "../util.h" | ||
14 | #include "../../evlist.h" | ||
15 | #include "../../hist.h" | ||
16 | #include "../../sort.h" | ||
17 | #include "../../symbol.h" | ||
18 | #include "../../top.h" | ||
19 | |||
20 | struct perf_top_browser { | ||
21 | struct ui_browser b; | ||
22 | struct rb_root root; | ||
23 | struct sym_entry *selection; | ||
24 | float sum_ksamples; | ||
25 | int dso_width; | ||
26 | int dso_short_width; | ||
27 | int sym_width; | ||
28 | }; | ||
29 | |||
30 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) | ||
31 | { | ||
32 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); | ||
33 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); | ||
34 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
35 | struct symbol *symbol = sym_entry__symbol(syme); | ||
36 | struct perf_top *top = browser->priv; | ||
37 | int width = browser->width; | ||
38 | double pcnt; | ||
39 | |||
40 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / | ||
41 | top_browser->sum_ksamples)); | ||
42 | ui_browser__set_percent_color(browser, pcnt, current_entry); | ||
43 | |||
44 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | ||
45 | slsmg_printf("%20.2f ", syme->weight); | ||
46 | width -= 24; | ||
47 | } else { | ||
48 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); | ||
49 | width -= 23; | ||
50 | } | ||
51 | |||
52 | slsmg_printf("%4.1f%%", pcnt); | ||
53 | width -= 7; | ||
54 | |||
55 | if (verbose) { | ||
56 | slsmg_printf(" %016" PRIx64, symbol->start); | ||
57 | width -= 17; | ||
58 | } | ||
59 | |||
60 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, | ||
61 | symbol->name); | ||
62 | width -= top_browser->sym_width; | ||
63 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | ||
64 | syme->map->dso->long_name : | ||
65 | syme->map->dso->short_name, width); | ||
66 | |||
67 | if (current_entry) | ||
68 | top_browser->selection = syme; | ||
69 | } | ||
70 | |||
71 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | ||
72 | { | ||
73 | struct perf_top *top = browser->b.priv; | ||
74 | u64 top_idx = browser->b.top_idx; | ||
75 | |||
76 | browser->root = RB_ROOT; | ||
77 | browser->b.top = NULL; | ||
78 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); | ||
79 | /* | ||
80 | * No active symbols | ||
81 | */ | ||
82 | if (top->rb_entries == 0) | ||
83 | return; | ||
84 | |||
85 | perf_top__find_widths(top, &browser->root, &browser->dso_width, | ||
86 | &browser->dso_short_width, | ||
87 | &browser->sym_width); | ||
88 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { | ||
89 | browser->dso_width = browser->dso_short_width; | ||
90 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) | ||
91 | browser->sym_width = browser->b.width - browser->dso_width - 29; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Adjust the ui_browser indexes since the entries in the browser->root | ||
96 | * rb_tree may have changed, then seek it from start, so that we get a | ||
97 | * possible new top of the screen. | ||
98 | */ | ||
99 | browser->b.nr_entries = top->rb_entries; | ||
100 | |||
101 | if (top_idx >= browser->b.nr_entries) { | ||
102 | if (browser->b.height >= browser->b.nr_entries) | ||
103 | top_idx = browser->b.nr_entries - browser->b.height; | ||
104 | else | ||
105 | top_idx = 0; | ||
106 | } | ||
107 | |||
108 | if (browser->b.index >= top_idx + browser->b.height) | ||
109 | browser->b.index = top_idx + browser->b.index - browser->b.top_idx; | ||
110 | |||
111 | if (browser->b.index >= browser->b.nr_entries) | ||
112 | browser->b.index = browser->b.nr_entries - 1; | ||
113 | |||
114 | browser->b.top_idx = top_idx; | ||
115 | browser->b.seek(&browser->b, top_idx, SEEK_SET); | ||
116 | } | ||
117 | |||
118 | static void perf_top_browser__annotate(struct perf_top_browser *browser) | ||
119 | { | ||
120 | struct sym_entry *syme = browser->selection; | ||
121 | struct symbol *sym = sym_entry__symbol(syme); | ||
122 | struct annotation *notes = symbol__annotation(sym); | ||
123 | struct perf_top *top = browser->b.priv; | ||
124 | |||
125 | if (notes->src != NULL) | ||
126 | goto do_annotation; | ||
127 | |||
128 | pthread_mutex_lock(¬es->lock); | ||
129 | |||
130 | top->sym_filter_entry = NULL; | ||
131 | |||
132 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { | ||
133 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
134 | sym->name); | ||
135 | pthread_mutex_unlock(¬es->lock); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | top->sym_filter_entry = syme; | ||
140 | |||
141 | pthread_mutex_unlock(¬es->lock); | ||
142 | do_annotation: | ||
143 | symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); | ||
144 | } | ||
145 | |||
146 | static int perf_top_browser__run(struct perf_top_browser *browser) | ||
147 | { | ||
148 | int key; | ||
149 | char title[160]; | ||
150 | struct perf_top *top = browser->b.priv; | ||
151 | int delay_msecs = top->delay_secs * 1000; | ||
152 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
153 | |||
154 | perf_top_browser__update_rb_tree(browser); | ||
155 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
156 | perf_top__reset_sample_counters(top); | ||
157 | |||
158 | if (ui_browser__show(&browser->b, title, | ||
159 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) | ||
160 | return -1; | ||
161 | |||
162 | newtFormSetTimer(browser->b.form, delay_msecs); | ||
163 | ui_browser__add_exit_keys(&browser->b, exit_keys); | ||
164 | |||
165 | while (1) { | ||
166 | key = ui_browser__run(&browser->b); | ||
167 | |||
168 | switch (key) { | ||
169 | case -1: | ||
170 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | ||
171 | perf_top_browser__update_rb_tree(browser); | ||
172 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
173 | perf_top__reset_sample_counters(top); | ||
174 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); | ||
175 | SLsmg_gotorc(0, 0); | ||
176 | slsmg_write_nstring(title, browser->b.width); | ||
177 | break; | ||
178 | case 'a': | ||
179 | case NEWT_KEY_RIGHT: | ||
180 | case NEWT_KEY_ENTER: | ||
181 | if (browser->selection) | ||
182 | perf_top_browser__annotate(browser); | ||
183 | break; | ||
184 | case NEWT_KEY_LEFT: | ||
185 | continue; | ||
186 | case NEWT_KEY_ESCAPE: | ||
187 | if (!ui__dialog_yesno("Do you really want to exit?")) | ||
188 | continue; | ||
189 | /* Fall thru */ | ||
190 | default: | ||
191 | goto out; | ||
192 | } | ||
193 | } | ||
194 | out: | ||
195 | ui_browser__hide(&browser->b); | ||
196 | return key; | ||
197 | } | ||
198 | |||
199 | int perf_top__tui_browser(struct perf_top *top) | ||
200 | { | ||
201 | struct perf_top_browser browser = { | ||
202 | .b = { | ||
203 | .entries = &browser.root, | ||
204 | .refresh = ui_browser__rb_tree_refresh, | ||
205 | .seek = ui_browser__rb_tree_seek, | ||
206 | .write = perf_top_browser__write, | ||
207 | .priv = top, | ||
208 | }, | ||
209 | }; | ||
210 | |||
211 | ui_helpline__push("Press <- or ESC to exit"); | ||
212 | return perf_top_browser__run(&browser); | ||
213 | } | ||
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c index f36d2ff509ed..6ef3c5691762 100644 --- a/tools/perf/util/ui/helpline.c +++ b/tools/perf/util/ui/helpline.c | |||
@@ -1,20 +1,28 @@ | |||
1 | #define _GNU_SOURCE | 1 | #define _GNU_SOURCE |
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <newt.h> | 4 | #include <string.h> |
5 | 5 | ||
6 | #include "../debug.h" | 6 | #include "../debug.h" |
7 | #include "helpline.h" | 7 | #include "helpline.h" |
8 | #include "ui.h" | 8 | #include "ui.h" |
9 | #include "libslang.h" | ||
9 | 10 | ||
10 | void ui_helpline__pop(void) | 11 | void ui_helpline__pop(void) |
11 | { | 12 | { |
12 | newtPopHelpLine(); | ||
13 | } | 13 | } |
14 | 14 | ||
15 | char ui_helpline__current[512]; | ||
16 | |||
15 | void ui_helpline__push(const char *msg) | 17 | void ui_helpline__push(const char *msg) |
16 | { | 18 | { |
17 | newtPushHelpLine(msg); | 19 | const size_t sz = sizeof(ui_helpline__current); |
20 | |||
21 | SLsmg_gotorc(SLtt_Screen_Rows - 1, 0); | ||
22 | SLsmg_set_color(0); | ||
23 | SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols); | ||
24 | SLsmg_refresh(); | ||
25 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; | ||
18 | } | 26 | } |
19 | 27 | ||
20 | void ui_helpline__vpush(const char *fmt, va_list ap) | 28 | void ui_helpline__vpush(const char *fmt, va_list ap) |
@@ -63,7 +71,7 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
63 | 71 | ||
64 | if (ui_helpline__last_msg[backlog - 1] == '\n') { | 72 | if (ui_helpline__last_msg[backlog - 1] == '\n') { |
65 | ui_helpline__puts(ui_helpline__last_msg); | 73 | ui_helpline__puts(ui_helpline__last_msg); |
66 | newtRefresh(); | 74 | SLsmg_refresh(); |
67 | backlog = 0; | 75 | backlog = 0; |
68 | } | 76 | } |
69 | pthread_mutex_unlock(&ui__lock); | 77 | pthread_mutex_unlock(&ui__lock); |
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h index ab6028d0c401..7bab6b34e35e 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/util/ui/helpline.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef _PERF_UI_HELPLINE_H_ | 1 | #ifndef _PERF_UI_HELPLINE_H_ |
2 | #define _PERF_UI_HELPLINE_H_ 1 | 2 | #define _PERF_UI_HELPLINE_H_ 1 |
3 | 3 | ||
4 | #include <stdio.h> | ||
5 | #include <stdarg.h> | ||
6 | |||
4 | void ui_helpline__init(void); | 7 | void ui_helpline__init(void); |
5 | void ui_helpline__pop(void); | 8 | void ui_helpline__pop(void); |
6 | void ui_helpline__push(const char *msg); | 9 | void ui_helpline__push(const char *msg); |
@@ -8,4 +11,6 @@ void ui_helpline__vpush(const char *fmt, va_list ap); | |||
8 | void ui_helpline__fpush(const char *fmt, ...); | 11 | void ui_helpline__fpush(const char *fmt, ...); |
9 | void ui_helpline__puts(const char *msg); | 12 | void ui_helpline__puts(const char *msg); |
10 | 13 | ||
14 | extern char ui_helpline__current[]; | ||
15 | |||
11 | #endif /* _PERF_UI_HELPLINE_H_ */ | 16 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h new file mode 100644 index 000000000000..3458b1985761 --- /dev/null +++ b/tools/perf/util/ui/keysyms.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef _PERF_KEYSYMS_H_ | ||
2 | #define _PERF_KEYSYMS_H_ 1 | ||
3 | |||
4 | #include "libslang.h" | ||
5 | |||
6 | #define K_DOWN SL_KEY_DOWN | ||
7 | #define K_END SL_KEY_END | ||
8 | #define K_ENTER '\r' | ||
9 | #define K_ESC 033 | ||
10 | #define K_F1 SL_KEY_F(1) | ||
11 | #define K_HOME SL_KEY_HOME | ||
12 | #define K_LEFT SL_KEY_LEFT | ||
13 | #define K_PGDN SL_KEY_NPAGE | ||
14 | #define K_PGUP SL_KEY_PPAGE | ||
15 | #define K_RIGHT SL_KEY_RIGHT | ||
16 | #define K_TAB '\t' | ||
17 | #define K_UNTAB SL_KEY_UNTAB | ||
18 | #define K_UP SL_KEY_UP | ||
19 | |||
20 | /* Not really keys */ | ||
21 | #define K_TIMER -1 | ||
22 | #define K_ERROR -2 | ||
23 | #define K_RESIZE -3 | ||
24 | |||
25 | #endif /* _PERF_KEYSYMS_H_ */ | ||
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h index 2b63e1c9b181..4d54b6450f5b 100644 --- a/tools/perf/util/ui/libslang.h +++ b/tools/perf/util/ui/libslang.h | |||
@@ -24,4 +24,6 @@ | |||
24 | #define sltt_set_color SLtt_set_color | 24 | #define sltt_set_color SLtt_set_color |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #define SL_KEY_UNTAB 0x1000 | ||
28 | |||
27 | #endif /* _PERF_UI_SLANG_H_ */ | 29 | #endif /* _PERF_UI_SLANG_H_ */ |
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c index d7fc399d36b3..295e366b6311 100644 --- a/tools/perf/util/ui/progress.c +++ b/tools/perf/util/ui/progress.c | |||
@@ -1,60 +1,29 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <newt.h> | ||
3 | #include "../cache.h" | 1 | #include "../cache.h" |
4 | #include "progress.h" | 2 | #include "progress.h" |
3 | #include "libslang.h" | ||
4 | #include "ui.h" | ||
5 | #include "browser.h" | ||
5 | 6 | ||
6 | struct ui_progress { | 7 | void ui_progress__update(u64 curr, u64 total, const char *title) |
7 | newtComponent form, scale; | ||
8 | }; | ||
9 | |||
10 | struct ui_progress *ui_progress__new(const char *title, u64 total) | ||
11 | { | ||
12 | struct ui_progress *self = malloc(sizeof(*self)); | ||
13 | |||
14 | if (self != NULL) { | ||
15 | int cols; | ||
16 | |||
17 | if (use_browser <= 0) | ||
18 | return self; | ||
19 | newtGetScreenSize(&cols, NULL); | ||
20 | cols -= 4; | ||
21 | newtCenteredWindow(cols, 1, title); | ||
22 | self->form = newtForm(NULL, NULL, 0); | ||
23 | if (self->form == NULL) | ||
24 | goto out_free_self; | ||
25 | self->scale = newtScale(0, 0, cols, total); | ||
26 | if (self->scale == NULL) | ||
27 | goto out_free_form; | ||
28 | newtFormAddComponent(self->form, self->scale); | ||
29 | newtRefresh(); | ||
30 | } | ||
31 | |||
32 | return self; | ||
33 | |||
34 | out_free_form: | ||
35 | newtFormDestroy(self->form); | ||
36 | out_free_self: | ||
37 | free(self); | ||
38 | return NULL; | ||
39 | } | ||
40 | |||
41 | void ui_progress__update(struct ui_progress *self, u64 curr) | ||
42 | { | 8 | { |
9 | int bar, y; | ||
43 | /* | 10 | /* |
44 | * FIXME: We should have a per UI backend way of showing progress, | 11 | * FIXME: We should have a per UI backend way of showing progress, |
45 | * stdio will just show a percentage as NN%, etc. | 12 | * stdio will just show a percentage as NN%, etc. |
46 | */ | 13 | */ |
47 | if (use_browser <= 0) | 14 | if (use_browser <= 0) |
48 | return; | 15 | return; |
49 | newtScaleSet(self->scale, curr); | ||
50 | newtRefresh(); | ||
51 | } | ||
52 | 16 | ||
53 | void ui_progress__delete(struct ui_progress *self) | 17 | ui__refresh_dimensions(true); |
54 | { | 18 | pthread_mutex_lock(&ui__lock); |
55 | if (use_browser > 0) { | 19 | y = SLtt_Screen_Rows / 2 - 2; |
56 | newtFormDestroy(self->form); | 20 | SLsmg_set_color(0); |
57 | newtPopWindow(); | 21 | SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); |
58 | } | 22 | SLsmg_gotorc(y++, 1); |
59 | free(self); | 23 | SLsmg_write_string((char *)title); |
24 | SLsmg_set_color(HE_COLORSET_SELECTED); | ||
25 | bar = ((SLtt_Screen_Cols - 2) * curr) / total; | ||
26 | SLsmg_fill_region(y, 1, 1, bar, ' '); | ||
27 | SLsmg_refresh(); | ||
28 | pthread_mutex_unlock(&ui__lock); | ||
60 | } | 29 | } |
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h index a3820a0beb5b..d9c205b59aa1 100644 --- a/tools/perf/util/ui/progress.h +++ b/tools/perf/util/ui/progress.h | |||
@@ -1,11 +1,8 @@ | |||
1 | #ifndef _PERF_UI_PROGRESS_H_ | 1 | #ifndef _PERF_UI_PROGRESS_H_ |
2 | #define _PERF_UI_PROGRESS_H_ 1 | 2 | #define _PERF_UI_PROGRESS_H_ 1 |
3 | 3 | ||
4 | struct ui_progress; | 4 | #include <../types.h> |
5 | 5 | ||
6 | struct ui_progress *ui_progress__new(const char *title, u64 total); | 6 | void ui_progress__update(u64 curr, u64 total, const char *title); |
7 | void ui_progress__delete(struct ui_progress *self); | ||
8 | |||
9 | void ui_progress__update(struct ui_progress *self, u64 curr); | ||
10 | 7 | ||
11 | #endif | 8 | #endif |
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c index ee46d671db59..85a69faa09aa 100644 --- a/tools/perf/util/ui/setup.c +++ b/tools/perf/util/ui/setup.c | |||
@@ -7,9 +7,85 @@ | |||
7 | #include "browser.h" | 7 | #include "browser.h" |
8 | #include "helpline.h" | 8 | #include "helpline.h" |
9 | #include "ui.h" | 9 | #include "ui.h" |
10 | #include "util.h" | ||
11 | #include "libslang.h" | ||
12 | #include "keysyms.h" | ||
10 | 13 | ||
11 | pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | 14 | pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; |
12 | 15 | ||
16 | static volatile int ui__need_resize; | ||
17 | |||
18 | void ui__refresh_dimensions(bool force) | ||
19 | { | ||
20 | if (force || ui__need_resize) { | ||
21 | ui__need_resize = 0; | ||
22 | pthread_mutex_lock(&ui__lock); | ||
23 | SLtt_get_screen_size(); | ||
24 | SLsmg_reinit_smg(); | ||
25 | pthread_mutex_unlock(&ui__lock); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | static void ui__sigwinch(int sig __used) | ||
30 | { | ||
31 | ui__need_resize = 1; | ||
32 | } | ||
33 | |||
34 | static void ui__setup_sigwinch(void) | ||
35 | { | ||
36 | static bool done; | ||
37 | |||
38 | if (done) | ||
39 | return; | ||
40 | |||
41 | done = true; | ||
42 | pthread__unblock_sigwinch(); | ||
43 | signal(SIGWINCH, ui__sigwinch); | ||
44 | } | ||
45 | |||
46 | int ui__getch(int delay_secs) | ||
47 | { | ||
48 | struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; | ||
49 | fd_set read_set; | ||
50 | int err, key; | ||
51 | |||
52 | ui__setup_sigwinch(); | ||
53 | |||
54 | FD_ZERO(&read_set); | ||
55 | FD_SET(0, &read_set); | ||
56 | |||
57 | if (delay_secs) { | ||
58 | timeout.tv_sec = delay_secs; | ||
59 | timeout.tv_usec = 0; | ||
60 | } | ||
61 | |||
62 | err = select(1, &read_set, NULL, NULL, ptimeout); | ||
63 | |||
64 | if (err == 0) | ||
65 | return K_TIMER; | ||
66 | |||
67 | if (err == -1) { | ||
68 | if (errno == EINTR) | ||
69 | return K_RESIZE; | ||
70 | return K_ERROR; | ||
71 | } | ||
72 | |||
73 | key = SLang_getkey(); | ||
74 | if (key != K_ESC) | ||
75 | return key; | ||
76 | |||
77 | FD_ZERO(&read_set); | ||
78 | FD_SET(0, &read_set); | ||
79 | timeout.tv_sec = 0; | ||
80 | timeout.tv_usec = 20; | ||
81 | err = select(1, &read_set, NULL, NULL, &timeout); | ||
82 | if (err == 0) | ||
83 | return K_ESC; | ||
84 | |||
85 | SLang_ungetkey(key); | ||
86 | return SLkp_getkey(); | ||
87 | } | ||
88 | |||
13 | static void newt_suspend(void *d __used) | 89 | static void newt_suspend(void *d __used) |
14 | { | 90 | { |
15 | newtSuspend(); | 91 | newtSuspend(); |
@@ -17,6 +93,33 @@ static void newt_suspend(void *d __used) | |||
17 | newtResume(); | 93 | newtResume(); |
18 | } | 94 | } |
19 | 95 | ||
96 | static int ui__init(void) | ||
97 | { | ||
98 | int err = SLkp_init(); | ||
99 | |||
100 | if (err < 0) | ||
101 | goto out; | ||
102 | |||
103 | SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); | ||
104 | out: | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | static void ui__exit(void) | ||
109 | { | ||
110 | SLtt_set_cursor_visibility(1); | ||
111 | SLsmg_refresh(); | ||
112 | SLsmg_reset_smg(); | ||
113 | SLang_reset_tty(); | ||
114 | } | ||
115 | |||
116 | static void ui__signal(int sig) | ||
117 | { | ||
118 | ui__exit(); | ||
119 | psignal(sig, "perf"); | ||
120 | exit(0); | ||
121 | } | ||
122 | |||
20 | void setup_browser(bool fallback_to_pager) | 123 | void setup_browser(bool fallback_to_pager) |
21 | { | 124 | { |
22 | if (!isatty(1) || !use_browser || dump_trace) { | 125 | if (!isatty(1) || !use_browser || dump_trace) { |
@@ -28,19 +131,25 @@ void setup_browser(bool fallback_to_pager) | |||
28 | 131 | ||
29 | use_browser = 1; | 132 | use_browser = 1; |
30 | newtInit(); | 133 | newtInit(); |
31 | newtCls(); | 134 | ui__init(); |
32 | newtSetSuspendCallback(newt_suspend, NULL); | 135 | newtSetSuspendCallback(newt_suspend, NULL); |
33 | ui_helpline__init(); | 136 | ui_helpline__init(); |
34 | ui_browser__init(); | 137 | ui_browser__init(); |
138 | |||
139 | signal(SIGSEGV, ui__signal); | ||
140 | signal(SIGFPE, ui__signal); | ||
141 | signal(SIGINT, ui__signal); | ||
142 | signal(SIGQUIT, ui__signal); | ||
143 | signal(SIGTERM, ui__signal); | ||
35 | } | 144 | } |
36 | 145 | ||
37 | void exit_browser(bool wait_for_ok) | 146 | void exit_browser(bool wait_for_ok) |
38 | { | 147 | { |
39 | if (use_browser > 0) { | 148 | if (use_browser > 0) { |
40 | if (wait_for_ok) { | 149 | if (wait_for_ok) |
41 | char title[] = "Fatal Error", ok[] = "Ok"; | 150 | ui__question_window("Fatal Error", |
42 | newtWinMessage(title, ok, ui_helpline__last_msg); | 151 | ui_helpline__last_msg, |
43 | } | 152 | "Press any key...", 0); |
44 | newtFinished(); | 153 | ui__exit(); |
45 | } | 154 | } |
46 | } | 155 | } |
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h index d264e059c829..7b67045479f6 100644 --- a/tools/perf/util/ui/ui.h +++ b/tools/perf/util/ui/ui.h | |||
@@ -2,7 +2,10 @@ | |||
2 | #define _PERF_UI_H_ 1 | 2 | #define _PERF_UI_H_ 1 |
3 | 3 | ||
4 | #include <pthread.h> | 4 | #include <pthread.h> |
5 | #include <stdbool.h> | ||
5 | 6 | ||
6 | extern pthread_mutex_t ui__lock; | 7 | extern pthread_mutex_t ui__lock; |
7 | 8 | ||
9 | void ui__refresh_dimensions(bool force); | ||
10 | |||
8 | #endif /* _PERF_UI_H_ */ | 11 | #endif /* _PERF_UI_H_ */ |
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c index fdf1fc8f08bc..45daa7c41dad 100644 --- a/tools/perf/util/ui/util.c +++ b/tools/perf/util/ui/util.c | |||
@@ -1,6 +1,5 @@ | |||
1 | #include <newt.h> | 1 | #include "../util.h" |
2 | #include <signal.h> | 2 | #include <signal.h> |
3 | #include <stdio.h> | ||
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
5 | #include <string.h> | 4 | #include <string.h> |
6 | #include <sys/ttydefaults.h> | 5 | #include <sys/ttydefaults.h> |
@@ -8,72 +7,75 @@ | |||
8 | #include "../cache.h" | 7 | #include "../cache.h" |
9 | #include "../debug.h" | 8 | #include "../debug.h" |
10 | #include "browser.h" | 9 | #include "browser.h" |
10 | #include "keysyms.h" | ||
11 | #include "helpline.h" | 11 | #include "helpline.h" |
12 | #include "ui.h" | 12 | #include "ui.h" |
13 | #include "util.h" | 13 | #include "util.h" |
14 | #include "libslang.h" | ||
14 | 15 | ||
15 | static void newt_form__set_exit_keys(newtComponent self) | 16 | static void ui_browser__argv_write(struct ui_browser *browser, |
17 | void *entry, int row) | ||
16 | { | 18 | { |
17 | newtFormAddHotKey(self, NEWT_KEY_LEFT); | 19 | char **arg = entry; |
18 | newtFormAddHotKey(self, NEWT_KEY_ESCAPE); | 20 | bool current_entry = ui_browser__is_current_entry(browser, row); |
19 | newtFormAddHotKey(self, 'Q'); | ||
20 | newtFormAddHotKey(self, 'q'); | ||
21 | newtFormAddHotKey(self, CTRL('c')); | ||
22 | } | ||
23 | 21 | ||
24 | static newtComponent newt_form__new(void) | 22 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
25 | { | 23 | HE_COLORSET_NORMAL); |
26 | newtComponent self = newtForm(NULL, NULL, 0); | 24 | slsmg_write_nstring(*arg, browser->width); |
27 | if (self) | ||
28 | newt_form__set_exit_keys(self); | ||
29 | return self; | ||
30 | } | 25 | } |
31 | 26 | ||
32 | int ui__popup_menu(int argc, char * const argv[]) | 27 | static int popup_menu__run(struct ui_browser *menu) |
33 | { | 28 | { |
34 | struct newtExitStruct es; | 29 | int key; |
35 | int i, rc = -1, max_len = 5; | ||
36 | newtComponent listbox, form = newt_form__new(); | ||
37 | 30 | ||
38 | if (form == NULL) | 31 | if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) |
39 | return -1; | 32 | return -1; |
40 | 33 | ||
41 | listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT); | 34 | while (1) { |
42 | if (listbox == NULL) | 35 | key = ui_browser__run(menu, 0); |
43 | goto out_destroy_form; | ||
44 | 36 | ||
45 | newtFormAddComponent(form, listbox); | 37 | switch (key) { |
38 | case K_RIGHT: | ||
39 | case K_ENTER: | ||
40 | key = menu->index; | ||
41 | break; | ||
42 | case K_LEFT: | ||
43 | case K_ESC: | ||
44 | case 'q': | ||
45 | case CTRL('c'): | ||
46 | key = -1; | ||
47 | break; | ||
48 | default: | ||
49 | continue; | ||
50 | } | ||
46 | 51 | ||
47 | for (i = 0; i < argc; ++i) { | 52 | break; |
48 | int len = strlen(argv[i]); | ||
49 | if (len > max_len) | ||
50 | max_len = len; | ||
51 | if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i)) | ||
52 | goto out_destroy_form; | ||
53 | } | 53 | } |
54 | 54 | ||
55 | newtCenteredWindow(max_len, argc, NULL); | 55 | ui_browser__hide(menu); |
56 | newtFormRun(form, &es); | 56 | return key; |
57 | rc = newtListboxGetCurrent(listbox) - NULL; | ||
58 | if (es.reason == NEWT_EXIT_HOTKEY) | ||
59 | rc = -1; | ||
60 | newtPopWindow(); | ||
61 | out_destroy_form: | ||
62 | newtFormDestroy(form); | ||
63 | return rc; | ||
64 | } | 57 | } |
65 | 58 | ||
66 | int ui__help_window(const char *text) | 59 | int ui__popup_menu(int argc, char * const argv[]) |
67 | { | 60 | { |
68 | struct newtExitStruct es; | 61 | struct ui_browser menu = { |
69 | newtComponent tb, form = newt_form__new(); | 62 | .entries = (void *)argv, |
70 | int rc = -1; | 63 | .refresh = ui_browser__argv_refresh, |
64 | .seek = ui_browser__argv_seek, | ||
65 | .write = ui_browser__argv_write, | ||
66 | .nr_entries = argc, | ||
67 | }; | ||
68 | |||
69 | return popup_menu__run(&menu); | ||
70 | } | ||
71 | |||
72 | int ui__question_window(const char *title, const char *text, | ||
73 | const char *exit_msg, int delay_secs) | ||
74 | { | ||
75 | int x, y; | ||
71 | int max_len = 0, nr_lines = 0; | 76 | int max_len = 0, nr_lines = 0; |
72 | const char *t; | 77 | const char *t; |
73 | 78 | ||
74 | if (form == NULL) | ||
75 | return -1; | ||
76 | |||
77 | t = text; | 79 | t = text; |
78 | while (1) { | 80 | while (1) { |
79 | const char *sep = strchr(t, '\n'); | 81 | const char *sep = strchr(t, '\n'); |
@@ -90,41 +92,77 @@ int ui__help_window(const char *text) | |||
90 | t = sep + 1; | 92 | t = sep + 1; |
91 | } | 93 | } |
92 | 94 | ||
93 | tb = newtTextbox(0, 0, max_len, nr_lines, 0); | 95 | max_len += 2; |
94 | if (tb == NULL) | 96 | nr_lines += 4; |
95 | goto out_destroy_form; | 97 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, |
96 | 98 | x = SLtt_Screen_Cols / 2 - max_len / 2; | |
97 | newtTextboxSetText(tb, text); | 99 | |
98 | newtFormAddComponent(form, tb); | 100 | SLsmg_set_color(0); |
99 | newtCenteredWindow(max_len, nr_lines, NULL); | 101 | SLsmg_draw_box(y, x++, nr_lines, max_len); |
100 | newtFormRun(form, &es); | 102 | if (title) { |
101 | newtPopWindow(); | 103 | SLsmg_gotorc(y, x + 1); |
102 | rc = 0; | 104 | SLsmg_write_string((char *)title); |
103 | out_destroy_form: | 105 | } |
104 | newtFormDestroy(form); | 106 | SLsmg_gotorc(++y, x); |
105 | return rc; | 107 | nr_lines -= 2; |
108 | max_len -= 2; | ||
109 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
110 | nr_lines, max_len, 1); | ||
111 | SLsmg_gotorc(y + nr_lines - 2, x); | ||
112 | SLsmg_write_nstring((char *)" ", max_len); | ||
113 | SLsmg_gotorc(y + nr_lines - 1, x); | ||
114 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
115 | SLsmg_refresh(); | ||
116 | return ui__getch(delay_secs); | ||
106 | } | 117 | } |
107 | 118 | ||
108 | static const char yes[] = "Yes", no[] = "No", | 119 | int ui__help_window(const char *text) |
109 | warning_str[] = "Warning!", ok[] = "Ok"; | 120 | { |
121 | return ui__question_window("Help", text, "Press any key...", 0); | ||
122 | } | ||
110 | 123 | ||
111 | bool ui__dialog_yesno(const char *msg) | 124 | int ui__dialog_yesno(const char *msg) |
112 | { | 125 | { |
113 | /* newtWinChoice should really be accepting const char pointers... */ | 126 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); |
114 | return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1; | ||
115 | } | 127 | } |
116 | 128 | ||
117 | void ui__warning(const char *format, ...) | 129 | int __ui__warning(const char *title, const char *format, va_list args) |
118 | { | 130 | { |
119 | va_list args; | 131 | char *s; |
132 | |||
133 | if (use_browser > 0 && vasprintf(&s, format, args) > 0) { | ||
134 | int key; | ||
120 | 135 | ||
121 | va_start(args, format); | ||
122 | if (use_browser > 0) { | ||
123 | pthread_mutex_lock(&ui__lock); | 136 | pthread_mutex_lock(&ui__lock); |
124 | newtWinMessagev((char *)warning_str, (char *)ok, | 137 | key = ui__question_window(title, s, "Press any key...", 0); |
125 | (char *)format, args); | ||
126 | pthread_mutex_unlock(&ui__lock); | 138 | pthread_mutex_unlock(&ui__lock); |
127 | } else | 139 | free(s); |
128 | vfprintf(stderr, format, args); | 140 | return key; |
141 | } | ||
142 | |||
143 | fprintf(stderr, "%s:\n", title); | ||
144 | vfprintf(stderr, format, args); | ||
145 | return K_ESC; | ||
146 | } | ||
147 | |||
148 | int ui__warning(const char *format, ...) | ||
149 | { | ||
150 | int key; | ||
151 | va_list args; | ||
152 | |||
153 | va_start(args, format); | ||
154 | key = __ui__warning("Warning", format, args); | ||
155 | va_end(args); | ||
156 | return key; | ||
157 | } | ||
158 | |||
159 | int ui__error(const char *format, ...) | ||
160 | { | ||
161 | int key; | ||
162 | va_list args; | ||
163 | |||
164 | va_start(args, format); | ||
165 | key = __ui__warning("Error", format, args); | ||
129 | va_end(args); | 166 | va_end(args); |
167 | return key; | ||
130 | } | 168 | } |
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h index afcbc1d99531..2d1738bd71c8 100644 --- a/tools/perf/util/ui/util.h +++ b/tools/perf/util/ui/util.h | |||
@@ -1,10 +1,14 @@ | |||
1 | #ifndef _PERF_UI_UTIL_H_ | 1 | #ifndef _PERF_UI_UTIL_H_ |
2 | #define _PERF_UI_UTIL_H_ 1 | 2 | #define _PERF_UI_UTIL_H_ 1 |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdarg.h> |
5 | 5 | ||
6 | int ui__getch(int delay_secs); | ||
6 | int ui__popup_menu(int argc, char * const argv[]); | 7 | int ui__popup_menu(int argc, char * const argv[]); |
7 | int ui__help_window(const char *text); | 8 | int ui__help_window(const char *text); |
8 | bool ui__dialog_yesno(const char *msg); | 9 | int ui__dialog_yesno(const char *msg); |
10 | int ui__question_window(const char *title, const char *text, | ||
11 | const char *exit_msg, int delay_secs); | ||
12 | int __ui__warning(const char *title, const char *format, va_list args); | ||
9 | 13 | ||
10 | #endif /* _PERF_UI_UTIL_H_ */ | 14 | #endif /* _PERF_UI_UTIL_H_ */ |
diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore new file mode 100644 index 000000000000..8a83dd2ffc11 --- /dev/null +++ b/tools/power/cpupower/.gitignore | |||
@@ -0,0 +1,22 @@ | |||
1 | .libs | ||
2 | libcpupower.so | ||
3 | libcpupower.so.0 | ||
4 | libcpupower.so.0.0.0 | ||
5 | build/ccdv | ||
6 | cpufreq-info | ||
7 | cpufreq-set | ||
8 | cpufreq-aperf | ||
9 | lib/.libs | ||
10 | lib/cpufreq.lo | ||
11 | lib/cpufreq.o | ||
12 | lib/proc.lo | ||
13 | lib/proc.o | ||
14 | lib/sysfs.lo | ||
15 | lib/sysfs.o | ||
16 | po/cpupowerutils.pot | ||
17 | po/*.gmo | ||
18 | utils/cpufreq-info.o | ||
19 | utils/cpufreq-set.o | ||
20 | utils/cpufreq-aperf.o | ||
21 | cpupower | ||
22 | bench/cpufreq-bench | ||
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile new file mode 100644 index 000000000000..e8a03aceceb1 --- /dev/null +++ b/tools/power/cpupower/Makefile | |||
@@ -0,0 +1,280 @@ | |||
1 | # Makefile for cpupower | ||
2 | # | ||
3 | # Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net> | ||
4 | # | ||
5 | # Based largely on the Makefile for udev by: | ||
6 | # | ||
7 | # Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License as published by | ||
11 | # the Free Software Foundation; version 2 of the License. | ||
12 | # | ||
13 | # This program is distributed in the hope that it will be useful, | ||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | # General Public License for more details. | ||
17 | # | ||
18 | # You should have received a copy of the GNU General Public License | ||
19 | # along with this program; if not, write to the Free Software | ||
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | # | ||
22 | |||
23 | # --- CONFIGURATION BEGIN --- | ||
24 | |||
25 | # Set the following to `true' to make a unstripped, unoptimized | ||
26 | # binary. Leave this set to `false' for production use. | ||
27 | DEBUG ?= true | ||
28 | |||
29 | # make the build silent. Set this to something else to make it noisy again. | ||
30 | V ?= false | ||
31 | |||
32 | # Internationalization support (output in different languages). | ||
33 | # Requires gettext. | ||
34 | NLS ?= true | ||
35 | |||
36 | # Set the following to 'true' to build/install the | ||
37 | # cpufreq-bench benchmarking tool | ||
38 | CPUFREQ_BENCH ?= true | ||
39 | |||
40 | # Prefix to the directories we're installing to | ||
41 | DESTDIR ?= | ||
42 | |||
43 | # --- CONFIGURATION END --- | ||
44 | |||
45 | |||
46 | |||
47 | # Package-related definitions. Distributions can modify the version | ||
48 | # and _should_ modify the PACKAGE_BUGREPORT definition | ||
49 | |||
50 | VERSION= $(shell ./utils/version-gen.sh) | ||
51 | LIB_MAJ= 0.0.0 | ||
52 | LIB_MIN= 0 | ||
53 | |||
54 | PACKAGE = cpupower | ||
55 | PACKAGE_BUGREPORT = cpufreq@vger.kernel.org | ||
56 | LANGUAGES = de fr it cs pt | ||
57 | |||
58 | |||
59 | # Directory definitions. These are default and most probably | ||
60 | # do not need to be changed. Please note that DESTDIR is | ||
61 | # added in front of any of them | ||
62 | |||
63 | bindir ?= /usr/bin | ||
64 | sbindir ?= /usr/sbin | ||
65 | mandir ?= /usr/man | ||
66 | includedir ?= /usr/include | ||
67 | libdir ?= /usr/lib | ||
68 | localedir ?= /usr/share/locale | ||
69 | docdir ?= /usr/share/doc/packages/cpupower | ||
70 | confdir ?= /etc/ | ||
71 | |||
72 | # Toolchain: what tools do we use, and what options do they need: | ||
73 | |||
74 | CP = cp -fpR | ||
75 | INSTALL = /usr/bin/install -c | ||
76 | INSTALL_PROGRAM = ${INSTALL} | ||
77 | INSTALL_DATA = ${INSTALL} -m 644 | ||
78 | INSTALL_SCRIPT = ${INSTALL_PROGRAM} | ||
79 | |||
80 | # If you are running a cross compiler, you may want to set this | ||
81 | # to something more interesting, like "arm-linux-". If you want | ||
82 | # to compile vs uClibc, that can be done here as well. | ||
83 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- | ||
84 | CC = $(CROSS)gcc | ||
85 | LD = $(CROSS)gcc | ||
86 | AR = $(CROSS)ar | ||
87 | STRIP = $(CROSS)strip | ||
88 | RANLIB = $(CROSS)ranlib | ||
89 | HOSTCC = gcc | ||
90 | |||
91 | |||
92 | # Now we set up the build system | ||
93 | # | ||
94 | |||
95 | # set up PWD so that older versions of make will work with our build. | ||
96 | PWD = $(shell pwd) | ||
97 | |||
98 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;} | ||
99 | |||
100 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | ||
101 | |||
102 | # check if compiler option is supported | ||
103 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | ||
104 | |||
105 | # use '-Os' optimization if available, else use -O2 | ||
106 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | ||
107 | |||
108 | WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare | ||
109 | WARNINGS += $(call cc-supports,-Wno-pointer-sign) | ||
110 | WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) | ||
111 | WARNINGS += -Wshadow | ||
112 | |||
113 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ | ||
114 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE | ||
115 | |||
116 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ | ||
117 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ | ||
118 | utils/helpers/pci.o utils/helpers/bitmask.o \ | ||
119 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ | ||
120 | utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ | ||
121 | utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ | ||
122 | utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ | ||
123 | utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o | ||
124 | |||
125 | UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ | ||
126 | utils/helpers/bitmask.h \ | ||
127 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def | ||
128 | |||
129 | UTIL_SRC := $(UTIL_OBJS:.o=.c) | ||
130 | |||
131 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h | ||
132 | LIB_SRC = lib/cpufreq.c lib/sysfs.c | ||
133 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o | ||
134 | |||
135 | CFLAGS += -pipe | ||
136 | |||
137 | ifeq ($(strip $(NLS)),true) | ||
138 | INSTALL_NLS += install-gmo | ||
139 | COMPILE_NLS += create-gmo | ||
140 | CFLAGS += -DNLS | ||
141 | endif | ||
142 | |||
143 | ifeq ($(strip $(CPUFREQ_BENCH)),true) | ||
144 | INSTALL_BENCH += install-bench | ||
145 | COMPILE_BENCH += compile-bench | ||
146 | endif | ||
147 | |||
148 | CFLAGS += $(WARNINGS) | ||
149 | |||
150 | ifeq ($(strip $(V)),false) | ||
151 | QUIET=@ | ||
152 | ECHO=@echo | ||
153 | else | ||
154 | QUIET= | ||
155 | ECHO=@\# | ||
156 | endif | ||
157 | export QUIET ECHO | ||
158 | |||
159 | # if DEBUG is enabled, then we do not strip or optimize | ||
160 | ifeq ($(strip $(DEBUG)),true) | ||
161 | CFLAGS += -O1 -g -DDEBUG | ||
162 | STRIPCMD = /bin/true -Since_we_are_debugging | ||
163 | else | ||
164 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | ||
165 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | ||
166 | endif | ||
167 | |||
168 | |||
169 | # the actual make rules | ||
170 | |||
171 | all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH) | ||
172 | |||
173 | lib/%.o: $(LIB_SRC) $(LIB_HEADERS) | ||
174 | $(ECHO) " CC " $@ | ||
175 | $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c | ||
176 | |||
177 | libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) | ||
178 | $(ECHO) " LD " $@ | ||
179 | $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ | ||
180 | -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) | ||
181 | @ln -sf $@ libcpupower.so | ||
182 | @ln -sf $@ libcpupower.so.$(LIB_MIN) | ||
183 | |||
184 | libcpupower: libcpupower.so.$(LIB_MAJ) | ||
185 | |||
186 | # Let all .o files depend on its .c file and all headers | ||
187 | # Might be worth to put this into utils/Makefile at some point of time | ||
188 | $(UTIL_OBJS): $(UTIL_HEADERS) | ||
189 | |||
190 | .c.o: | ||
191 | $(ECHO) " CC " $@ | ||
192 | $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c | ||
193 | |||
194 | cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ) | ||
195 | $(ECHO) " CC " $@ | ||
196 | $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS) | ||
197 | $(QUIET) $(STRIPCMD) $@ | ||
198 | |||
199 | po/$(PACKAGE).pot: $(UTIL_SRC) | ||
200 | $(ECHO) " GETTEXT " $@ | ||
201 | $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ | ||
202 | --keyword=_ --keyword=N_ $(UTIL_SRC) && \ | ||
203 | test -f $(PACKAGE).po && \ | ||
204 | mv -f $(PACKAGE).po po/$(PACKAGE).pot | ||
205 | |||
206 | po/%.gmo: po/%.po | ||
207 | $(ECHO) " MSGFMT " $@ | ||
208 | $(QUIET) msgfmt -o $@ po/$*.po | ||
209 | |||
210 | create-gmo: ${GMO_FILES} | ||
211 | |||
212 | update-po: po/$(PACKAGE).pot | ||
213 | $(ECHO) " MSGMRG " $@ | ||
214 | $(QUIET) @for HLANG in $(LANGUAGES); do \ | ||
215 | echo -n "Updating $$HLANG "; \ | ||
216 | if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \ | ||
217 | po/$$HLANG.new.po; then \ | ||
218 | mv -f po/$$HLANG.new.po po/$$HLANG.po; \ | ||
219 | else \ | ||
220 | echo "msgmerge for $$HLANG failed!"; \ | ||
221 | rm -f po/$$HLANG.new.po; \ | ||
222 | fi; \ | ||
223 | done; | ||
224 | |||
225 | compile-bench: libcpupower.so.$(LIB_MAJ) | ||
226 | @V=$(V) confdir=$(confdir) $(MAKE) -C bench | ||
227 | |||
228 | clean: | ||
229 | -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | ||
230 | | xargs rm -f | ||
231 | -rm -f $(UTIL_BINS) | ||
232 | -rm -f $(IDLE_OBJS) | ||
233 | -rm -f cpupower | ||
234 | -rm -f libcpupower.so* | ||
235 | -rm -rf po/*.gmo po/*.pot | ||
236 | $(MAKE) -C bench clean | ||
237 | |||
238 | |||
239 | install-lib: | ||
240 | $(INSTALL) -d $(DESTDIR)${libdir} | ||
241 | $(CP) libcpupower.so* $(DESTDIR)${libdir}/ | ||
242 | $(INSTALL) -d $(DESTDIR)${includedir} | ||
243 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h | ||
244 | |||
245 | install-tools: | ||
246 | $(INSTALL) -d $(DESTDIR)${bindir} | ||
247 | $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir} | ||
248 | |||
249 | install-man: | ||
250 | $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 | ||
251 | $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 | ||
252 | $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 | ||
253 | $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 | ||
254 | $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 | ||
255 | $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 | ||
256 | |||
257 | install-gmo: | ||
258 | $(INSTALL) -d $(DESTDIR)${localedir} | ||
259 | for HLANG in $(LANGUAGES); do \ | ||
260 | echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ | ||
261 | $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ | ||
262 | done; | ||
263 | |||
264 | install-bench: | ||
265 | @#DESTDIR must be set from outside to survive | ||
266 | @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install | ||
267 | |||
268 | install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) | ||
269 | |||
270 | uninstall: | ||
271 | - rm -f $(DESTDIR)${libdir}/libcpupower.* | ||
272 | - rm -f $(DESTDIR)${includedir}/cpufreq.h | ||
273 | - rm -f $(DESTDIR)${bindir}/utils/cpupower | ||
274 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1 | ||
275 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1 | ||
276 | - for HLANG in $(LANGUAGES); do \ | ||
277 | rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ | ||
278 | done; | ||
279 | |||
280 | .PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean | ||
diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README new file mode 100644 index 000000000000..fd9d4c0d6688 --- /dev/null +++ b/tools/power/cpupower/README | |||
@@ -0,0 +1,49 @@ | |||
1 | The cpufrequtils package (homepage: | ||
2 | http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html ) | ||
3 | consists of the following elements: | ||
4 | |||
5 | requirements | ||
6 | ------------ | ||
7 | |||
8 | On x86 pciutils is needed at runtime (-lpci). | ||
9 | For compilation pciutils-devel (pci/pci.h) and a gcc version | ||
10 | providing cpuid.h is needed. | ||
11 | For both it's not explicitly checked for (yet). | ||
12 | |||
13 | |||
14 | libcpufreq | ||
15 | ---------- | ||
16 | |||
17 | "libcpufreq" is a library which offers a unified access method for userspace | ||
18 | tools and programs to the cpufreq core and drivers in the Linux kernel. This | ||
19 | allows for code reduction in userspace tools, a clean implementation of | ||
20 | the interaction to the cpufreq core, and support for both the sysfs and proc | ||
21 | interfaces [depending on configuration, see below]. | ||
22 | |||
23 | |||
24 | compilation and installation | ||
25 | ---------------------------- | ||
26 | |||
27 | make | ||
28 | su | ||
29 | make install | ||
30 | |||
31 | should suffice on most systems. It builds default libcpufreq, | ||
32 | cpufreq-set and cpufreq-info files and installs them in /usr/lib and | ||
33 | /usr/bin, respectively. If you want to set up the paths differently and/or | ||
34 | want to configure the package to your specific needs, you need to open | ||
35 | "Makefile" with an editor of your choice and edit the block marked | ||
36 | CONFIGURATION. | ||
37 | |||
38 | |||
39 | THANKS | ||
40 | ------ | ||
41 | Many thanks to Mattia Dongili who wrote the autotoolization and | ||
42 | libtoolization, the manpages and the italian language file for cpufrequtils; | ||
43 | to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his | ||
44 | powernow-k8-decode and intel_gsic tools as well as the french language file; | ||
45 | and to various others commenting on the previous (pre-)releases of | ||
46 | cpufrequtils. | ||
47 | |||
48 | |||
49 | Dominik Brodowski | ||
diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo new file mode 100644 index 000000000000..874b78b586ee --- /dev/null +++ b/tools/power/cpupower/ToDo | |||
@@ -0,0 +1,11 @@ | |||
1 | ToDos sorted by priority: | ||
2 | |||
3 | - Use bitmask functions to parse CPU topology more robust | ||
4 | (current implementation has issues on AMD) | ||
5 | - Try to read out boost states and frequencies on Intel | ||
6 | - Adjust README | ||
7 | - Somewhere saw the ability to read power consumption of | ||
8 | RAM from HW on Intel SandyBridge -> another monitor? | ||
9 | - Add another c1e debug idle monitor | ||
10 | -> Is by design racy with BIOS, but could be added | ||
11 | with a --force option and some "be careful" messages | ||
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile new file mode 100644 index 000000000000..2b67606fc3e3 --- /dev/null +++ b/tools/power/cpupower/bench/Makefile | |||
@@ -0,0 +1,29 @@ | |||
1 | LIBS = -L../ -lm -lcpupower | ||
2 | |||
3 | OBJS = main.o parse.o system.o benchmark.o | ||
4 | CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" | ||
5 | |||
6 | %.o : %.c | ||
7 | $(ECHO) " CC " $@ | ||
8 | $(QUIET) $(CC) -c $(CFLAGS) $< -o $@ | ||
9 | |||
10 | cpufreq-bench: $(OBJS) | ||
11 | $(ECHO) " CC " $@ | ||
12 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) | ||
13 | |||
14 | all: cpufreq-bench | ||
15 | |||
16 | install: | ||
17 | mkdir -p $(DESTDIR)/$(sbindir) | ||
18 | mkdir -p $(DESTDIR)/$(bindir) | ||
19 | mkdir -p $(DESTDIR)/$(docdir) | ||
20 | mkdir -p $(DESTDIR)/$(confdir) | ||
21 | install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench | ||
22 | install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh | ||
23 | install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH | ||
24 | install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh | ||
25 | install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf | ||
26 | |||
27 | clean: | ||
28 | rm -f *.o | ||
29 | rm -f cpufreq-bench | ||
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH new file mode 100644 index 000000000000..8093ec738170 --- /dev/null +++ b/tools/power/cpupower/bench/README-BENCH | |||
@@ -0,0 +1,124 @@ | |||
1 | This is cpufreq-bench, a microbenchmark for the cpufreq framework. | ||
2 | |||
3 | Purpose | ||
4 | ======= | ||
5 | |||
6 | What is this benchmark for: | ||
7 | - Identify worst case performance loss when doing dynamic frequency | ||
8 | scaling using Linux kernel governors | ||
9 | - Identify average reaction time of a governor to CPU load changes | ||
10 | - (Stress) Testing whether a cpufreq low level driver or governor works | ||
11 | as expected | ||
12 | - Identify cpufreq related performance regressions between kernels | ||
13 | - Possibly Real time priority testing? -> what happens if there are | ||
14 | processes with a higher prio than the governor's kernel thread | ||
15 | - ... | ||
16 | |||
17 | What this benchmark does *not* cover: | ||
18 | - Power saving related regressions (In fact as better the performance | ||
19 | throughput is, the worse the power savings will be, but the first should | ||
20 | mostly count more...) | ||
21 | - Real world (workloads) | ||
22 | |||
23 | |||
24 | Description | ||
25 | =========== | ||
26 | |||
27 | cpufreq-bench helps to test the condition of a given cpufreq governor. | ||
28 | For that purpose, it compares the performance governor to a configured | ||
29 | powersave module. | ||
30 | |||
31 | |||
32 | How it works | ||
33 | ============ | ||
34 | You can specify load (100% CPU load) and sleep (0% CPU load) times in us which | ||
35 | will be run X time in a row (cycles): | ||
36 | |||
37 | sleep=25000 | ||
38 | load=25000 | ||
39 | cycles=20 | ||
40 | |||
41 | This part of the configuration file will create 25ms load/sleep turns, | ||
42 | repeated 20 times. | ||
43 | |||
44 | Adding this: | ||
45 | sleep_step=25000 | ||
46 | load_step=25000 | ||
47 | rounds=5 | ||
48 | Will increase load and sleep time by 25ms 5 times. | ||
49 | Together you get following test: | ||
50 | 25ms load/sleep time repeated 20 times (cycles). | ||
51 | 50ms load/sleep time repeated 20 times (cycles). | ||
52 | .. | ||
53 | 100ms load/sleep time repeated 20 times (cycles). | ||
54 | |||
55 | First it is calibrated how long a specific CPU intensive calculation | ||
56 | takes on this machine and needs to be run in a loop using the performance | ||
57 | governor. | ||
58 | Then the above test runs are processed using the performance governor | ||
59 | and the governor to test. The time the calculation really needed | ||
60 | with the dynamic freq scaling governor is compared with the time needed | ||
61 | on full performance and you get the overall performance loss. | ||
62 | |||
63 | |||
64 | Example of expected results with ondemand governor: | ||
65 | |||
66 | This shows expected results of the first two test run rounds from | ||
67 | above config, you there have: | ||
68 | |||
69 | 100% CPU load (load) | 0 % CPU load (sleep) | round | ||
70 | 25 ms | 25 ms | 1 | ||
71 | 50 ms | 50 ms | 2 | ||
72 | |||
73 | For example if ondemand governor is configured to have a 50ms | ||
74 | sampling rate you get: | ||
75 | |||
76 | In round 1, ondemand should have rather static 50% load and probably | ||
77 | won't ever switch up (as long as up_threshold is above). | ||
78 | |||
79 | In round 2, if the ondemand sampling times exactly match the load/sleep | ||
80 | trigger of the cpufreq-bench, you will see no performance loss (compare with | ||
81 | below possible ondemand sample kick ins (1)): | ||
82 | |||
83 | But if ondemand always kicks in in the middle of the load sleep cycles, it | ||
84 | will always see 50% loads and you get worst performance impact never | ||
85 | switching up (compare with below possible ondemand sample kick ins (2)):: | ||
86 | |||
87 | 50 50 50 50ms ->time | ||
88 | load -----| |-----| |-----| |-----| | ||
89 | | | | | | | | | ||
90 | sleep |-----| |-----| |-----| |---- | ||
91 | |-----|-----|-----|-----|-----|-----|-----|---- ondemand sampling (1) | ||
92 | 100 0 100 0 100 0 100 load seen by ondemand(%) | ||
93 | |-----|-----|-----|-----|-----|-----|-----|-- ondemand sampling (2) | ||
94 | 50 50 50 50 50 50 50 load seen by ondemand(%) | ||
95 | |||
96 | You can easily test all kind of load/sleep times and check whether your | ||
97 | governor in average behaves as expected. | ||
98 | |||
99 | |||
100 | ToDo | ||
101 | ==== | ||
102 | |||
103 | Provide a gnuplot utility script for easy generation of plots to present | ||
104 | the outcome nicely. | ||
105 | |||
106 | |||
107 | cpufreq-bench Command Usage | ||
108 | =========================== | ||
109 | -l, --load=<long int> initial load time in us | ||
110 | -s, --sleep=<long int> initial sleep time in us | ||
111 | -x, --load-step=<long int> time to be added to load time, in us | ||
112 | -y, --sleep-step=<long int> time to be added to sleep time, in us | ||
113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 | ||
114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT | ||
115 | -g, --governor=<governor> cpufreq governor to test | ||
116 | -n, --cycles=<int> load/sleep cycles to get an avarage value to compare | ||
117 | -r, --rounds<int> load/sleep rounds | ||
118 | -f, --file=<configfile> config file to use | ||
119 | -o, --output=<dir> output dir, must exist | ||
120 | -v, --verbose verbose output on/off | ||
121 | |||
122 | Due to the high priority, the application may not be responsible for some time. | ||
123 | After the benchmark, the logfile is saved in OUTPUTDIR/benchmark_TIMESTAMP.log | ||
124 | |||
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c new file mode 100644 index 000000000000..81b1c48607d9 --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.c | |||
@@ -0,0 +1,194 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <unistd.h> | ||
22 | #include <math.h> | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "system.h" | ||
26 | #include "benchmark.h" | ||
27 | |||
28 | /* Print out progress if we log into a file */ | ||
29 | #define show_progress(total_time, progress_time) \ | ||
30 | if (config->output != stdout) { \ | ||
31 | fprintf(stdout, "Progress: %02lu %%\r", \ | ||
32 | (progress_time * 100) / total_time); \ | ||
33 | fflush(stdout); \ | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * compute how many rounds of calculation we should do | ||
38 | * to get the given load time | ||
39 | * | ||
40 | * @param load aimed load time in µs | ||
41 | * | ||
42 | * @retval rounds of calculation | ||
43 | **/ | ||
44 | |||
45 | unsigned int calculate_timespace(long load, struct config *config) | ||
46 | { | ||
47 | int i; | ||
48 | long long now, then; | ||
49 | unsigned int estimated = GAUGECOUNT; | ||
50 | unsigned int rounds = 0; | ||
51 | unsigned int timed = 0; | ||
52 | |||
53 | if (config->verbose) | ||
54 | printf("calibrating load of %lius, please wait...\n", load); | ||
55 | |||
56 | /* get the initial calculation time for a specific number of rounds */ | ||
57 | now = get_time(); | ||
58 | ROUNDS(estimated); | ||
59 | then = get_time(); | ||
60 | |||
61 | timed = (unsigned int)(then - now); | ||
62 | |||
63 | /* approximation of the wanted load time by comparing with the | ||
64 | * initial calculation time */ | ||
65 | for (i = 0; i < 4; i++) { | ||
66 | rounds = (unsigned int)(load * estimated / timed); | ||
67 | dprintf("calibrating with %u rounds\n", rounds); | ||
68 | now = get_time(); | ||
69 | ROUNDS(rounds); | ||
70 | then = get_time(); | ||
71 | |||
72 | timed = (unsigned int)(then - now); | ||
73 | estimated = rounds; | ||
74 | } | ||
75 | if (config->verbose) | ||
76 | printf("calibration done\n"); | ||
77 | |||
78 | return estimated; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * benchmark | ||
83 | * generates a specific sleep an load time with the performance | ||
84 | * governor and compares the used time for same calculations done | ||
85 | * with the configured powersave governor | ||
86 | * | ||
87 | * @param config config values for the benchmark | ||
88 | * | ||
89 | **/ | ||
90 | |||
91 | void start_benchmark(struct config *config) | ||
92 | { | ||
93 | unsigned int _round, cycle; | ||
94 | long long now, then; | ||
95 | long sleep_time = 0, load_time = 0; | ||
96 | long performance_time = 0, powersave_time = 0; | ||
97 | unsigned int calculations; | ||
98 | unsigned long total_time = 0, progress_time = 0; | ||
99 | |||
100 | sleep_time = config->sleep; | ||
101 | load_time = config->load; | ||
102 | |||
103 | /* For the progress bar */ | ||
104 | for (_round = 1; _round <= config->rounds; _round++) | ||
105 | total_time += _round * (config->sleep + config->load); | ||
106 | total_time *= 2; /* powersave and performance cycles */ | ||
107 | |||
108 | for (_round = 0; _round < config->rounds; _round++) { | ||
109 | performance_time = 0LL; | ||
110 | powersave_time = 0LL; | ||
111 | |||
112 | show_progress(total_time, progress_time); | ||
113 | |||
114 | /* set the cpufreq governor to "performance" which disables | ||
115 | * P-State switching. */ | ||
116 | if (set_cpufreq_governor("performance", config->cpu) != 0) | ||
117 | return; | ||
118 | |||
119 | /* calibrate the calculation time. the resulting calculation | ||
120 | * _rounds should produce a load which matches the configured | ||
121 | * load time */ | ||
122 | calculations = calculate_timespace(load_time, config); | ||
123 | |||
124 | if (config->verbose) | ||
125 | printf("_round %i: doing %u cycles with %u calculations" | ||
126 | " for %lius\n", _round + 1, config->cycles, | ||
127 | calculations, load_time); | ||
128 | |||
129 | fprintf(config->output, "%u %li %li ", | ||
130 | _round, load_time, sleep_time); | ||
131 | |||
132 | if (config->verbose) | ||
133 | printf("avarage: %lius, rps:%li\n", | ||
134 | load_time / calculations, | ||
135 | 1000000 * calculations / load_time); | ||
136 | |||
137 | /* do some sleep/load cycles with the performance governor */ | ||
138 | for (cycle = 0; cycle < config->cycles; cycle++) { | ||
139 | now = get_time(); | ||
140 | usleep(sleep_time); | ||
141 | ROUNDS(calculations); | ||
142 | then = get_time(); | ||
143 | performance_time += then - now - sleep_time; | ||
144 | if (config->verbose) | ||
145 | printf("performance cycle took %lius, " | ||
146 | "sleep: %lius, " | ||
147 | "load: %lius, rounds: %u\n", | ||
148 | (long)(then - now), sleep_time, | ||
149 | load_time, calculations); | ||
150 | } | ||
151 | fprintf(config->output, "%li ", | ||
152 | performance_time / config->cycles); | ||
153 | |||
154 | progress_time += sleep_time + load_time; | ||
155 | show_progress(total_time, progress_time); | ||
156 | |||
157 | /* set the powersave governor which activates P-State switching | ||
158 | * again */ | ||
159 | if (set_cpufreq_governor(config->governor, config->cpu) != 0) | ||
160 | return; | ||
161 | |||
162 | /* again, do some sleep/load cycles with the | ||
163 | * powersave governor */ | ||
164 | for (cycle = 0; cycle < config->cycles; cycle++) { | ||
165 | now = get_time(); | ||
166 | usleep(sleep_time); | ||
167 | ROUNDS(calculations); | ||
168 | then = get_time(); | ||
169 | powersave_time += then - now - sleep_time; | ||
170 | if (config->verbose) | ||
171 | printf("powersave cycle took %lius, " | ||
172 | "sleep: %lius, " | ||
173 | "load: %lius, rounds: %u\n", | ||
174 | (long)(then - now), sleep_time, | ||
175 | load_time, calculations); | ||
176 | } | ||
177 | |||
178 | progress_time += sleep_time + load_time; | ||
179 | |||
180 | /* compare the avarage sleep/load cycles */ | ||
181 | fprintf(config->output, "%li ", | ||
182 | powersave_time / config->cycles); | ||
183 | fprintf(config->output, "%.3f\n", | ||
184 | performance_time * 100.0 / powersave_time); | ||
185 | fflush(config->output); | ||
186 | |||
187 | if (config->verbose) | ||
188 | printf("performance is at %.2f%%\n", | ||
189 | performance_time * 100.0 / powersave_time); | ||
190 | |||
191 | sleep_time += config->sleep_step; | ||
192 | load_time += config->load_step; | ||
193 | } | ||
194 | } | ||
diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h new file mode 100644 index 000000000000..51d7f50ac2bb --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* load loop, this schould take about 1 to 2ms to complete */ | ||
21 | #define ROUNDS(x) {unsigned int rcnt; \ | ||
22 | for (rcnt = 0; rcnt < x*1000; rcnt++) { \ | ||
23 | (void)(((int)(pow(rcnt, rcnt) * \ | ||
24 | sqrt(rcnt*7230970)) ^ 7230716) ^ \ | ||
25 | (int)atan2(rcnt, rcnt)); \ | ||
26 | } } \ | ||
27 | |||
28 | |||
29 | void start_benchmark(struct config *config); | ||
diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h new file mode 100644 index 000000000000..ee6f258e5336 --- /dev/null +++ b/tools/power/cpupower/bench/config.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* initial loop count for the load calibration */ | ||
21 | #define GAUGECOUNT 1500 | ||
22 | |||
23 | /* default scheduling policy SCHED_OTHER */ | ||
24 | #define SCHEDULER SCHED_OTHER | ||
25 | |||
26 | #define PRIORITY_DEFAULT 0 | ||
27 | #define PRIORITY_HIGH sched_get_priority_max(SCHEDULER) | ||
28 | #define PRIORITY_LOW sched_get_priority_min(SCHEDULER) | ||
29 | |||
30 | /* enable further debug messages */ | ||
31 | #ifdef DEBUG | ||
32 | #define dprintf printf | ||
33 | #else | ||
34 | #define dprintf(...) do { } while (0) | ||
35 | #endif | ||
36 | |||
diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh new file mode 100644 index 000000000000..410021a12f40 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_plot.sh | |||
@@ -0,0 +1,104 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This program is free software: you can redistribute it and/or modify | ||
4 | # it under the terms of the GNU General Public License as published by | ||
5 | # the Free Software Foundation; either version 2, or (at your option) | ||
6 | # any later version. | ||
7 | |||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | |||
13 | # You should have received a copy of the GNU General Public License | ||
14 | # along with this program; if not, write to the Free Software | ||
15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
16 | # 02110-1301, USA. | ||
17 | |||
18 | # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
19 | |||
20 | # Helper script to easily create nice plots of your cpufreq-bench results | ||
21 | |||
22 | dir=`mktemp -d` | ||
23 | output_file="cpufreq-bench.png" | ||
24 | global_title="cpufreq-bench plot" | ||
25 | picture_type="jpeg" | ||
26 | file[0]="" | ||
27 | |||
28 | function usage() | ||
29 | { | ||
30 | echo "cpufreq-bench_plot.sh [OPTIONS] logfile [measure_title] [logfile [measure_title]] ...]" | ||
31 | echo | ||
32 | echo "Options" | ||
33 | echo " -o output_file" | ||
34 | echo " -t global_title" | ||
35 | echo " -p picture_type [jpeg|gif|png|postscript|...]" | ||
36 | exit 1 | ||
37 | } | ||
38 | |||
39 | if [ $# -eq 0 ];then | ||
40 | echo "No benchmark results file provided" | ||
41 | echo | ||
42 | usage | ||
43 | fi | ||
44 | |||
45 | while getopts o:t:p: name ; do | ||
46 | case $name in | ||
47 | o) | ||
48 | output_file="$OPTARG".$picture_type | ||
49 | ;; | ||
50 | t) | ||
51 | global_title="$OPTARG" | ||
52 | ;; | ||
53 | p) | ||
54 | picture_type="$OPTARG" | ||
55 | ;; | ||
56 | ?) | ||
57 | usage | ||
58 | ;; | ||
59 | esac | ||
60 | done | ||
61 | shift $(($OPTIND -1)) | ||
62 | |||
63 | plots=0 | ||
64 | while [ "$1" ];do | ||
65 | if [ ! -f "$1" ];then | ||
66 | echo "File $1 does not exist" | ||
67 | usage | ||
68 | fi | ||
69 | file[$plots]="$1" | ||
70 | title[$plots]="$2" | ||
71 | # echo "File: ${file[$plots]} - ${title[plots]}" | ||
72 | shift;shift | ||
73 | plots=$((plots + 1)) | ||
74 | done | ||
75 | |||
76 | echo "set terminal $picture_type" >> $dir/plot_script.gpl | ||
77 | echo "set output \"$output_file\"" >> $dir/plot_script.gpl | ||
78 | echo "set title \"$global_title\"" >> $dir/plot_script.gpl | ||
79 | echo "set xlabel \"sleep/load time\"" >> $dir/plot_script.gpl | ||
80 | echo "set ylabel \"Performance (%)\"" >> $dir/plot_script.gpl | ||
81 | |||
82 | for((plot=0;plot<$plots;plot++));do | ||
83 | |||
84 | # Sanity check | ||
85 | ###### I am to dump to get this redirected to stderr/stdout in one awk call... ##### | ||
86 | cat ${file[$plot]} |grep -v "^#" |awk '{if ($2 != $3) printf("Error in measure %d:Load time %s does not equal sleep time %s, plot will not be correct\n", $1, $2, $3); ERR=1}' | ||
87 | ###### I am to dump to get this redirected in one awk call... ##### | ||
88 | |||
89 | # Parse out load time (which must be equal to sleep time for a plot), divide it by 1000 | ||
90 | # to get ms and parse out the performance in percentage and write it to a temp file for plotting | ||
91 | cat ${file[$plot]} |grep -v "^#" |awk '{printf "%lu %.1f\n",$2/1000, $6}' >$dir/data_$plot | ||
92 | |||
93 | if [ $plot -eq 0 ];then | ||
94 | echo -n "plot " >> $dir/plot_script.gpl | ||
95 | fi | ||
96 | echo -n "\"$dir/data_$plot\" title \"${title[$plot]}\" with lines" >> $dir/plot_script.gpl | ||
97 | if [ $(($plot + 1)) -ne $plots ];then | ||
98 | echo -n ", " >> $dir/plot_script.gpl | ||
99 | fi | ||
100 | done | ||
101 | echo >> $dir/plot_script.gpl | ||
102 | |||
103 | gnuplot $dir/plot_script.gpl | ||
104 | rm -r $dir \ No newline at end of file | ||
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh new file mode 100644 index 000000000000..de20d2a06879 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_script.sh | |||
@@ -0,0 +1,101 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This program is free software: you can redistribute it and/or modify | ||
4 | # it under the terms of the GNU General Public License as published by | ||
5 | # the Free Software Foundation; either version 2, or (at your option) | ||
6 | # any later version. | ||
7 | |||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | |||
13 | # You should have received a copy of the GNU General Public License | ||
14 | # along with this program; if not, write to the Free Software | ||
15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
16 | # 02110-1301, USA. | ||
17 | |||
18 | # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
19 | |||
20 | # Ondemand up_threshold and sampling rate test script for cpufreq-bench | ||
21 | # mircobenchmark. | ||
22 | # Modify the general variables at the top or extend or copy out parts | ||
23 | # if you want to test other things | ||
24 | # | ||
25 | |||
26 | # Default with latest kernels is 95, before micro account patches | ||
27 | # it was 80, cmp. with git commit 808009131046b62ac434dbc796 | ||
28 | UP_THRESHOLD="60 80 95" | ||
29 | # Depending on the kernel and the HW sampling rate could be restricted | ||
30 | # and cannot be set that low... | ||
31 | # E.g. before git commit cef9615a853ebc4972084f7 one could only set | ||
32 | # min sampling rate of 80000 if CONFIG_HZ=250 | ||
33 | SAMPLING_RATE="20000 80000" | ||
34 | |||
35 | function measure() | ||
36 | { | ||
37 | local -i up_threshold_set | ||
38 | local -i sampling_rate_set | ||
39 | |||
40 | for up_threshold in $UP_THRESHOLD;do | ||
41 | for sampling_rate in $SAMPLING_RATE;do | ||
42 | # Set values in sysfs | ||
43 | echo $up_threshold >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold | ||
44 | echo $sampling_rate >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate | ||
45 | up_threshold_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold) | ||
46 | sampling_rate_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate) | ||
47 | |||
48 | # Verify set values in sysfs | ||
49 | if [ ${up_threshold_set} -eq ${up_threshold} ];then | ||
50 | echo "up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" | ||
51 | else | ||
52 | echo "WARNING: Tried to set up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" | ||
53 | fi | ||
54 | if [ ${sampling_rate_set} -eq ${sampling_rate} ];then | ||
55 | echo "sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" | ||
56 | else | ||
57 | echo "WARNING: Tried to set sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" | ||
58 | fi | ||
59 | |||
60 | # Benchmark | ||
61 | cpufreq-bench -o /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate} | ||
62 | done | ||
63 | done | ||
64 | } | ||
65 | |||
66 | function create_plots() | ||
67 | { | ||
68 | local command | ||
69 | |||
70 | for up_threshold in $UP_THRESHOLD;do | ||
71 | command="cpufreq-bench_plot.sh -o \"sampling_rate_${SAMPLING_RATE}_up_threshold_${up_threshold}\" -t \"Ondemand sampling_rate: ${SAMPLING_RATE} comparison - Up_threshold: $up_threshold %\"" | ||
72 | for sampling_rate in $SAMPLING_RATE;do | ||
73 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"sampling_rate = $sampling_rate\"" | ||
74 | done | ||
75 | echo $command | ||
76 | eval "$command" | ||
77 | echo | ||
78 | done | ||
79 | |||
80 | for sampling_rate in $SAMPLING_RATE;do | ||
81 | command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${sampling_rate}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} % comparison - sampling_rate: $sampling_rate\"" | ||
82 | for up_threshold in $UP_THRESHOLD;do | ||
83 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold\"" | ||
84 | done | ||
85 | echo $command | ||
86 | eval "$command" | ||
87 | echo | ||
88 | done | ||
89 | |||
90 | command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${SAMPLING_RATE}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} and sampling_rate ${SAMPLING_RATE} comparison\"" | ||
91 | for sampling_rate in $SAMPLING_RATE;do | ||
92 | for up_threshold in $UP_THRESHOLD;do | ||
93 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold - sampling_rate = $sampling_rate\"" | ||
94 | done | ||
95 | done | ||
96 | echo "$command" | ||
97 | eval "$command" | ||
98 | } | ||
99 | |||
100 | measure | ||
101 | create_plots \ No newline at end of file | ||
diff --git a/tools/power/cpupower/bench/example.cfg b/tools/power/cpupower/bench/example.cfg new file mode 100644 index 000000000000..f91f64360688 --- /dev/null +++ b/tools/power/cpupower/bench/example.cfg | |||
@@ -0,0 +1,11 @@ | |||
1 | sleep = 50000 | ||
2 | load = 50000 | ||
3 | cpu = 0 | ||
4 | priority = LOW | ||
5 | output = /var/log/cpufreq-bench | ||
6 | sleep_step = 50000 | ||
7 | load_step = 50000 | ||
8 | cycles = 20 | ||
9 | rounds = 40 | ||
10 | verbose = 0 | ||
11 | governor = ondemand | ||
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c new file mode 100644 index 000000000000..24910313a521 --- /dev/null +++ b/tools/power/cpupower/bench/main.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <unistd.h> | ||
24 | #include <getopt.h> | ||
25 | #include <errno.h> | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "system.h" | ||
29 | #include "benchmark.h" | ||
30 | |||
31 | static struct option long_options[] = { | ||
32 | {"output", 1, 0, 'o'}, | ||
33 | {"sleep", 1, 0, 's'}, | ||
34 | {"load", 1, 0, 'l'}, | ||
35 | {"verbose", 0, 0, 'v'}, | ||
36 | {"cpu", 1, 0, 'c'}, | ||
37 | {"governor", 1, 0, 'g'}, | ||
38 | {"prio", 1, 0, 'p'}, | ||
39 | {"file", 1, 0, 'f'}, | ||
40 | {"cycles", 1, 0, 'n'}, | ||
41 | {"rounds", 1, 0, 'r'}, | ||
42 | {"load-step", 1, 0, 'x'}, | ||
43 | {"sleep-step", 1, 0, 'y'}, | ||
44 | {"help", 0, 0, 'h'}, | ||
45 | {0, 0, 0, 0} | ||
46 | }; | ||
47 | |||
48 | /******************************************************************* | ||
49 | usage | ||
50 | *******************************************************************/ | ||
51 | |||
52 | void usage() | ||
53 | { | ||
54 | printf("usage: ./bench\n"); | ||
55 | printf("Options:\n"); | ||
56 | printf(" -l, --load=<long int>\t\tinitial load time in us\n"); | ||
57 | printf(" -s, --sleep=<long int>\t\tinitial sleep time in us\n"); | ||
58 | printf(" -x, --load-step=<long int>\ttime to be added to load time, in us\n"); | ||
59 | printf(" -y, --sleep-step=<long int>\ttime to be added to sleep time, in us\n"); | ||
60 | printf(" -c, --cpu=<cpu #>\t\t\tCPU Nr. to use, starting at 0\n"); | ||
61 | printf(" -p, --prio=<priority>\t\t\tscheduler priority, HIGH, LOW or DEFAULT\n"); | ||
62 | printf(" -g, --governor=<governor>\t\tcpufreq governor to test\n"); | ||
63 | printf(" -n, --cycles=<int>\t\t\tload/sleep cycles\n"); | ||
64 | printf(" -r, --rounds<int>\t\t\tload/sleep rounds\n"); | ||
65 | printf(" -f, --file=<configfile>\t\tconfig file to use\n"); | ||
66 | printf(" -o, --output=<dir>\t\t\toutput path. Filename will be OUTPUTPATH/benchmark_TIMESTAMP.log\n"); | ||
67 | printf(" -v, --verbose\t\t\t\tverbose output on/off\n"); | ||
68 | printf(" -h, --help\t\t\t\tPrint this help screen\n"); | ||
69 | exit(1); | ||
70 | } | ||
71 | |||
72 | /******************************************************************* | ||
73 | main | ||
74 | *******************************************************************/ | ||
75 | |||
76 | int main(int argc, char **argv) | ||
77 | { | ||
78 | int c; | ||
79 | int option_index = 0; | ||
80 | struct config *config = NULL; | ||
81 | |||
82 | config = prepare_default_config(); | ||
83 | |||
84 | if (config == NULL) | ||
85 | return EXIT_FAILURE; | ||
86 | |||
87 | while (1) { | ||
88 | c = getopt_long (argc, argv, "hg:o:s:l:vc:p:f:n:r:x:y:", | ||
89 | long_options, &option_index); | ||
90 | if (c == -1) | ||
91 | break; | ||
92 | |||
93 | switch (c) { | ||
94 | case 'o': | ||
95 | if (config->output != NULL) | ||
96 | fclose(config->output); | ||
97 | |||
98 | config->output = prepare_output(optarg); | ||
99 | |||
100 | if (config->output == NULL) | ||
101 | return EXIT_FAILURE; | ||
102 | |||
103 | dprintf("user output path -> %s\n", optarg); | ||
104 | break; | ||
105 | case 's': | ||
106 | sscanf(optarg, "%li", &config->sleep); | ||
107 | dprintf("user sleep time -> %s\n", optarg); | ||
108 | break; | ||
109 | case 'l': | ||
110 | sscanf(optarg, "%li", &config->load); | ||
111 | dprintf("user load time -> %s\n", optarg); | ||
112 | break; | ||
113 | case 'c': | ||
114 | sscanf(optarg, "%u", &config->cpu); | ||
115 | dprintf("user cpu -> %s\n", optarg); | ||
116 | break; | ||
117 | case 'g': | ||
118 | strncpy(config->governor, optarg, 14); | ||
119 | dprintf("user governor -> %s\n", optarg); | ||
120 | break; | ||
121 | case 'p': | ||
122 | if (string_to_prio(optarg) != SCHED_ERR) { | ||
123 | config->prio = string_to_prio(optarg); | ||
124 | dprintf("user prio -> %s\n", optarg); | ||
125 | } else { | ||
126 | if (config != NULL) { | ||
127 | if (config->output != NULL) | ||
128 | fclose(config->output); | ||
129 | free(config); | ||
130 | } | ||
131 | usage(); | ||
132 | } | ||
133 | break; | ||
134 | case 'n': | ||
135 | sscanf(optarg, "%u", &config->cycles); | ||
136 | dprintf("user cycles -> %s\n", optarg); | ||
137 | break; | ||
138 | case 'r': | ||
139 | sscanf(optarg, "%u", &config->rounds); | ||
140 | dprintf("user rounds -> %s\n", optarg); | ||
141 | break; | ||
142 | case 'x': | ||
143 | sscanf(optarg, "%li", &config->load_step); | ||
144 | dprintf("user load_step -> %s\n", optarg); | ||
145 | break; | ||
146 | case 'y': | ||
147 | sscanf(optarg, "%li", &config->sleep_step); | ||
148 | dprintf("user sleep_step -> %s\n", optarg); | ||
149 | break; | ||
150 | case 'f': | ||
151 | if (prepare_config(optarg, config)) | ||
152 | return EXIT_FAILURE; | ||
153 | break; | ||
154 | case 'v': | ||
155 | config->verbose = 1; | ||
156 | dprintf("verbose output enabled\n"); | ||
157 | break; | ||
158 | case 'h': | ||
159 | case '?': | ||
160 | default: | ||
161 | if (config != NULL) { | ||
162 | if (config->output != NULL) | ||
163 | fclose(config->output); | ||
164 | free(config); | ||
165 | } | ||
166 | usage(); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (config->verbose) { | ||
171 | printf("starting benchmark with parameters:\n"); | ||
172 | printf("config:\n\t" | ||
173 | "sleep=%li\n\t" | ||
174 | "load=%li\n\t" | ||
175 | "sleep_step=%li\n\t" | ||
176 | "load_step=%li\n\t" | ||
177 | "cpu=%u\n\t" | ||
178 | "cycles=%u\n\t" | ||
179 | "rounds=%u\n\t" | ||
180 | "governor=%s\n\n", | ||
181 | config->sleep, | ||
182 | config->load, | ||
183 | config->sleep_step, | ||
184 | config->load_step, | ||
185 | config->cpu, | ||
186 | config->cycles, | ||
187 | config->rounds, | ||
188 | config->governor); | ||
189 | } | ||
190 | |||
191 | prepare_user(config); | ||
192 | prepare_system(config); | ||
193 | start_benchmark(config); | ||
194 | |||
195 | if (config->output != stdout) | ||
196 | fclose(config->output); | ||
197 | |||
198 | free(config); | ||
199 | |||
200 | return EXIT_SUCCESS; | ||
201 | } | ||
202 | |||
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c new file mode 100644 index 000000000000..543bba14ae2c --- /dev/null +++ b/tools/power/cpupower/bench/parse.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <string.h> | ||
24 | #include <time.h> | ||
25 | #include <dirent.h> | ||
26 | |||
27 | #include <sys/utsname.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | |||
31 | #include "parse.h" | ||
32 | #include "config.h" | ||
33 | |||
34 | /** | ||
35 | * converts priority string to priority | ||
36 | * | ||
37 | * @param str string that represents a scheduler priority | ||
38 | * | ||
39 | * @retval priority | ||
40 | * @retval SCHED_ERR when the priority doesn't exit | ||
41 | **/ | ||
42 | |||
43 | enum sched_prio string_to_prio(const char *str) | ||
44 | { | ||
45 | if (strncasecmp("high", str, strlen(str)) == 0) | ||
46 | return SCHED_HIGH; | ||
47 | else if (strncasecmp("default", str, strlen(str)) == 0) | ||
48 | return SCHED_DEFAULT; | ||
49 | else if (strncasecmp("low", str, strlen(str)) == 0) | ||
50 | return SCHED_LOW; | ||
51 | else | ||
52 | return SCHED_ERR; | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * create and open logfile | ||
57 | * | ||
58 | * @param dir directory in which the logfile should be created | ||
59 | * | ||
60 | * @retval logfile on success | ||
61 | * @retval NULL when the file can't be created | ||
62 | **/ | ||
63 | |||
64 | FILE *prepare_output(const char *dirname) | ||
65 | { | ||
66 | FILE *output = NULL; | ||
67 | int len; | ||
68 | char *filename; | ||
69 | struct utsname sysdata; | ||
70 | DIR *dir; | ||
71 | |||
72 | dir = opendir(dirname); | ||
73 | if (dir == NULL) { | ||
74 | if (mkdir(dirname, 0755)) { | ||
75 | perror("mkdir"); | ||
76 | fprintf(stderr, "error: Cannot create dir %s\n", | ||
77 | dirname); | ||
78 | return NULL; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | len = strlen(dirname) + 30; | ||
83 | filename = malloc(sizeof(char) * len); | ||
84 | |||
85 | if (uname(&sysdata) == 0) { | ||
86 | len += strlen(sysdata.nodename) + strlen(sysdata.release); | ||
87 | filename = realloc(filename, sizeof(char) * len); | ||
88 | |||
89 | if (filename == NULL) { | ||
90 | perror("realloc"); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", | ||
95 | dirname, sysdata.nodename, sysdata.release, time(NULL)); | ||
96 | } else { | ||
97 | snprintf(filename, len - 1, "%s/benchmark_%li.log", | ||
98 | dirname, time(NULL)); | ||
99 | } | ||
100 | |||
101 | dprintf("logilename: %s\n", filename); | ||
102 | |||
103 | output = fopen(filename, "w+"); | ||
104 | if (output == NULL) { | ||
105 | perror("fopen"); | ||
106 | fprintf(stderr, "error: unable to open logfile\n"); | ||
107 | } | ||
108 | |||
109 | fprintf(stdout, "Logfile: %s\n", filename); | ||
110 | |||
111 | free(filename); | ||
112 | fprintf(output, "#round load sleep performance powersave percentage\n"); | ||
113 | return output; | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * returns the default config | ||
118 | * | ||
119 | * @retval default config on success | ||
120 | * @retval NULL when the output file can't be created | ||
121 | **/ | ||
122 | |||
123 | struct config *prepare_default_config() | ||
124 | { | ||
125 | struct config *config = malloc(sizeof(struct config)); | ||
126 | |||
127 | dprintf("loading defaults\n"); | ||
128 | |||
129 | config->sleep = 500000; | ||
130 | config->load = 500000; | ||
131 | config->sleep_step = 500000; | ||
132 | config->load_step = 500000; | ||
133 | config->cycles = 5; | ||
134 | config->rounds = 50; | ||
135 | config->cpu = 0; | ||
136 | config->prio = SCHED_HIGH; | ||
137 | config->verbose = 0; | ||
138 | strncpy(config->governor, "ondemand", 8); | ||
139 | |||
140 | config->output = stdout; | ||
141 | |||
142 | #ifdef DEFAULT_CONFIG_FILE | ||
143 | if (prepare_config(DEFAULT_CONFIG_FILE, config)) | ||
144 | return NULL; | ||
145 | #endif | ||
146 | return config; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * parses config file and returns the config to the caller | ||
151 | * | ||
152 | * @param path config file name | ||
153 | * | ||
154 | * @retval 1 on error | ||
155 | * @retval 0 on success | ||
156 | **/ | ||
157 | |||
158 | int prepare_config(const char *path, struct config *config) | ||
159 | { | ||
160 | size_t len = 0; | ||
161 | char *opt, *val, *line = NULL; | ||
162 | FILE *configfile = fopen(path, "r"); | ||
163 | |||
164 | if (config == NULL) { | ||
165 | fprintf(stderr, "error: config is NULL\n"); | ||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | if (configfile == NULL) { | ||
170 | perror("fopen"); | ||
171 | fprintf(stderr, "error: unable to read configfile\n"); | ||
172 | free(config); | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | while (getline(&line, &len, configfile) != -1) { | ||
177 | if (line[0] == '#' || line[0] == ' ') | ||
178 | continue; | ||
179 | |||
180 | sscanf(line, "%as = %as", &opt, &val); | ||
181 | |||
182 | dprintf("parsing: %s -> %s\n", opt, val); | ||
183 | |||
184 | if (strncmp("sleep", opt, strlen(opt)) == 0) | ||
185 | sscanf(val, "%li", &config->sleep); | ||
186 | |||
187 | else if (strncmp("load", opt, strlen(opt)) == 0) | ||
188 | sscanf(val, "%li", &config->load); | ||
189 | |||
190 | else if (strncmp("load_step", opt, strlen(opt)) == 0) | ||
191 | sscanf(val, "%li", &config->load_step); | ||
192 | |||
193 | else if (strncmp("sleep_step", opt, strlen(opt)) == 0) | ||
194 | sscanf(val, "%li", &config->sleep_step); | ||
195 | |||
196 | else if (strncmp("cycles", opt, strlen(opt)) == 0) | ||
197 | sscanf(val, "%u", &config->cycles); | ||
198 | |||
199 | else if (strncmp("rounds", opt, strlen(opt)) == 0) | ||
200 | sscanf(val, "%u", &config->rounds); | ||
201 | |||
202 | else if (strncmp("verbose", opt, strlen(opt)) == 0) | ||
203 | sscanf(val, "%u", &config->verbose); | ||
204 | |||
205 | else if (strncmp("output", opt, strlen(opt)) == 0) | ||
206 | config->output = prepare_output(val); | ||
207 | |||
208 | else if (strncmp("cpu", opt, strlen(opt)) == 0) | ||
209 | sscanf(val, "%u", &config->cpu); | ||
210 | |||
211 | else if (strncmp("governor", opt, 14) == 0) | ||
212 | strncpy(config->governor, val, 14); | ||
213 | |||
214 | else if (strncmp("priority", opt, strlen(opt)) == 0) { | ||
215 | if (string_to_prio(val) != SCHED_ERR) | ||
216 | config->prio = string_to_prio(val); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | free(line); | ||
221 | free(opt); | ||
222 | free(val); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h new file mode 100644 index 000000000000..a8dc632d9eee --- /dev/null +++ b/tools/power/cpupower/bench/parse.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* struct that holds the required config parameters */ | ||
21 | struct config | ||
22 | { | ||
23 | long sleep; /* sleep time in µs */ | ||
24 | long load; /* load time in µs */ | ||
25 | long sleep_step; /* time value which changes the | ||
26 | * sleep time after every round in µs */ | ||
27 | long load_step; /* time value which changes the | ||
28 | * load time after every round in µs */ | ||
29 | unsigned int cycles; /* calculation cycles with the same sleep/load time */ | ||
30 | unsigned int rounds; /* calculation rounds with iterated sleep/load time */ | ||
31 | unsigned int cpu; /* cpu for which the affinity is set */ | ||
32 | char governor[15]; /* cpufreq governor */ | ||
33 | enum sched_prio /* possible scheduler priorities */ | ||
34 | { | ||
35 | SCHED_ERR = -1, | ||
36 | SCHED_HIGH, | ||
37 | SCHED_DEFAULT, | ||
38 | SCHED_LOW | ||
39 | } prio; | ||
40 | |||
41 | unsigned int verbose; /* verbose output */ | ||
42 | FILE *output; /* logfile */ | ||
43 | char *output_filename; /* logfile name, must be freed at the end | ||
44 | if output != NULL and output != stdout*/ | ||
45 | }; | ||
46 | |||
47 | enum sched_prio string_to_prio(const char *str); | ||
48 | |||
49 | FILE *prepare_output(const char *dir); | ||
50 | |||
51 | int prepare_config(const char *path, struct config *config); | ||
52 | struct config *prepare_default_config(); | ||
53 | |||
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c new file mode 100644 index 000000000000..f01e3f4be84c --- /dev/null +++ b/tools/power/cpupower/bench/system.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <time.h> | ||
22 | #include <sys/time.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <sched.h> | ||
27 | |||
28 | #include <cpufreq.h> | ||
29 | |||
30 | #include "config.h" | ||
31 | #include "system.h" | ||
32 | |||
33 | /** | ||
34 | * returns time since epoch in µs | ||
35 | * | ||
36 | * @retval time | ||
37 | **/ | ||
38 | |||
39 | long long int get_time() | ||
40 | { | ||
41 | struct timeval now; | ||
42 | |||
43 | gettimeofday(&now, NULL); | ||
44 | |||
45 | return (long long int)(now.tv_sec * 1000000LL + now.tv_usec); | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * sets the cpufreq governor | ||
50 | * | ||
51 | * @param governor cpufreq governor name | ||
52 | * @param cpu cpu for which the governor should be set | ||
53 | * | ||
54 | * @retval 0 on success | ||
55 | * @retval -1 when failed | ||
56 | **/ | ||
57 | |||
58 | int set_cpufreq_governor(char *governor, unsigned int cpu) | ||
59 | { | ||
60 | |||
61 | dprintf("set %s as cpufreq governor\n", governor); | ||
62 | |||
63 | if (cpufreq_cpu_exists(cpu) != 0) { | ||
64 | perror("cpufreq_cpu_exists"); | ||
65 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | if (cpufreq_modify_policy_governor(cpu, governor) != 0) { | ||
70 | perror("cpufreq_modify_policy_governor"); | ||
71 | fprintf(stderr, "error: unable to set %s governor\n", governor); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * sets cpu affinity for the process | ||
80 | * | ||
81 | * @param cpu cpu# to which the affinity should be set | ||
82 | * | ||
83 | * @retval 0 on success | ||
84 | * @retval -1 when setting the affinity failed | ||
85 | **/ | ||
86 | |||
87 | int set_cpu_affinity(unsigned int cpu) | ||
88 | { | ||
89 | cpu_set_t cpuset; | ||
90 | |||
91 | CPU_ZERO(&cpuset); | ||
92 | CPU_SET(cpu, &cpuset); | ||
93 | |||
94 | dprintf("set affinity to cpu #%u\n", cpu); | ||
95 | |||
96 | if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpuset) < 0) { | ||
97 | perror("sched_setaffinity"); | ||
98 | fprintf(stderr, "warning: unable to set cpu affinity\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * sets the process priority parameter | ||
107 | * | ||
108 | * @param priority priority value | ||
109 | * | ||
110 | * @retval 0 on success | ||
111 | * @retval -1 when setting the priority failed | ||
112 | **/ | ||
113 | |||
114 | int set_process_priority(int priority) | ||
115 | { | ||
116 | struct sched_param param; | ||
117 | |||
118 | dprintf("set scheduler priority to %i\n", priority); | ||
119 | |||
120 | param.sched_priority = priority; | ||
121 | |||
122 | if (sched_setscheduler(0, SCHEDULER, ¶m) < 0) { | ||
123 | perror("sched_setscheduler"); | ||
124 | fprintf(stderr, "warning: unable to set scheduler priority\n"); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * notifies the user that the benchmark may run some time | ||
133 | * | ||
134 | * @param config benchmark config values | ||
135 | * | ||
136 | **/ | ||
137 | |||
138 | void prepare_user(const struct config *config) | ||
139 | { | ||
140 | unsigned long sleep_time = 0; | ||
141 | unsigned long load_time = 0; | ||
142 | unsigned int round; | ||
143 | |||
144 | for (round = 0; round < config->rounds; round++) { | ||
145 | sleep_time += 2 * config->cycles * | ||
146 | (config->sleep + config->sleep_step * round); | ||
147 | load_time += 2 * config->cycles * | ||
148 | (config->load + config->load_step * round) + | ||
149 | (config->load + config->load_step * round * 4); | ||
150 | } | ||
151 | |||
152 | if (config->verbose || config->output != stdout) | ||
153 | printf("approx. test duration: %im\n", | ||
154 | (int)((sleep_time + load_time) / 60000000)); | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * sets up the cpu affinity and scheduler priority | ||
159 | * | ||
160 | * @param config benchmark config values | ||
161 | * | ||
162 | **/ | ||
163 | |||
164 | void prepare_system(const struct config *config) | ||
165 | { | ||
166 | if (config->verbose) | ||
167 | printf("set cpu affinity to cpu #%u\n", config->cpu); | ||
168 | |||
169 | set_cpu_affinity(config->cpu); | ||
170 | |||
171 | switch (config->prio) { | ||
172 | case SCHED_HIGH: | ||
173 | if (config->verbose) | ||
174 | printf("high priority condition requested\n"); | ||
175 | |||
176 | set_process_priority(PRIORITY_HIGH); | ||
177 | break; | ||
178 | case SCHED_LOW: | ||
179 | if (config->verbose) | ||
180 | printf("low priority condition requested\n"); | ||
181 | |||
182 | set_process_priority(PRIORITY_LOW); | ||
183 | break; | ||
184 | default: | ||
185 | if (config->verbose) | ||
186 | printf("default priority condition requested\n"); | ||
187 | |||
188 | set_process_priority(PRIORITY_DEFAULT); | ||
189 | } | ||
190 | } | ||
191 | |||
diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h new file mode 100644 index 000000000000..3a8c858b78f0 --- /dev/null +++ b/tools/power/cpupower/bench/system.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include "parse.h" | ||
21 | |||
22 | long long get_time(); | ||
23 | |||
24 | int set_cpufreq_governor(char *governor, unsigned int cpu); | ||
25 | int set_cpu_affinity(unsigned int cpu); | ||
26 | int set_process_priority(int priority); | ||
27 | |||
28 | void prepare_user(const struct config *config); | ||
29 | void prepare_system(const struct config *config); | ||
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile new file mode 100644 index 000000000000..d08cc1ead9bc --- /dev/null +++ b/tools/power/cpupower/debug/i386/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | default: all | ||
2 | |||
3 | centrino-decode: centrino-decode.c | ||
4 | $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c | ||
5 | |||
6 | dump_psb: dump_psb.c | ||
7 | $(CC) $(CFLAGS) -o dump_psb dump_psb.c | ||
8 | |||
9 | intel_gsic: intel_gsic.c | ||
10 | $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c | ||
11 | |||
12 | powernow-k8-decode: powernow-k8-decode.c | ||
13 | $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c | ||
14 | |||
15 | all: centrino-decode dump_psb intel_gsic powernow-k8-decode | ||
16 | |||
17 | clean: | ||
18 | rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode | ||
19 | |||
20 | .PHONY: all default clean | ||
diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c new file mode 100644 index 000000000000..7ef24cce4926 --- /dev/null +++ b/tools/power/cpupower/debug/i386/centrino-decode.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * (C) 2003 - 2004 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on code found in | ||
7 | * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | ||
8 | * and originally developed by Jeremy Fitzhardinge. | ||
9 | * | ||
10 | * USAGE: simply run it to decode the current settings on CPU 0, | ||
11 | * or pass the CPU number as argument, or pass the MSR content | ||
12 | * as argument. | ||
13 | */ | ||
14 | |||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <stdint.h> | ||
18 | #include <unistd.h> | ||
19 | #include <errno.h> | ||
20 | #include <fcntl.h> | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | |||
25 | #define MCPU 32 | ||
26 | |||
27 | #define MSR_IA32_PERF_STATUS 0x198 | ||
28 | |||
29 | static int rdmsr(unsigned int cpu, unsigned int msr, | ||
30 | unsigned int *lo, unsigned int *hi) | ||
31 | { | ||
32 | int fd; | ||
33 | char file[20]; | ||
34 | unsigned long long val; | ||
35 | int retval = -1; | ||
36 | |||
37 | *lo = *hi = 0; | ||
38 | |||
39 | if (cpu > MCPU) | ||
40 | goto err1; | ||
41 | |||
42 | sprintf(file, "/dev/cpu/%d/msr", cpu); | ||
43 | fd = open(file, O_RDONLY); | ||
44 | |||
45 | if (fd < 0) | ||
46 | goto err1; | ||
47 | |||
48 | if (lseek(fd, msr, SEEK_CUR) == -1) | ||
49 | goto err2; | ||
50 | |||
51 | if (read(fd, &val, 8) != 8) | ||
52 | goto err2; | ||
53 | |||
54 | *lo = (uint32_t )(val & 0xffffffffull); | ||
55 | *hi = (uint32_t )(val>>32 & 0xffffffffull); | ||
56 | |||
57 | retval = 0; | ||
58 | err2: | ||
59 | close(fd); | ||
60 | err1: | ||
61 | return retval; | ||
62 | } | ||
63 | |||
64 | static void decode (unsigned int msr) | ||
65 | { | ||
66 | unsigned int multiplier; | ||
67 | unsigned int mv; | ||
68 | |||
69 | multiplier = ((msr >> 8) & 0xFF); | ||
70 | |||
71 | mv = (((msr & 0xFF) * 16) + 700); | ||
72 | |||
73 | printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv); | ||
74 | } | ||
75 | |||
76 | static int decode_live(unsigned int cpu) | ||
77 | { | ||
78 | unsigned int lo, hi; | ||
79 | int err; | ||
80 | |||
81 | err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi); | ||
82 | |||
83 | if (err) { | ||
84 | printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu); | ||
85 | printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n"); | ||
86 | printf("or you are not root, or the msr driver is not present\n"); | ||
87 | return 1; | ||
88 | } | ||
89 | |||
90 | decode(lo); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int main (int argc, char **argv) | ||
96 | { | ||
97 | unsigned int cpu, mode = 0; | ||
98 | |||
99 | if (argc < 2) | ||
100 | cpu = 0; | ||
101 | else { | ||
102 | cpu = strtoul(argv[1], NULL, 0); | ||
103 | if (cpu >= MCPU) | ||
104 | mode = 1; | ||
105 | } | ||
106 | |||
107 | if (mode) | ||
108 | decode(cpu); | ||
109 | else | ||
110 | decode_live(cpu); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c new file mode 100644 index 000000000000..8d6a47514253 --- /dev/null +++ b/tools/power/cpupower/debug/i386/dump_psb.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * dump_psb. (c) 2004, Dave Jones, Red Hat Inc. | ||
3 | * Licensed under the GPL v2. | ||
4 | */ | ||
5 | |||
6 | #include <fcntl.h> | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | #include <unistd.h> | ||
11 | |||
12 | #define _GNU_SOURCE | ||
13 | #include <getopt.h> | ||
14 | |||
15 | #include <sys/mman.h> | ||
16 | |||
17 | #define LEN (0x100000 - 0xc0000) | ||
18 | #define OFFSET (0xc0000) | ||
19 | |||
20 | #ifndef __packed | ||
21 | #define __packed __attribute((packed)) | ||
22 | #endif | ||
23 | |||
24 | static long relevant; | ||
25 | |||
26 | static const int fid_to_mult[32] = { | ||
27 | 110, 115, 120, 125, 50, 55, 60, 65, | ||
28 | 70, 75, 80, 85, 90, 95, 100, 105, | ||
29 | 30, 190, 40, 200, 130, 135, 140, 210, | ||
30 | 150, 225, 160, 165, 170, 180, -1, -1, | ||
31 | }; | ||
32 | |||
33 | static const int vid_to_voltage[32] = { | ||
34 | 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, | ||
35 | 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, | ||
36 | 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, | ||
37 | 1075, 1050, 1024, 1000, 975, 950, 925, 0, | ||
38 | }; | ||
39 | |||
40 | struct psb_header { | ||
41 | char signature[10]; | ||
42 | u_char version; | ||
43 | u_char flags; | ||
44 | u_short settlingtime; | ||
45 | u_char res1; | ||
46 | u_char numpst; | ||
47 | } __packed; | ||
48 | |||
49 | struct pst_header { | ||
50 | u_int32_t cpuid; | ||
51 | u_char fsb; | ||
52 | u_char maxfid; | ||
53 | u_char startvid; | ||
54 | u_char numpstates; | ||
55 | } __packed; | ||
56 | |||
57 | static u_int fsb; | ||
58 | static u_int sgtc; | ||
59 | |||
60 | static int | ||
61 | decode_pst(char *p, int npstates) | ||
62 | { | ||
63 | int i; | ||
64 | int freq, fid, vid; | ||
65 | |||
66 | for (i = 0; i < npstates; ++i) { | ||
67 | fid = *p++; | ||
68 | vid = *p++; | ||
69 | freq = 100 * fid_to_mult[fid] * fsb; | ||
70 | |||
71 | printf(" %2d %8dkHz FID %02x (%2d.%01d) VID %02x (%4dmV)\n", | ||
72 | i, | ||
73 | freq, | ||
74 | fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, | ||
75 | vid, vid_to_voltage[vid]); | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static | ||
82 | void decode_psb(char *p, int numpst) | ||
83 | { | ||
84 | int i; | ||
85 | struct psb_header *psb; | ||
86 | struct pst_header *pst; | ||
87 | |||
88 | psb = (struct psb_header*) p; | ||
89 | |||
90 | if (psb->version != 0x12) | ||
91 | return; | ||
92 | |||
93 | printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n", | ||
94 | psb->version, | ||
95 | psb->flags, | ||
96 | psb->settlingtime, | ||
97 | psb->res1, | ||
98 | psb->numpst); | ||
99 | sgtc = psb->settlingtime * 100; | ||
100 | |||
101 | if (sgtc < 10000) | ||
102 | sgtc = 10000; | ||
103 | |||
104 | p = ((char *) psb) + sizeof(struct psb_header); | ||
105 | |||
106 | if (numpst < 0) | ||
107 | numpst = psb->numpst; | ||
108 | else | ||
109 | printf("Overriding number of pst :%d\n", numpst); | ||
110 | |||
111 | for (i = 0; i < numpst; i++) { | ||
112 | pst = (struct pst_header*) p; | ||
113 | |||
114 | if (relevant != 0) { | ||
115 | if (relevant!= pst->cpuid) | ||
116 | goto next_one; | ||
117 | } | ||
118 | |||
119 | printf(" PST %d cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n", | ||
120 | i+1, | ||
121 | pst->cpuid, | ||
122 | pst->fsb, | ||
123 | pst->maxfid, | ||
124 | pst->startvid, | ||
125 | pst->numpstates); | ||
126 | |||
127 | fsb = pst->fsb; | ||
128 | decode_pst(p + sizeof(struct pst_header), pst->numpstates); | ||
129 | |||
130 | next_one: | ||
131 | p += sizeof(struct pst_header) + 2*pst->numpstates; | ||
132 | } | ||
133 | |||
134 | } | ||
135 | |||
136 | static struct option info_opts[] = { | ||
137 | {.name = "numpst", .has_arg=no_argument, .flag=NULL, .val='n'}, | ||
138 | }; | ||
139 | |||
140 | void print_help(void) | ||
141 | { | ||
142 | printf ("Usage: dump_psb [options]\n"); | ||
143 | printf ("Options:\n"); | ||
144 | printf (" -n, --numpst Set number of PST tables to scan\n"); | ||
145 | printf (" -r, --relevant Only display PSTs relevant to cpuid N\n"); | ||
146 | } | ||
147 | |||
148 | int | ||
149 | main(int argc, char *argv[]) | ||
150 | { | ||
151 | int fd; | ||
152 | int numpst=-1; | ||
153 | int ret=0, cont=1; | ||
154 | char *mem = NULL; | ||
155 | char *p; | ||
156 | |||
157 | do { | ||
158 | ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL); | ||
159 | switch (ret){ | ||
160 | case '?': | ||
161 | case 'h': | ||
162 | print_help(); | ||
163 | cont = 0; | ||
164 | break; | ||
165 | case 'r': | ||
166 | relevant = strtol(optarg, NULL, 16); | ||
167 | break; | ||
168 | case 'n': | ||
169 | numpst = strtol(optarg, NULL, 10); | ||
170 | break; | ||
171 | case -1: | ||
172 | cont = 0; | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | } while(cont); | ||
177 | |||
178 | fd = open("/dev/mem", O_RDONLY); | ||
179 | if (fd < 0) { | ||
180 | printf ("Couldn't open /dev/mem. Are you root?\n"); | ||
181 | exit(1); | ||
182 | } | ||
183 | |||
184 | mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); | ||
185 | close(fd); | ||
186 | |||
187 | for (p = mem; p - mem < LEN; p+=16) { | ||
188 | if (memcmp(p, "AMDK7PNOW!", 10) == 0) { | ||
189 | decode_psb(p, numpst); | ||
190 | break; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | munmap(mem, LEN); | ||
195 | return 0; | ||
196 | } | ||
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c new file mode 100644 index 000000000000..53f5293c9c9a --- /dev/null +++ b/tools/power/cpupower/debug/i386/intel_gsic.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * (C) 2003 Bruno Ducrot | ||
3 | * (C) 2004 Dominik Brodowski <linux@dominikbrodowski.de> | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | * | ||
7 | * Based on code found in | ||
8 | * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c | ||
9 | * and originally developed by Andy Grover <andrew.grover@intel.com> | ||
10 | */ | ||
11 | |||
12 | #include <stdio.h> | ||
13 | #include <string.h> | ||
14 | #include <lrmi.h> | ||
15 | |||
16 | int main (void) | ||
17 | { | ||
18 | struct LRMI_regs r; | ||
19 | int retval; | ||
20 | |||
21 | if (!LRMI_init()) | ||
22 | return 0; | ||
23 | |||
24 | memset(&r, 0, sizeof(r)); | ||
25 | |||
26 | r.eax = 0x0000E980; | ||
27 | r.edx = 0x47534943; | ||
28 | |||
29 | retval = LRMI_int(0x15, &r); | ||
30 | |||
31 | if (!retval) { | ||
32 | printf("Failed!\n"); | ||
33 | return 0; | ||
34 | } | ||
35 | if (r.eax == 0x47534943) { | ||
36 | printf("BIOS supports GSIC call:\n"); | ||
37 | printf("\tsignature: %c%c%c%c\n", | ||
38 | (r.eax >> 24) & 0xff, | ||
39 | (r.eax >> 16) & 0xff, | ||
40 | (r.eax >> 8) & 0xff, | ||
41 | (r.eax) & 0xff); | ||
42 | printf("\tcommand port = 0x%.4x\n", | ||
43 | r.ebx & 0xffff); | ||
44 | printf("\tcommand = 0x%.4x\n", | ||
45 | (r.ebx >> 16) & 0xffff); | ||
46 | printf("\tevent port = 0x%.8x\n", r.ecx); | ||
47 | printf("\tflags = 0x%.8x\n", r.edx); | ||
48 | if (((r.ebx >> 16) & 0xffff) != 0x82) { | ||
49 | printf("non-default command value. If speedstep-smi " | ||
50 | "doesn't work out of the box,\nyou may want to " | ||
51 | "try out the default value by passing " | ||
52 | "smi_cmd=0x82 to the module\n ON YOUR OWN " | ||
53 | "RISK.\n"); | ||
54 | } | ||
55 | if ((r.ebx & 0xffff) != 0xb2) { | ||
56 | printf("non-default command port. If speedstep-smi " | ||
57 | "doesn't work out of the box,\nyou may want to " | ||
58 | "try out the default value by passing " | ||
59 | "smi_port=0x82 to the module\n ON YOUR OWN " | ||
60 | "RISK.\n"); | ||
61 | } | ||
62 | } else { | ||
63 | printf("BIOS DOES NOT support GSIC call. Dumping registers anyway:\n"); | ||
64 | printf("eax = 0x%.8x\n", r.eax); | ||
65 | printf("ebx = 0x%.8x\n", r.ebx); | ||
66 | printf("ecx = 0x%.8x\n", r.ecx); | ||
67 | printf("edx = 0x%.8x\n", r.edx); | ||
68 | printf("Note also that some BIOS do not support the initial " | ||
69 | "GSIC call, but the newer\nspeeedstep-smi driver may " | ||
70 | "work.\nFor this, you need to pass some arguments to " | ||
71 | "the speedstep-smi driver:\n"); | ||
72 | printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n"); | ||
73 | printf("\nUnfortunately, you have to know what exactly are " | ||
74 | "smi_cmd and smi_port, and this\nis system " | ||
75 | "dependant.\n"); | ||
76 | } | ||
77 | return 1; | ||
78 | } | ||
diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c new file mode 100644 index 000000000000..638a6b3bfd97 --- /dev/null +++ b/tools/power/cpupower/debug/i386/powernow-k8-decode.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * (C) 2004 Bruno Ducrot <ducrot@poupinou.org> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on code found in | ||
7 | * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c | ||
8 | * and originally developed by Paul Devriendt | ||
9 | */ | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <stdint.h> | ||
14 | #include <unistd.h> | ||
15 | #include <errno.h> | ||
16 | #include <fcntl.h> | ||
17 | |||
18 | #include <sys/types.h> | ||
19 | #include <sys/stat.h> | ||
20 | |||
21 | #define MCPU 32 | ||
22 | |||
23 | #define MSR_FIDVID_STATUS 0xc0010042 | ||
24 | |||
25 | #define MSR_S_HI_CURRENT_VID 0x0000001f | ||
26 | #define MSR_S_LO_CURRENT_FID 0x0000003f | ||
27 | |||
28 | static int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid) | ||
29 | { | ||
30 | int err = 1; | ||
31 | uint64_t msr = 0; | ||
32 | int fd; | ||
33 | char file[20]; | ||
34 | |||
35 | if (cpu > MCPU) | ||
36 | goto out; | ||
37 | |||
38 | sprintf(file, "/dev/cpu/%d/msr", cpu); | ||
39 | |||
40 | fd = open(file, O_RDONLY); | ||
41 | if (fd < 0) | ||
42 | goto out; | ||
43 | lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR); | ||
44 | if (read(fd, &msr, 8) != 8) | ||
45 | goto err1; | ||
46 | |||
47 | *fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID; | ||
48 | *vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID; | ||
49 | err = 0; | ||
50 | err1: | ||
51 | close(fd); | ||
52 | out: | ||
53 | return err; | ||
54 | } | ||
55 | |||
56 | |||
57 | /* Return a frequency in MHz, given an input fid */ | ||
58 | static uint32_t find_freq_from_fid(uint32_t fid) | ||
59 | { | ||
60 | return 800 + (fid * 100); | ||
61 | } | ||
62 | |||
63 | /* Return a voltage in miliVolts, given an input vid */ | ||
64 | static uint32_t find_millivolts_from_vid(uint32_t vid) | ||
65 | { | ||
66 | return 1550-vid*25; | ||
67 | } | ||
68 | |||
69 | int main (int argc, char *argv[]) | ||
70 | { | ||
71 | int err; | ||
72 | int cpu; | ||
73 | uint32_t fid, vid; | ||
74 | |||
75 | if (argc < 2) | ||
76 | cpu = 0; | ||
77 | else | ||
78 | cpu = strtoul(argv[1], NULL, 0); | ||
79 | |||
80 | err = get_fidvid(cpu, &fid, &vid); | ||
81 | |||
82 | if (err) { | ||
83 | printf("can't get fid, vid from MSR\n"); | ||
84 | printf("Possible trouble: you don't run a powernow-k8 capable cpu\n"); | ||
85 | printf("or you are not root, or the msr driver is not present\n"); | ||
86 | exit(1); | ||
87 | } | ||
88 | |||
89 | |||
90 | printf("cpu %d currently at %d MHz and %d mV\n", | ||
91 | cpu, | ||
92 | find_freq_from_fid(fid), | ||
93 | find_millivolts_from_vid(vid)); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile new file mode 100644 index 000000000000..96b146fe6f8d --- /dev/null +++ b/tools/power/cpupower/debug/kernel/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | obj-m := | ||
2 | |||
3 | KDIR := /lib/modules/$(shell uname -r)/build | ||
4 | PWD := $(shell pwd) | ||
5 | KMISC := /lib/modules/$(shell uname -r)/cpufrequtils/ | ||
6 | |||
7 | ifeq ("$(CONFIG_X86_TSC)", "y") | ||
8 | obj-m += cpufreq-test_tsc.o | ||
9 | endif | ||
10 | |||
11 | default: | ||
12 | $(MAKE) -C $(KDIR) M=$(PWD) | ||
13 | |||
14 | clean: | ||
15 | - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c | ||
16 | - rm -rf .tmp_versions* Module.symvers modules.order | ||
17 | |||
18 | install: default | ||
19 | install -d $(KMISC) | ||
20 | install -m 644 -c *.ko $(KMISC) | ||
21 | /sbin/depmod -a | ||
22 | |||
23 | all: default | ||
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c new file mode 100644 index 000000000000..66cace601e57 --- /dev/null +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * test module to check whether the TSC-based delay routine continues | ||
3 | * to work properly after cpufreq transitions. Needs ACPI to work | ||
4 | * properly. | ||
5 | * | ||
6 | * Based partly on the Power Management Timer (PMTMR) code to be found | ||
7 | * in arch/i386/kernel/timers/timer_pm.c on recent 2.6. kernels, especially | ||
8 | * code written by John Stultz. The read_pmtmr function was copied verbatim | ||
9 | * from that file. | ||
10 | * | ||
11 | * (C) 2004 Dominik Brodowski | ||
12 | * | ||
13 | * To use: | ||
14 | * 1.) pass clock=tsc to the kernel on your bootloader | ||
15 | * 2.) modprobe this module (it'll fail) | ||
16 | * 3.) change CPU frequency | ||
17 | * 4.) modprobe this module again | ||
18 | * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the | ||
19 | * TSC-based delay routine on the Linux kernel does not correctly | ||
20 | * handle the cpufreq transition. Please report this to | ||
21 | * cpufreq@vger.kernel.org | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | |||
31 | #include <acpi/acpi_bus.h> | ||
32 | #include <acpi/acpi_drivers.h> | ||
33 | |||
34 | static int pm_tmr_ioport = 0; | ||
35 | |||
36 | /*helper function to safely read acpi pm timesource*/ | ||
37 | static u32 read_pmtmr(void) | ||
38 | { | ||
39 | u32 v1=0,v2=0,v3=0; | ||
40 | /* It has been reported that because of various broken | ||
41 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time | ||
42 | * source is not latched, so you must read it multiple | ||
43 | * times to insure a safe value is read. | ||
44 | */ | ||
45 | do { | ||
46 | v1 = inl(pm_tmr_ioport); | ||
47 | v2 = inl(pm_tmr_ioport); | ||
48 | v3 = inl(pm_tmr_ioport); | ||
49 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | ||
50 | || (v3 > v1 && v3 < v2)); | ||
51 | |||
52 | /* mask the output to 24 bits */ | ||
53 | return (v2 & 0xFFFFFF); | ||
54 | } | ||
55 | |||
56 | static int __init cpufreq_test_tsc(void) | ||
57 | { | ||
58 | u32 now, then, diff; | ||
59 | u64 now_tsc, then_tsc, diff_tsc; | ||
60 | int i; | ||
61 | |||
62 | /* the following code snipped is copied from arch/x86/kernel/acpi/boot.c | ||
63 | of Linux v2.6.25. */ | ||
64 | |||
65 | /* detect the location of the ACPI PM Timer */ | ||
66 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { | ||
67 | /* FADT rev. 2 */ | ||
68 | if (acpi_gbl_FADT.xpm_timer_block.space_id != | ||
69 | ACPI_ADR_SPACE_SYSTEM_IO) | ||
70 | return 0; | ||
71 | |||
72 | pm_tmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; | ||
73 | /* | ||
74 | * "X" fields are optional extensions to the original V1.0 | ||
75 | * fields, so we must selectively expand V1.0 fields if the | ||
76 | * corresponding X field is zero. | ||
77 | */ | ||
78 | if (!pm_tmr_ioport) | ||
79 | pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; | ||
80 | } else { | ||
81 | /* FADT rev. 1 */ | ||
82 | pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; | ||
83 | } | ||
84 | |||
85 | printk(KERN_DEBUG "start--> \n"); | ||
86 | then = read_pmtmr(); | ||
87 | rdtscll(then_tsc); | ||
88 | for (i=0;i<20;i++) { | ||
89 | mdelay(100); | ||
90 | now = read_pmtmr(); | ||
91 | rdtscll(now_tsc); | ||
92 | diff = (now - then) & 0xFFFFFF; | ||
93 | diff_tsc = now_tsc - then_tsc; | ||
94 | printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc); | ||
95 | then = now; | ||
96 | then_tsc = now_tsc; | ||
97 | } | ||
98 | printk(KERN_DEBUG "<-- end \n"); | ||
99 | return -ENODEV; | ||
100 | } | ||
101 | |||
102 | static void __exit cpufreq_none(void) | ||
103 | { | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | module_init(cpufreq_test_tsc) | ||
108 | module_exit(cpufreq_none) | ||
109 | |||
110 | |||
111 | MODULE_AUTHOR("Dominik Brodowski"); | ||
112 | MODULE_DESCRIPTION("Verify the TSC cpufreq notifier working correctly -- needs ACPI-enabled system"); | ||
113 | MODULE_LICENSE ("GPL"); | ||
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile new file mode 100644 index 000000000000..3326217dd311 --- /dev/null +++ b/tools/power/cpupower/debug/x86_64/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | default: all | ||
2 | |||
3 | centrino-decode: ../i386/centrino-decode.c | ||
4 | $(CC) $(CFLAGS) -o $@ $< | ||
5 | |||
6 | powernow-k8-decode: ../i386/powernow-k8-decode.c | ||
7 | $(CC) $(CFLAGS) -o $@ $< | ||
8 | |||
9 | all: centrino-decode powernow-k8-decode | ||
10 | |||
11 | clean: | ||
12 | rm -rf centrino-decode powernow-k8-decode | ||
13 | |||
14 | .PHONY: all default clean | ||
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c new file mode 100644 index 000000000000..d961101d1cea --- /dev/null +++ b/tools/power/cpupower/lib/cpufreq.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <errno.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | #include "cpufreq.h" | ||
14 | #include "sysfs.h" | ||
15 | |||
16 | int cpufreq_cpu_exists(unsigned int cpu) | ||
17 | { | ||
18 | return sysfs_cpu_exists(cpu); | ||
19 | } | ||
20 | |||
21 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu) | ||
22 | { | ||
23 | return sysfs_get_freq_kernel(cpu); | ||
24 | } | ||
25 | |||
26 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu) | ||
27 | { | ||
28 | return sysfs_get_freq_hardware(cpu); | ||
29 | } | ||
30 | |||
31 | unsigned long cpufreq_get_transition_latency(unsigned int cpu) | ||
32 | { | ||
33 | return sysfs_get_freq_transition_latency(cpu); | ||
34 | } | ||
35 | |||
36 | int cpufreq_get_hardware_limits(unsigned int cpu, | ||
37 | unsigned long *min, | ||
38 | unsigned long *max) | ||
39 | { | ||
40 | if ((!min) || (!max)) | ||
41 | return -EINVAL; | ||
42 | return sysfs_get_freq_hardware_limits(cpu, min, max); | ||
43 | } | ||
44 | |||
45 | char *cpufreq_get_driver(unsigned int cpu) | ||
46 | { | ||
47 | return sysfs_get_freq_driver(cpu); | ||
48 | } | ||
49 | |||
50 | void cpufreq_put_driver(char *ptr) | ||
51 | { | ||
52 | if (!ptr) | ||
53 | return; | ||
54 | free(ptr); | ||
55 | } | ||
56 | |||
57 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) | ||
58 | { | ||
59 | return sysfs_get_freq_policy(cpu); | ||
60 | } | ||
61 | |||
62 | void cpufreq_put_policy(struct cpufreq_policy *policy) | ||
63 | { | ||
64 | if ((!policy) || (!policy->governor)) | ||
65 | return; | ||
66 | |||
67 | free(policy->governor); | ||
68 | policy->governor = NULL; | ||
69 | free(policy); | ||
70 | } | ||
71 | |||
72 | struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned | ||
73 | int cpu) | ||
74 | { | ||
75 | return sysfs_get_freq_available_governors(cpu); | ||
76 | } | ||
77 | |||
78 | void cpufreq_put_available_governors(struct cpufreq_available_governors *any) | ||
79 | { | ||
80 | struct cpufreq_available_governors *tmp, *next; | ||
81 | |||
82 | if (!any) | ||
83 | return; | ||
84 | |||
85 | tmp = any->first; | ||
86 | while (tmp) { | ||
87 | next = tmp->next; | ||
88 | if (tmp->governor) | ||
89 | free(tmp->governor); | ||
90 | free(tmp); | ||
91 | tmp = next; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | struct cpufreq_available_frequencies | ||
97 | *cpufreq_get_available_frequencies(unsigned int cpu) | ||
98 | { | ||
99 | return sysfs_get_available_frequencies(cpu); | ||
100 | } | ||
101 | |||
102 | void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies | ||
103 | *any) { | ||
104 | struct cpufreq_available_frequencies *tmp, *next; | ||
105 | |||
106 | if (!any) | ||
107 | return; | ||
108 | |||
109 | tmp = any->first; | ||
110 | while (tmp) { | ||
111 | next = tmp->next; | ||
112 | free(tmp); | ||
113 | tmp = next; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) | ||
119 | { | ||
120 | return sysfs_get_freq_affected_cpus(cpu); | ||
121 | } | ||
122 | |||
123 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) | ||
124 | { | ||
125 | struct cpufreq_affected_cpus *tmp, *next; | ||
126 | |||
127 | if (!any) | ||
128 | return; | ||
129 | |||
130 | tmp = any->first; | ||
131 | while (tmp) { | ||
132 | next = tmp->next; | ||
133 | free(tmp); | ||
134 | tmp = next; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | |||
139 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) | ||
140 | { | ||
141 | return sysfs_get_freq_related_cpus(cpu); | ||
142 | } | ||
143 | |||
144 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) | ||
145 | { | ||
146 | cpufreq_put_affected_cpus(any); | ||
147 | } | ||
148 | |||
149 | |||
150 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) | ||
151 | { | ||
152 | if (!policy || !(policy->governor)) | ||
153 | return -EINVAL; | ||
154 | |||
155 | return sysfs_set_freq_policy(cpu, policy); | ||
156 | } | ||
157 | |||
158 | |||
159 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) | ||
160 | { | ||
161 | return sysfs_modify_freq_policy_min(cpu, min_freq); | ||
162 | } | ||
163 | |||
164 | |||
165 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) | ||
166 | { | ||
167 | return sysfs_modify_freq_policy_max(cpu, max_freq); | ||
168 | } | ||
169 | |||
170 | |||
171 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) | ||
172 | { | ||
173 | if ((!governor) || (strlen(governor) > 19)) | ||
174 | return -EINVAL; | ||
175 | |||
176 | return sysfs_modify_freq_policy_governor(cpu, governor); | ||
177 | } | ||
178 | |||
179 | int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) | ||
180 | { | ||
181 | return sysfs_set_frequency(cpu, target_frequency); | ||
182 | } | ||
183 | |||
184 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | ||
185 | unsigned long long *total_time) | ||
186 | { | ||
187 | return sysfs_get_freq_stats(cpu, total_time); | ||
188 | } | ||
189 | |||
190 | void cpufreq_put_stats(struct cpufreq_stats *any) | ||
191 | { | ||
192 | struct cpufreq_stats *tmp, *next; | ||
193 | |||
194 | if (!any) | ||
195 | return; | ||
196 | |||
197 | tmp = any->first; | ||
198 | while (tmp) { | ||
199 | next = tmp->next; | ||
200 | free(tmp); | ||
201 | tmp = next; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | unsigned long cpufreq_get_transitions(unsigned int cpu) | ||
206 | { | ||
207 | return sysfs_get_freq_transitions(cpu); | ||
208 | } | ||
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h new file mode 100644 index 000000000000..3aae8e7a0839 --- /dev/null +++ b/tools/power/cpupower/lib/cpufreq.h | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * cpufreq.h - definitions for libcpufreq | ||
3 | * | ||
4 | * Copyright (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation, version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #ifndef _CPUFREQ_H | ||
21 | #define _CPUFREQ_H 1 | ||
22 | |||
23 | struct cpufreq_policy { | ||
24 | unsigned long min; | ||
25 | unsigned long max; | ||
26 | char *governor; | ||
27 | }; | ||
28 | |||
29 | struct cpufreq_available_governors { | ||
30 | char *governor; | ||
31 | struct cpufreq_available_governors *next; | ||
32 | struct cpufreq_available_governors *first; | ||
33 | }; | ||
34 | |||
35 | struct cpufreq_available_frequencies { | ||
36 | unsigned long frequency; | ||
37 | struct cpufreq_available_frequencies *next; | ||
38 | struct cpufreq_available_frequencies *first; | ||
39 | }; | ||
40 | |||
41 | |||
42 | struct cpufreq_affected_cpus { | ||
43 | unsigned int cpu; | ||
44 | struct cpufreq_affected_cpus *next; | ||
45 | struct cpufreq_affected_cpus *first; | ||
46 | }; | ||
47 | |||
48 | struct cpufreq_stats { | ||
49 | unsigned long frequency; | ||
50 | unsigned long long time_in_state; | ||
51 | struct cpufreq_stats *next; | ||
52 | struct cpufreq_stats *first; | ||
53 | }; | ||
54 | |||
55 | |||
56 | |||
57 | #ifdef __cplusplus | ||
58 | extern "C" { | ||
59 | #endif | ||
60 | |||
61 | /* | ||
62 | * returns 0 if the specified CPU is present (it doesn't say | ||
63 | * whether it is online!), and an error value if not. | ||
64 | */ | ||
65 | |||
66 | extern int cpufreq_cpu_exists(unsigned int cpu); | ||
67 | |||
68 | /* determine current CPU frequency | ||
69 | * - _kernel variant means kernel's opinion of CPU frequency | ||
70 | * - _hardware variant means actual hardware CPU frequency, | ||
71 | * which is only available to root. | ||
72 | * | ||
73 | * returns 0 on failure, else frequency in kHz. | ||
74 | */ | ||
75 | |||
76 | extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu); | ||
77 | |||
78 | extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); | ||
79 | |||
80 | #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); | ||
81 | |||
82 | |||
83 | /* determine CPU transition latency | ||
84 | * | ||
85 | * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds | ||
86 | */ | ||
87 | extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); | ||
88 | |||
89 | |||
90 | /* determine hardware CPU frequency limits | ||
91 | * | ||
92 | * These may be limited further by thermal, energy or other | ||
93 | * considerations by cpufreq policy notifiers in the kernel. | ||
94 | */ | ||
95 | |||
96 | extern int cpufreq_get_hardware_limits(unsigned int cpu, | ||
97 | unsigned long *min, | ||
98 | unsigned long *max); | ||
99 | |||
100 | |||
101 | /* determine CPUfreq driver used | ||
102 | * | ||
103 | * Remember to call cpufreq_put_driver when no longer needed | ||
104 | * to avoid memory leakage, please. | ||
105 | */ | ||
106 | |||
107 | extern char *cpufreq_get_driver(unsigned int cpu); | ||
108 | |||
109 | extern void cpufreq_put_driver(char *ptr); | ||
110 | |||
111 | |||
112 | /* determine CPUfreq policy currently used | ||
113 | * | ||
114 | * Remember to call cpufreq_put_policy when no longer needed | ||
115 | * to avoid memory leakage, please. | ||
116 | */ | ||
117 | |||
118 | |||
119 | extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); | ||
120 | |||
121 | extern void cpufreq_put_policy(struct cpufreq_policy *policy); | ||
122 | |||
123 | |||
124 | /* determine CPUfreq governors currently available | ||
125 | * | ||
126 | * may be modified by modprobe'ing or rmmod'ing other governors. Please | ||
127 | * free allocated memory by calling cpufreq_put_available_governors | ||
128 | * after use. | ||
129 | */ | ||
130 | |||
131 | |||
132 | extern struct cpufreq_available_governors | ||
133 | *cpufreq_get_available_governors(unsigned int cpu); | ||
134 | |||
135 | extern void cpufreq_put_available_governors( | ||
136 | struct cpufreq_available_governors *first); | ||
137 | |||
138 | |||
139 | /* determine CPU frequency states available | ||
140 | * | ||
141 | * Only present on _some_ ->target() cpufreq drivers. For information purposes | ||
142 | * only. Please free allocated memory by calling | ||
143 | * cpufreq_put_available_frequencies after use. | ||
144 | */ | ||
145 | |||
146 | extern struct cpufreq_available_frequencies | ||
147 | *cpufreq_get_available_frequencies(unsigned int cpu); | ||
148 | |||
149 | extern void cpufreq_put_available_frequencies( | ||
150 | struct cpufreq_available_frequencies *first); | ||
151 | |||
152 | |||
153 | /* determine affected CPUs | ||
154 | * | ||
155 | * Remember to call cpufreq_put_affected_cpus when no longer needed | ||
156 | * to avoid memory leakage, please. | ||
157 | */ | ||
158 | |||
159 | extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned | ||
160 | int cpu); | ||
161 | |||
162 | extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); | ||
163 | |||
164 | |||
165 | /* determine related CPUs | ||
166 | * | ||
167 | * Remember to call cpufreq_put_related_cpus when no longer needed | ||
168 | * to avoid memory leakage, please. | ||
169 | */ | ||
170 | |||
171 | extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned | ||
172 | int cpu); | ||
173 | |||
174 | extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); | ||
175 | |||
176 | |||
177 | /* determine stats for cpufreq subsystem | ||
178 | * | ||
179 | * This is not available in all kernel versions or configurations. | ||
180 | */ | ||
181 | |||
182 | extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | ||
183 | unsigned long long *total_time); | ||
184 | |||
185 | extern void cpufreq_put_stats(struct cpufreq_stats *stats); | ||
186 | |||
187 | extern unsigned long cpufreq_get_transitions(unsigned int cpu); | ||
188 | |||
189 | |||
190 | /* set new cpufreq policy | ||
191 | * | ||
192 | * Tries to set the passed policy as new policy as close as possible, | ||
193 | * but results may differ depending e.g. on governors being available. | ||
194 | */ | ||
195 | |||
196 | extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); | ||
197 | |||
198 | |||
199 | /* modify a policy by only changing min/max freq or governor | ||
200 | * | ||
201 | * Does not check whether result is what was intended. | ||
202 | */ | ||
203 | |||
204 | extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); | ||
205 | extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); | ||
206 | extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); | ||
207 | |||
208 | |||
209 | /* set a specific frequency | ||
210 | * | ||
211 | * Does only work if userspace governor can be used and no external | ||
212 | * interference (other calls to this function or to set/modify_policy) | ||
213 | * occurs. Also does not work on ->range() cpufreq drivers. | ||
214 | */ | ||
215 | |||
216 | extern int cpufreq_set_frequency(unsigned int cpu, | ||
217 | unsigned long target_frequency); | ||
218 | |||
219 | #ifdef __cplusplus | ||
220 | } | ||
221 | #endif | ||
222 | |||
223 | #endif /* _CPUFREQ_H */ | ||
diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c new file mode 100644 index 000000000000..870713a75a81 --- /dev/null +++ b/tools/power/cpupower/lib/sysfs.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <errno.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <limits.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "cpufreq.h" | ||
18 | |||
19 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
20 | #define MAX_LINE_LEN 4096 | ||
21 | #define SYSFS_PATH_MAX 255 | ||
22 | |||
23 | |||
24 | static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
25 | { | ||
26 | int fd; | ||
27 | ssize_t numread; | ||
28 | |||
29 | fd = open(path, O_RDONLY); | ||
30 | if (fd == -1) | ||
31 | return 0; | ||
32 | |||
33 | numread = read(fd, buf, buflen - 1); | ||
34 | if (numread < 1) { | ||
35 | close(fd); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | buf[numread] = '\0'; | ||
40 | close(fd); | ||
41 | |||
42 | return (unsigned int) numread; | ||
43 | } | ||
44 | |||
45 | |||
46 | /* CPUFREQ sysfs access **************************************************/ | ||
47 | |||
48 | /* helper function to read file from /sys into given buffer */ | ||
49 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
50 | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | ||
51 | char *buf, size_t buflen) | ||
52 | { | ||
53 | char path[SYSFS_PATH_MAX]; | ||
54 | |||
55 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
56 | cpu, fname); | ||
57 | return sysfs_read_file(path, buf, buflen); | ||
58 | } | ||
59 | |||
60 | /* helper function to write a new value to a /sys file */ | ||
61 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
62 | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | ||
63 | const char *fname, | ||
64 | const char *value, size_t len) | ||
65 | { | ||
66 | char path[SYSFS_PATH_MAX]; | ||
67 | int fd; | ||
68 | ssize_t numwrite; | ||
69 | |||
70 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
71 | cpu, fname); | ||
72 | |||
73 | fd = open(path, O_WRONLY); | ||
74 | if (fd == -1) | ||
75 | return 0; | ||
76 | |||
77 | numwrite = write(fd, value, len); | ||
78 | if (numwrite < 1) { | ||
79 | close(fd); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | close(fd); | ||
84 | |||
85 | return (unsigned int) numwrite; | ||
86 | } | ||
87 | |||
88 | /* read access to files which contain one numeric value */ | ||
89 | |||
90 | enum cpufreq_value { | ||
91 | CPUINFO_CUR_FREQ, | ||
92 | CPUINFO_MIN_FREQ, | ||
93 | CPUINFO_MAX_FREQ, | ||
94 | CPUINFO_LATENCY, | ||
95 | SCALING_CUR_FREQ, | ||
96 | SCALING_MIN_FREQ, | ||
97 | SCALING_MAX_FREQ, | ||
98 | STATS_NUM_TRANSITIONS, | ||
99 | MAX_CPUFREQ_VALUE_READ_FILES | ||
100 | }; | ||
101 | |||
102 | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | ||
103 | [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | ||
104 | [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | ||
105 | [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | ||
106 | [CPUINFO_LATENCY] = "cpuinfo_transition_latency", | ||
107 | [SCALING_CUR_FREQ] = "scaling_cur_freq", | ||
108 | [SCALING_MIN_FREQ] = "scaling_min_freq", | ||
109 | [SCALING_MAX_FREQ] = "scaling_max_freq", | ||
110 | [STATS_NUM_TRANSITIONS] = "stats/total_trans" | ||
111 | }; | ||
112 | |||
113 | |||
114 | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | ||
115 | enum cpufreq_value which) | ||
116 | { | ||
117 | unsigned long value; | ||
118 | unsigned int len; | ||
119 | char linebuf[MAX_LINE_LEN]; | ||
120 | char *endp; | ||
121 | |||
122 | if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | ||
123 | return 0; | ||
124 | |||
125 | len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | ||
126 | linebuf, sizeof(linebuf)); | ||
127 | |||
128 | if (len == 0) | ||
129 | return 0; | ||
130 | |||
131 | value = strtoul(linebuf, &endp, 0); | ||
132 | |||
133 | if (endp == linebuf || errno == ERANGE) | ||
134 | return 0; | ||
135 | |||
136 | return value; | ||
137 | } | ||
138 | |||
139 | /* read access to files which contain one string */ | ||
140 | |||
141 | enum cpufreq_string { | ||
142 | SCALING_DRIVER, | ||
143 | SCALING_GOVERNOR, | ||
144 | MAX_CPUFREQ_STRING_FILES | ||
145 | }; | ||
146 | |||
147 | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | ||
148 | [SCALING_DRIVER] = "scaling_driver", | ||
149 | [SCALING_GOVERNOR] = "scaling_governor", | ||
150 | }; | ||
151 | |||
152 | |||
153 | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | ||
154 | enum cpufreq_string which) | ||
155 | { | ||
156 | char linebuf[MAX_LINE_LEN]; | ||
157 | char *result; | ||
158 | unsigned int len; | ||
159 | |||
160 | if (which >= MAX_CPUFREQ_STRING_FILES) | ||
161 | return NULL; | ||
162 | |||
163 | len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | ||
164 | linebuf, sizeof(linebuf)); | ||
165 | if (len == 0) | ||
166 | return NULL; | ||
167 | |||
168 | result = strdup(linebuf); | ||
169 | if (result == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | if (result[strlen(result) - 1] == '\n') | ||
173 | result[strlen(result) - 1] = '\0'; | ||
174 | |||
175 | return result; | ||
176 | } | ||
177 | |||
178 | /* write access */ | ||
179 | |||
180 | enum cpufreq_write { | ||
181 | WRITE_SCALING_MIN_FREQ, | ||
182 | WRITE_SCALING_MAX_FREQ, | ||
183 | WRITE_SCALING_GOVERNOR, | ||
184 | WRITE_SCALING_SET_SPEED, | ||
185 | MAX_CPUFREQ_WRITE_FILES | ||
186 | }; | ||
187 | |||
188 | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | ||
189 | [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | ||
190 | [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | ||
191 | [WRITE_SCALING_GOVERNOR] = "scaling_governor", | ||
192 | [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | ||
193 | }; | ||
194 | |||
195 | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | ||
196 | enum cpufreq_write which, | ||
197 | const char *new_value, size_t len) | ||
198 | { | ||
199 | if (which >= MAX_CPUFREQ_WRITE_FILES) | ||
200 | return 0; | ||
201 | |||
202 | if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | ||
203 | new_value, len) != len) | ||
204 | return -ENODEV; | ||
205 | |||
206 | return 0; | ||
207 | }; | ||
208 | |||
209 | unsigned long sysfs_get_freq_kernel(unsigned int cpu) | ||
210 | { | ||
211 | return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); | ||
212 | } | ||
213 | |||
214 | unsigned long sysfs_get_freq_hardware(unsigned int cpu) | ||
215 | { | ||
216 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); | ||
217 | } | ||
218 | |||
219 | unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) | ||
220 | { | ||
221 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); | ||
222 | } | ||
223 | |||
224 | int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
225 | unsigned long *min, | ||
226 | unsigned long *max) | ||
227 | { | ||
228 | if ((!min) || (!max)) | ||
229 | return -EINVAL; | ||
230 | |||
231 | *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | ||
232 | if (!*min) | ||
233 | return -ENODEV; | ||
234 | |||
235 | *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | ||
236 | if (!*max) | ||
237 | return -ENODEV; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | char *sysfs_get_freq_driver(unsigned int cpu) | ||
243 | { | ||
244 | return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); | ||
245 | } | ||
246 | |||
247 | struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) | ||
248 | { | ||
249 | struct cpufreq_policy *policy; | ||
250 | |||
251 | policy = malloc(sizeof(struct cpufreq_policy)); | ||
252 | if (!policy) | ||
253 | return NULL; | ||
254 | |||
255 | policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | ||
256 | if (!policy->governor) { | ||
257 | free(policy); | ||
258 | return NULL; | ||
259 | } | ||
260 | policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
261 | policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | ||
262 | if ((!policy->min) || (!policy->max)) { | ||
263 | free(policy->governor); | ||
264 | free(policy); | ||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | return policy; | ||
269 | } | ||
270 | |||
271 | struct cpufreq_available_governors * | ||
272 | sysfs_get_freq_available_governors(unsigned int cpu) { | ||
273 | struct cpufreq_available_governors *first = NULL; | ||
274 | struct cpufreq_available_governors *current = NULL; | ||
275 | char linebuf[MAX_LINE_LEN]; | ||
276 | unsigned int pos, i; | ||
277 | unsigned int len; | ||
278 | |||
279 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | ||
280 | linebuf, sizeof(linebuf)); | ||
281 | if (len == 0) | ||
282 | return NULL; | ||
283 | |||
284 | pos = 0; | ||
285 | for (i = 0; i < len; i++) { | ||
286 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
287 | if (i - pos < 2) | ||
288 | continue; | ||
289 | if (current) { | ||
290 | current->next = malloc(sizeof(*current)); | ||
291 | if (!current->next) | ||
292 | goto error_out; | ||
293 | current = current->next; | ||
294 | } else { | ||
295 | first = malloc(sizeof(*first)); | ||
296 | if (!first) | ||
297 | goto error_out; | ||
298 | current = first; | ||
299 | } | ||
300 | current->first = first; | ||
301 | current->next = NULL; | ||
302 | |||
303 | current->governor = malloc(i - pos + 1); | ||
304 | if (!current->governor) | ||
305 | goto error_out; | ||
306 | |||
307 | memcpy(current->governor, linebuf + pos, i - pos); | ||
308 | current->governor[i - pos] = '\0'; | ||
309 | pos = i + 1; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | return first; | ||
314 | |||
315 | error_out: | ||
316 | while (first) { | ||
317 | current = first->next; | ||
318 | if (first->governor) | ||
319 | free(first->governor); | ||
320 | free(first); | ||
321 | first = current; | ||
322 | } | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | |||
327 | struct cpufreq_available_frequencies * | ||
328 | sysfs_get_available_frequencies(unsigned int cpu) { | ||
329 | struct cpufreq_available_frequencies *first = NULL; | ||
330 | struct cpufreq_available_frequencies *current = NULL; | ||
331 | char one_value[SYSFS_PATH_MAX]; | ||
332 | char linebuf[MAX_LINE_LEN]; | ||
333 | unsigned int pos, i; | ||
334 | unsigned int len; | ||
335 | |||
336 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | ||
337 | linebuf, sizeof(linebuf)); | ||
338 | if (len == 0) | ||
339 | return NULL; | ||
340 | |||
341 | pos = 0; | ||
342 | for (i = 0; i < len; i++) { | ||
343 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
344 | if (i - pos < 2) | ||
345 | continue; | ||
346 | if (i - pos >= SYSFS_PATH_MAX) | ||
347 | goto error_out; | ||
348 | if (current) { | ||
349 | current->next = malloc(sizeof(*current)); | ||
350 | if (!current->next) | ||
351 | goto error_out; | ||
352 | current = current->next; | ||
353 | } else { | ||
354 | first = malloc(sizeof(*first)); | ||
355 | if (!first) | ||
356 | goto error_out; | ||
357 | current = first; | ||
358 | } | ||
359 | current->first = first; | ||
360 | current->next = NULL; | ||
361 | |||
362 | memcpy(one_value, linebuf + pos, i - pos); | ||
363 | one_value[i - pos] = '\0'; | ||
364 | if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | ||
365 | goto error_out; | ||
366 | |||
367 | pos = i + 1; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | return first; | ||
372 | |||
373 | error_out: | ||
374 | while (first) { | ||
375 | current = first->next; | ||
376 | free(first); | ||
377 | first = current; | ||
378 | } | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | ||
383 | const char *file) | ||
384 | { | ||
385 | struct cpufreq_affected_cpus *first = NULL; | ||
386 | struct cpufreq_affected_cpus *current = NULL; | ||
387 | char one_value[SYSFS_PATH_MAX]; | ||
388 | char linebuf[MAX_LINE_LEN]; | ||
389 | unsigned int pos, i; | ||
390 | unsigned int len; | ||
391 | |||
392 | len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | ||
393 | if (len == 0) | ||
394 | return NULL; | ||
395 | |||
396 | pos = 0; | ||
397 | for (i = 0; i < len; i++) { | ||
398 | if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
399 | if (i - pos < 1) | ||
400 | continue; | ||
401 | if (i - pos >= SYSFS_PATH_MAX) | ||
402 | goto error_out; | ||
403 | if (current) { | ||
404 | current->next = malloc(sizeof(*current)); | ||
405 | if (!current->next) | ||
406 | goto error_out; | ||
407 | current = current->next; | ||
408 | } else { | ||
409 | first = malloc(sizeof(*first)); | ||
410 | if (!first) | ||
411 | goto error_out; | ||
412 | current = first; | ||
413 | } | ||
414 | current->first = first; | ||
415 | current->next = NULL; | ||
416 | |||
417 | memcpy(one_value, linebuf + pos, i - pos); | ||
418 | one_value[i - pos] = '\0'; | ||
419 | |||
420 | if (sscanf(one_value, "%u", ¤t->cpu) != 1) | ||
421 | goto error_out; | ||
422 | |||
423 | pos = i + 1; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | return first; | ||
428 | |||
429 | error_out: | ||
430 | while (first) { | ||
431 | current = first->next; | ||
432 | free(first); | ||
433 | first = current; | ||
434 | } | ||
435 | return NULL; | ||
436 | } | ||
437 | |||
438 | struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) | ||
439 | { | ||
440 | return sysfs_get_cpu_list(cpu, "affected_cpus"); | ||
441 | } | ||
442 | |||
443 | struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) | ||
444 | { | ||
445 | return sysfs_get_cpu_list(cpu, "related_cpus"); | ||
446 | } | ||
447 | |||
448 | struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
449 | unsigned long long *total_time) { | ||
450 | struct cpufreq_stats *first = NULL; | ||
451 | struct cpufreq_stats *current = NULL; | ||
452 | char one_value[SYSFS_PATH_MAX]; | ||
453 | char linebuf[MAX_LINE_LEN]; | ||
454 | unsigned int pos, i; | ||
455 | unsigned int len; | ||
456 | |||
457 | len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | ||
458 | linebuf, sizeof(linebuf)); | ||
459 | if (len == 0) | ||
460 | return NULL; | ||
461 | |||
462 | *total_time = 0; | ||
463 | pos = 0; | ||
464 | for (i = 0; i < len; i++) { | ||
465 | if (i == strlen(linebuf) || linebuf[i] == '\n') { | ||
466 | if (i - pos < 2) | ||
467 | continue; | ||
468 | if ((i - pos) >= SYSFS_PATH_MAX) | ||
469 | goto error_out; | ||
470 | if (current) { | ||
471 | current->next = malloc(sizeof(*current)); | ||
472 | if (!current->next) | ||
473 | goto error_out; | ||
474 | current = current->next; | ||
475 | } else { | ||
476 | first = malloc(sizeof(*first)); | ||
477 | if (!first) | ||
478 | goto error_out; | ||
479 | current = first; | ||
480 | } | ||
481 | current->first = first; | ||
482 | current->next = NULL; | ||
483 | |||
484 | memcpy(one_value, linebuf + pos, i - pos); | ||
485 | one_value[i - pos] = '\0'; | ||
486 | if (sscanf(one_value, "%lu %llu", | ||
487 | ¤t->frequency, | ||
488 | ¤t->time_in_state) != 2) | ||
489 | goto error_out; | ||
490 | |||
491 | *total_time = *total_time + current->time_in_state; | ||
492 | pos = i + 1; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | return first; | ||
497 | |||
498 | error_out: | ||
499 | while (first) { | ||
500 | current = first->next; | ||
501 | free(first); | ||
502 | first = current; | ||
503 | } | ||
504 | return NULL; | ||
505 | } | ||
506 | |||
507 | unsigned long sysfs_get_freq_transitions(unsigned int cpu) | ||
508 | { | ||
509 | return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); | ||
510 | } | ||
511 | |||
512 | static int verify_gov(char *new_gov, char *passed_gov) | ||
513 | { | ||
514 | unsigned int i, j = 0; | ||
515 | |||
516 | if (!passed_gov || (strlen(passed_gov) > 19)) | ||
517 | return -EINVAL; | ||
518 | |||
519 | strncpy(new_gov, passed_gov, 20); | ||
520 | for (i = 0; i < 20; i++) { | ||
521 | if (j) { | ||
522 | new_gov[i] = '\0'; | ||
523 | continue; | ||
524 | } | ||
525 | if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | ||
526 | continue; | ||
527 | |||
528 | if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | ||
529 | continue; | ||
530 | |||
531 | if (new_gov[i] == '-') | ||
532 | continue; | ||
533 | |||
534 | if (new_gov[i] == '_') | ||
535 | continue; | ||
536 | |||
537 | if (new_gov[i] == '\0') { | ||
538 | j = 1; | ||
539 | continue; | ||
540 | } | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | new_gov[19] = '\0'; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) | ||
548 | { | ||
549 | char new_gov[SYSFS_PATH_MAX]; | ||
550 | |||
551 | if (!governor) | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (verify_gov(new_gov, governor)) | ||
555 | return -EINVAL; | ||
556 | |||
557 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
558 | new_gov, strlen(new_gov)); | ||
559 | }; | ||
560 | |||
561 | int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) | ||
562 | { | ||
563 | char value[SYSFS_PATH_MAX]; | ||
564 | |||
565 | snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | ||
566 | |||
567 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
568 | value, strlen(value)); | ||
569 | }; | ||
570 | |||
571 | |||
572 | int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) | ||
573 | { | ||
574 | char value[SYSFS_PATH_MAX]; | ||
575 | |||
576 | snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | ||
577 | |||
578 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | ||
579 | value, strlen(value)); | ||
580 | }; | ||
581 | |||
582 | |||
583 | int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) | ||
584 | { | ||
585 | char min[SYSFS_PATH_MAX]; | ||
586 | char max[SYSFS_PATH_MAX]; | ||
587 | char gov[SYSFS_PATH_MAX]; | ||
588 | int ret; | ||
589 | unsigned long old_min; | ||
590 | int write_max_first; | ||
591 | |||
592 | if (!policy || !(policy->governor)) | ||
593 | return -EINVAL; | ||
594 | |||
595 | if (policy->max < policy->min) | ||
596 | return -EINVAL; | ||
597 | |||
598 | if (verify_gov(gov, policy->governor)) | ||
599 | return -EINVAL; | ||
600 | |||
601 | snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | ||
602 | snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | ||
603 | |||
604 | old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
605 | write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | ||
606 | |||
607 | if (write_max_first) { | ||
608 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
609 | max, strlen(max)); | ||
610 | if (ret) | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | ||
615 | strlen(min)); | ||
616 | if (ret) | ||
617 | return ret; | ||
618 | |||
619 | if (!write_max_first) { | ||
620 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
621 | max, strlen(max)); | ||
622 | if (ret) | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
627 | gov, strlen(gov)); | ||
628 | } | ||
629 | |||
630 | int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) | ||
631 | { | ||
632 | struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); | ||
633 | char userspace_gov[] = "userspace"; | ||
634 | char freq[SYSFS_PATH_MAX]; | ||
635 | int ret; | ||
636 | |||
637 | if (!pol) | ||
638 | return -ENODEV; | ||
639 | |||
640 | if (strncmp(pol->governor, userspace_gov, 9) != 0) { | ||
641 | ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); | ||
642 | if (ret) { | ||
643 | cpufreq_put_policy(pol); | ||
644 | return ret; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | cpufreq_put_policy(pol); | ||
649 | |||
650 | snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | ||
651 | |||
652 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | ||
653 | freq, strlen(freq)); | ||
654 | } | ||
655 | |||
656 | /* CPUFREQ sysfs access **************************************************/ | ||
657 | |||
658 | /* General sysfs access **************************************************/ | ||
659 | int sysfs_cpu_exists(unsigned int cpu) | ||
660 | { | ||
661 | char file[SYSFS_PATH_MAX]; | ||
662 | struct stat statbuf; | ||
663 | |||
664 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); | ||
665 | |||
666 | if (stat(file, &statbuf) != 0) | ||
667 | return -ENOSYS; | ||
668 | |||
669 | return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; | ||
670 | } | ||
671 | |||
672 | /* General sysfs access **************************************************/ | ||
diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h new file mode 100644 index 000000000000..c76a5e0af501 --- /dev/null +++ b/tools/power/cpupower/lib/sysfs.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* General */ | ||
2 | extern unsigned int sysfs_cpu_exists(unsigned int cpu); | ||
3 | |||
4 | /* CPUfreq */ | ||
5 | extern unsigned long sysfs_get_freq_kernel(unsigned int cpu); | ||
6 | extern unsigned long sysfs_get_freq_hardware(unsigned int cpu); | ||
7 | extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu); | ||
8 | extern int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
9 | unsigned long *min, unsigned long *max); | ||
10 | extern char *sysfs_get_freq_driver(unsigned int cpu); | ||
11 | extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu); | ||
12 | extern struct cpufreq_available_governors *sysfs_get_freq_available_governors( | ||
13 | unsigned int cpu); | ||
14 | extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies( | ||
15 | unsigned int cpu); | ||
16 | extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus( | ||
17 | unsigned int cpu); | ||
18 | extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus( | ||
19 | unsigned int cpu); | ||
20 | extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
21 | unsigned long long *total_time); | ||
22 | extern unsigned long sysfs_get_freq_transitions(unsigned int cpu); | ||
23 | extern int sysfs_set_freq_policy(unsigned int cpu, | ||
24 | struct cpufreq_policy *policy); | ||
25 | extern int sysfs_modify_freq_policy_min(unsigned int cpu, | ||
26 | unsigned long min_freq); | ||
27 | extern int sysfs_modify_freq_policy_max(unsigned int cpu, | ||
28 | unsigned long max_freq); | ||
29 | extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor); | ||
30 | extern int sysfs_set_frequency(unsigned int cpu, | ||
31 | unsigned long target_frequency); | ||
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 new file mode 100644 index 000000000000..bb60a8d1e45a --- /dev/null +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 | |||
@@ -0,0 +1,76 @@ | |||
1 | .TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" "" | ||
2 | .SH "NAME" | ||
3 | .LP | ||
4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information | ||
5 | .SH "SYNTAX" | ||
6 | .LP | ||
7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] | ||
8 | .SH "DESCRIPTION" | ||
9 | .LP | ||
10 | A small tool which prints out cpufreq information helpful to developers and interested users. | ||
11 | .SH "OPTIONS" | ||
12 | .LP | ||
13 | .TP | ||
14 | \fB\-e\fR \fB\-\-debug\fR | ||
15 | Prints out debug information. | ||
16 | .TP | ||
17 | \fB\-f\fR \fB\-\-freq\fR | ||
18 | Get frequency the CPU currently runs at, according to the cpufreq core. | ||
19 | .TP | ||
20 | \fB\-w\fR \fB\-\-hwfreq\fR | ||
21 | Get frequency the CPU currently runs at, by reading it from hardware (only available to root). | ||
22 | .TP | ||
23 | \fB\-l\fR \fB\-\-hwlimits\fR | ||
24 | Determine the minimum and maximum CPU frequency allowed. | ||
25 | .TP | ||
26 | \fB\-d\fR \fB\-\-driver\fR | ||
27 | Determines the used cpufreq kernel driver. | ||
28 | .TP | ||
29 | \fB\-p\fR \fB\-\-policy\fR | ||
30 | Gets the currently used cpufreq policy. | ||
31 | .TP | ||
32 | \fB\-g\fR \fB\-\-governors\fR | ||
33 | Determines available cpufreq governors. | ||
34 | .TP | ||
35 | \fB\-a\fR \fB\-\-related\-cpus\fR | ||
36 | Determines which CPUs run at the same hardware frequency. | ||
37 | .TP | ||
38 | \fB\-a\fR \fB\-\-affected\-cpus\fR | ||
39 | Determines which CPUs need to have their frequency coordinated by software. | ||
40 | .TP | ||
41 | \fB\-s\fR \fB\-\-stats\fR | ||
42 | Shows cpufreq statistics if available. | ||
43 | .TP | ||
44 | \fB\-y\fR \fB\-\-latency\fR | ||
45 | Determines the maximum latency on CPU frequency changes. | ||
46 | .TP | ||
47 | \fB\-o\fR \fB\-\-proc\fR | ||
48 | Prints out information like provided by the /proc/cpufreq interface in 2.4. and early 2.6. kernels. | ||
49 | .TP | ||
50 | \fB\-m\fR \fB\-\-human\fR | ||
51 | human\-readable output for the \-f, \-w, \-s and \-y parameters. | ||
52 | .TP | ||
53 | \fB\-h\fR \fB\-\-help\fR | ||
54 | Prints out the help screen. | ||
55 | .SH "REMARKS" | ||
56 | .LP | ||
57 | By default only values of core zero are displayed. How to display settings of | ||
58 | other cores is described in the cpupower(1) manpage in the \-\-cpu option section. | ||
59 | .LP | ||
60 | You can't specify more than one of the output specific options \-o \-e \-a \-g \-p \-d \-l \-w \-f \-y. | ||
61 | .LP | ||
62 | You also can't specify the \-o option combined with the \-c option. | ||
63 | .SH "FILES" | ||
64 | .nf | ||
65 | \fI/sys/devices/system/cpu/cpu*/cpufreq/\fP | ||
66 | \fI/proc/cpufreq\fP (deprecated) | ||
67 | \fI/proc/sys/cpu/\fP (deprecated) | ||
68 | .fi | ||
69 | .SH "AUTHORS" | ||
70 | .nf | ||
71 | Dominik Brodowski <linux@brodo.de> \- author | ||
72 | Mattia Dongili<malattia@gmail.com> \- first autolibtoolization | ||
73 | .fi | ||
74 | .SH "SEE ALSO" | ||
75 | .LP | ||
76 | cpupower\-frequency\-set(1), cpupower(1) | ||
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 new file mode 100644 index 000000000000..685f469093ad --- /dev/null +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 | |||
@@ -0,0 +1,54 @@ | |||
1 | .TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" "" | ||
2 | .SH "NAME" | ||
3 | .LP | ||
4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. | ||
5 | .SH "SYNTAX" | ||
6 | .LP | ||
7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] | ||
8 | .SH "DESCRIPTION" | ||
9 | .LP | ||
10 | cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. | ||
11 | .SH "OPTIONS" | ||
12 | .LP | ||
13 | .TP | ||
14 | \fB\-d\fR \fB\-\-min\fR <FREQ> | ||
15 | new minimum CPU frequency the governor may select. | ||
16 | .TP | ||
17 | \fB\-u\fR \fB\-\-max\fR <FREQ> | ||
18 | new maximum CPU frequency the governor may select. | ||
19 | .TP | ||
20 | \fB\-g\fR \fB\-\-governor\fR <GOV> | ||
21 | new cpufreq governor. | ||
22 | .TP | ||
23 | \fB\-f\fR \fB\-\-freq\fR <FREQ> | ||
24 | specific frequency to be set. Requires userspace governor to be available and loaded. | ||
25 | .TP | ||
26 | \fB\-r\fR \fB\-\-related\fR | ||
27 | modify all hardware-related CPUs at the same time | ||
28 | .TP | ||
29 | \fB\-h\fR \fB\-\-help\fR | ||
30 | Prints out the help screen. | ||
31 | .SH "REMARKS" | ||
32 | .LP | ||
33 | By default values are applied on all cores. How to modify single core | ||
34 | configurations is described in the cpupower(1) manpage in the \-\-cpu option section. | ||
35 | .LP | ||
36 | The \-f FREQ, \-\-freq FREQ parameter cannot be combined with any other parameter. | ||
37 | .LP | ||
38 | FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz by postfixing the value with the wanted unit name, without any space (frequency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000). | ||
39 | .LP | ||
40 | On Linux kernels up to 2.6.29, the \-r or \-\-related parameter is ignored. | ||
41 | .SH "FILES" | ||
42 | .nf | ||
43 | \fI/sys/devices/system/cpu/cpu*/cpufreq/\fP | ||
44 | \fI/proc/cpufreq\fP (deprecated) | ||
45 | \fI/proc/sys/cpu/\fP (deprecated) | ||
46 | .fi | ||
47 | .SH "AUTHORS" | ||
48 | .nf | ||
49 | Dominik Brodowski <linux@brodo.de> \- author | ||
50 | Mattia Dongili<malattia@gmail.com> \- first autolibtoolization | ||
51 | .fi | ||
52 | .SH "SEE ALSO" | ||
53 | .LP | ||
54 | cpupower\-frequency\-info(1), cpupower(1) | ||
diff --git a/tools/power/cpupower/man/cpupower-info.1 b/tools/power/cpupower/man/cpupower-info.1 new file mode 100644 index 000000000000..58e21196f17f --- /dev/null +++ b/tools/power/cpupower/man/cpupower-info.1 | |||
@@ -0,0 +1,19 @@ | |||
1 | .TH CPUPOWER\-INFO "1" "22/02/2011" "" "cpupower Manual" | ||
2 | .SH NAME | ||
3 | cpupower\-info \- Shows processor power related kernel or hardware configurations | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B cpupower info [ \-b ] [ \-s ] [ \-m ] | ||
7 | |||
8 | .SH DESCRIPTION | ||
9 | \fBcpupower info \fP shows kernel configurations or processor hardware | ||
10 | registers affecting processor power saving policies. | ||
11 | |||
12 | Some options are platform wide, some affect single cores. By default values | ||
13 | of core zero are displayed only. cpupower --cpu all cpuinfo will show the | ||
14 | settings of all cores, see cpupower(1) how to choose specific cores. | ||
15 | |||
16 | .SH "SEE ALSO" | ||
17 | Options are described in detail in: | ||
18 | |||
19 | cpupower(1), cpupower-set(1) | ||
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1 new file mode 100644 index 000000000000..d5cfa265c3d3 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-monitor.1 | |||
@@ -0,0 +1,179 @@ | |||
1 | .TH CPUPOWER\-MONITOR "1" "22/02/2011" "" "cpupower Manual" | ||
2 | .SH NAME | ||
3 | cpupower\-monitor \- Report processor frequency and idle statistics | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B cpupower monitor | ||
7 | .RB "\-l" | ||
8 | |||
9 | .B cpupower monitor | ||
10 | .RB [ "\-m <mon1>," [ "<mon2>,..." ] ] | ||
11 | .RB [ "\-i seconds" ] | ||
12 | .br | ||
13 | .B cpupower monitor | ||
14 | .RB [ "\-m <mon1>," [ "<mon2>,..." ] ] | ||
15 | .RB command | ||
16 | .br | ||
17 | .SH DESCRIPTION | ||
18 | \fBcpupower-monitor \fP reports processor topology, frequency and idle power | ||
19 | state statistics. Either \fBcommand\fP is forked and | ||
20 | statistics are printed upon its completion, or statistics are printed periodically. | ||
21 | |||
22 | \fBcpupower-monitor \fP implements independent processor sleep state and | ||
23 | frequency counters. Some are retrieved from kernel statistics, some are | ||
24 | directly reading out hardware registers. Use \-l to get an overview which are | ||
25 | supported on your system. | ||
26 | |||
27 | .SH Options | ||
28 | .PP | ||
29 | \-l | ||
30 | .RS 4 | ||
31 | List available monitors on your system. Additional details about each monitor | ||
32 | are shown: | ||
33 | .RS 2 | ||
34 | .IP \(bu | ||
35 | The name in quotation marks which can be passed to the \-m parameter. | ||
36 | .IP \(bu | ||
37 | The number of different counters the monitor supports in brackets. | ||
38 | .IP \(bu | ||
39 | The amount of time in seconds the counters might overflow, due to | ||
40 | implementation constraints. | ||
41 | .IP \(bu | ||
42 | The name and a description of each counter and its processor hierarchy level | ||
43 | coverage in square brackets: | ||
44 | .RS 4 | ||
45 | .IP \(bu | ||
46 | [T] \-> Thread | ||
47 | .IP \(bu | ||
48 | [C] \-> Core | ||
49 | .IP \(bu | ||
50 | [P] \-> Processor Package (Socket) | ||
51 | .IP \(bu | ||
52 | [M] \-> Machine/Platform wide counter | ||
53 | .RE | ||
54 | .RE | ||
55 | .RE | ||
56 | .PP | ||
57 | \-m <mon1>,<mon2>,... | ||
58 | .RS 4 | ||
59 | Only display specific monitors. Use the monitor string(s) provided by \-l option. | ||
60 | .RE | ||
61 | .PP | ||
62 | \-i seconds | ||
63 | .RS 4 | ||
64 | Measure intervall. | ||
65 | .RE | ||
66 | .PP | ||
67 | command | ||
68 | .RS 4 | ||
69 | Measure idle and frequency characteristics of an arbitrary command/workload. | ||
70 | The executable \fBcommand\fP is forked and upon its exit, statistics gathered since it was | ||
71 | forked are displayed. | ||
72 | .RE | ||
73 | .PP | ||
74 | \-v | ||
75 | .RS 4 | ||
76 | Increase verbosity if the binary was compiled with the DEBUG option set. | ||
77 | .RE | ||
78 | |||
79 | .SH MONITOR DESCRIPTIONS | ||
80 | .SS "Idle_Stats" | ||
81 | Shows statistics of the cpuidle kernel subsystem. Values are retrieved from | ||
82 | /sys/devices/system/cpu/cpu*/cpuidle/state*/. | ||
83 | The kernel updates these values every time an idle state is entered or | ||
84 | left. Therefore there can be some inaccuracy when cores are in an idle | ||
85 | state for some time when the measure starts or ends. In worst case it can happen | ||
86 | that one core stayed in an idle state for the whole measure time and the idle | ||
87 | state usage time as exported by the kernel did not get updated. In this case | ||
88 | a state residency of 0 percent is shown while it was 100. | ||
89 | |||
90 | .SS "Mperf" | ||
91 | The name comes from the aperf/mperf (average and maximum) MSR registers used | ||
92 | which are available on recent X86 processors. It shows the average frequency | ||
93 | (including boost frequencies). | ||
94 | The fact that on all recent hardware the mperf timer stops ticking in any idle | ||
95 | state it is also used to show C0 (processor is active) and Cx (processor is in | ||
96 | any sleep state) times. These counters do not have the inaccuracy restrictions | ||
97 | the "Idle_Stats" counters may show. | ||
98 | May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP | ||
99 | kernel frequency driver periodically cleared aperf/mperf registers in those | ||
100 | kernels. | ||
101 | |||
102 | .SS "Nehalem" "SandyBridge" | ||
103 | Intel Core and Package sleep state counters. | ||
104 | Threads (hyperthreaded cores) may not be able to enter deeper core states if | ||
105 | its sibling is utilized. | ||
106 | Deepest package sleep states may in reality show up as machine/platform wide | ||
107 | sleep states and can only be entered if all cores are idle. Look up Intel | ||
108 | manuals (some are provided in the References section) for further details. | ||
109 | |||
110 | .SS "Ontario" "Liano" | ||
111 | AMD laptop and desktop processor (family 12h and 14h) sleep state counters. | ||
112 | The registers are accessed via PCI and therefore can still be read out while | ||
113 | cores have been offlined. | ||
114 | |||
115 | There is one special counter: NBP1 (North Bridge P1). | ||
116 | This one always returns 0 or 1, depending on whether the North Bridge P1 | ||
117 | power state got entered at least once during measure time. | ||
118 | Being able to enter NBP1 state also depends on graphics power management. | ||
119 | Therefore this counter can be used to verify whether the graphics' driver | ||
120 | power management is working as expected. | ||
121 | |||
122 | .SH EXAMPLES | ||
123 | |||
124 | cpupower monitor -l" may show: | ||
125 | .RS 4 | ||
126 | Monitor "Mperf" (3 states) \- Might overflow after 922000000 s | ||
127 | |||
128 | ... | ||
129 | |||
130 | Monitor "Idle_Stats" (3 states) \- Might overflow after 4294967295 s | ||
131 | |||
132 | ... | ||
133 | |||
134 | .RE | ||
135 | cpupower monitor \-m "Idle_Stats,Mperf" scp /tmp/test /nfs/tmp | ||
136 | |||
137 | Monitor the scp command, show both Mperf and Idle_Stats states counter | ||
138 | statistics, but in exchanged order. | ||
139 | |||
140 | |||
141 | |||
142 | .RE | ||
143 | Be careful that the typical command to fully utilize one CPU by doing: | ||
144 | |||
145 | cpupower monitor cat /dev/zero >/dev/null | ||
146 | |||
147 | Does not work as expected, because the measured output is redirected to | ||
148 | /dev/null. This could get workarounded by putting the line into an own, tiny | ||
149 | shell script. Hit CTRL\-c to terminate the command and get the measure output | ||
150 | displayed. | ||
151 | |||
152 | .SH REFERENCES | ||
153 | "BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors" | ||
154 | http://support.amd.com/us/Processor_TechDocs/43170.pdf | ||
155 | |||
156 | "Intel® Turbo Boost Technology | ||
157 | in Intel® Core™ Microarchitecture (Nehalem) Based Processors" | ||
158 | http://download.intel.com/design/processor/applnots/320354.pdf | ||
159 | |||
160 | "Intel® 64 and IA-32 Architectures Software Developer's Manual | ||
161 | Volume 3B: System Programming Guide" | ||
162 | http://www.intel.com/products/processor/manuals | ||
163 | |||
164 | .SH FILES | ||
165 | .ta | ||
166 | .nf | ||
167 | /dev/cpu/*/msr | ||
168 | /sys/devices/system/cpu/cpu*/cpuidle/state*/. | ||
169 | .fi | ||
170 | |||
171 | .SH "SEE ALSO" | ||
172 | powertop(8), msr(4), vmstat(8) | ||
173 | .PP | ||
174 | .SH AUTHORS | ||
175 | .nf | ||
176 | Written by Thomas Renninger <trenn@suse.de> | ||
177 | |||
178 | Nehalem, SandyBridge monitors and command passing | ||
179 | based on turbostat.8 from Len Brown <len.brown@intel.com> | ||
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1 new file mode 100644 index 000000000000..c4954a9fe4e7 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-set.1 | |||
@@ -0,0 +1,103 @@ | |||
1 | .TH CPUPOWER\-SET "1" "22/02/2011" "" "cpupower Manual" | ||
2 | .SH NAME | ||
3 | cpupower\-set \- Set processor power related kernel or hardware configurations | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B cpupower set [ \-b VAL ] [ \-s VAL ] [ \-m VAL ] | ||
7 | |||
8 | |||
9 | .SH DESCRIPTION | ||
10 | \fBcpupower set \fP sets kernel configurations or directly accesses hardware | ||
11 | registers affecting processor power saving policies. | ||
12 | |||
13 | Some options are platform wide, some affect single cores. By default values | ||
14 | are applied on all cores. How to modify single core configurations is | ||
15 | described in the cpupower(1) manpage in the \-\-cpu option section. Whether an | ||
16 | option affects the whole system or can be applied to individual cores is | ||
17 | described in the Options sections. | ||
18 | |||
19 | Use \fBcpupower info \fP to read out current settings and whether they are | ||
20 | supported on the system at all. | ||
21 | |||
22 | .SH Options | ||
23 | .PP | ||
24 | \-\-perf-bias, \-b | ||
25 | .RS 4 | ||
26 | Sets a register on supported Intel processore which allows software to convey | ||
27 | its policy for the relative importance of performance versus energy savings to | ||
28 | the processor. | ||
29 | |||
30 | The range of valid numbers is 0-15, where 0 is maximum | ||
31 | performance and 15 is maximum energy efficiency. | ||
32 | |||
33 | The processor uses this information in model-specific ways | ||
34 | when it must select trade-offs between performance and | ||
35 | energy efficiency. | ||
36 | |||
37 | This policy hint does not supersede Processor Performance states | ||
38 | (P-states) or CPU Idle power states (C-states), but allows | ||
39 | software to have influence where it would otherwise be unable | ||
40 | to express a preference. | ||
41 | |||
42 | For example, this setting may tell the hardware how | ||
43 | aggressively or conservatively to control frequency | ||
44 | in the "turbo range" above the explicitly OS-controlled | ||
45 | P-state frequency range. It may also tell the hardware | ||
46 | how aggressively it should enter the OS requested C-states. | ||
47 | |||
48 | This option can be applied to individual cores only via the \-\-cpu option, | ||
49 | cpupower(1). | ||
50 | |||
51 | Setting the performance bias value on one CPU can modify the setting on | ||
52 | related CPUs as well (for example all CPUs on one socket), because of | ||
53 | hardware restrictions. | ||
54 | Use \fBcpupower -c all info -b\fP to verify. | ||
55 | |||
56 | This options needs the msr kernel driver (CONFIG_X86_MSR) loaded. | ||
57 | .RE | ||
58 | .PP | ||
59 | \-\-sched\-mc, \-m [ VAL ] | ||
60 | .RE | ||
61 | \-\-sched\-smt, \-s [ VAL ] | ||
62 | .RS 4 | ||
63 | \-\-sched\-mc utilizes cores in one processor package/socket first before | ||
64 | processes are scheduled to other processor packages/sockets. | ||
65 | |||
66 | \-\-sched\-smt utilizes thread siblings of one processor core first before | ||
67 | processes are scheduled to other cores. | ||
68 | |||
69 | The impact on power consumption and performance (positiv or negativ) heavily | ||
70 | depends on processor support for deep sleep states, frequency scaling and | ||
71 | frequency boost modes and their dependencies between other thread siblings | ||
72 | and processor cores. | ||
73 | |||
74 | Taken over from kernel documentation: | ||
75 | |||
76 | Adjust the kernel's multi-core scheduler support. | ||
77 | |||
78 | Possible values are: | ||
79 | .RS 2 | ||
80 | 0 - No power saving load balance (default value) | ||
81 | |||
82 | 1 - Fill one thread/core/package first for long running threads | ||
83 | |||
84 | 2 - Also bias task wakeups to semi-idle cpu package for power | ||
85 | savings | ||
86 | .RE | ||
87 | |||
88 | sched_mc_power_savings is dependent upon SCHED_MC, which is | ||
89 | itself architecture dependent. | ||
90 | |||
91 | sched_smt_power_savings is dependent upon SCHED_SMT, which | ||
92 | is itself architecture dependent. | ||
93 | |||
94 | The two files are independent of each other. It is possible | ||
95 | that one file may be present without the other. | ||
96 | |||
97 | .SH "SEE ALSO" | ||
98 | cpupower-info(1), cpupower-monitor(1), powertop(1) | ||
99 | .PP | ||
100 | .SH AUTHORS | ||
101 | .nf | ||
102 | \-\-perf\-bias parts written by Len Brown <len.brown@intel.com> | ||
103 | Thomas Renninger <trenn@suse.de> | ||
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1 new file mode 100644 index 000000000000..baf741d06e82 --- /dev/null +++ b/tools/power/cpupower/man/cpupower.1 | |||
@@ -0,0 +1,72 @@ | |||
1 | .TH CPUPOWER "1" "07/03/2011" "" "cpupower Manual" | ||
2 | .SH NAME | ||
3 | cpupower \- Shows and sets processor power related values | ||
4 | .SH SYNOPSIS | ||
5 | .ft B | ||
6 | .B cpupower [ \-c cpulist ] <command> [ARGS] | ||
7 | |||
8 | .B cpupower \-v|\-\-version | ||
9 | |||
10 | .B cpupower \-h|\-\-help | ||
11 | |||
12 | .SH DESCRIPTION | ||
13 | \fBcpupower \fP is a collection of tools to examine and tune power saving | ||
14 | related features of your processor. | ||
15 | |||
16 | The manpages of the commands (cpupower\-<command>(1)) provide detailed | ||
17 | descriptions of supported features. Run \fBcpupower help\fP to get an overview | ||
18 | of supported commands. | ||
19 | |||
20 | .SH Options | ||
21 | .PP | ||
22 | \-\-help, \-h | ||
23 | .RS 4 | ||
24 | Shows supported commands and general usage. | ||
25 | .RE | ||
26 | .PP | ||
27 | \-\-cpu cpulist, \-c cpulist | ||
28 | .RS 4 | ||
29 | Only show or set values for specific cores. | ||
30 | This option is not supported by all commands, details can be found in the | ||
31 | manpages of the commands. | ||
32 | |||
33 | Some commands access all cores (typically the *\-set commands), some only | ||
34 | the first core (typically the *\-info commands) by default. | ||
35 | |||
36 | The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via | ||
37 | sysfs files. Some examples: | ||
38 | .RS 4 | ||
39 | .TP 16 | ||
40 | Input | ||
41 | Equivalent to | ||
42 | .TP | ||
43 | all | ||
44 | all cores | ||
45 | .TP | ||
46 | 0\-3 | ||
47 | 0,1,2,3 | ||
48 | .TP | ||
49 | 0\-7:2 | ||
50 | 0,2,4,6 | ||
51 | .TP | ||
52 | 1,3,5-7 | ||
53 | 1,3,5,6,7 | ||
54 | .TP | ||
55 | 0\-3:2,8\-15:4 | ||
56 | 0,2,8,12 | ||
57 | .RE | ||
58 | .RE | ||
59 | .PP | ||
60 | \-\-version, \-v | ||
61 | .RS 4 | ||
62 | Print the package name and version number. | ||
63 | |||
64 | .SH "SEE ALSO" | ||
65 | cpupower-set(1), cpupower-info(1), cpupower-idle(1), | ||
66 | cpupower-frequency-set(1), cpupower-frequency-info(1), cpupower-monitor(1), | ||
67 | powertop(1) | ||
68 | .PP | ||
69 | .SH AUTHORS | ||
70 | .nf | ||
71 | \-\-perf\-bias parts written by Len Brown <len.brown@intel.com> | ||
72 | Thomas Renninger <trenn@suse.de> | ||
diff --git a/tools/power/cpupower/po/cs.po b/tools/power/cpupower/po/cs.po new file mode 100644 index 000000000000..cb22c45c5069 --- /dev/null +++ b/tools/power/cpupower/po/cs.po | |||
@@ -0,0 +1,944 @@ | |||
1 | # translation of cs.po to Czech | ||
2 | # Czech translation for cpufrequtils package | ||
3 | # Czech messages for cpufrequtils. | ||
4 | # Copyright (C) 2007 kavol | ||
5 | # This file is distributed under the same license as the cpufrequtils package. | ||
6 | # | ||
7 | # Karel Volný <kavol@seznam.cz>, 2007, 2008. | ||
8 | msgid "" | ||
9 | msgstr "" | ||
10 | "Project-Id-Version: cs\n" | ||
11 | "Report-Msgid-Bugs-To: \n" | ||
12 | "POT-Creation-Date: 2011-03-08 17:03+0100\n" | ||
13 | "PO-Revision-Date: 2008-06-11 16:26+0200\n" | ||
14 | "Last-Translator: Karel Volný <kavol@seznam.cz>\n" | ||
15 | "Language-Team: Czech <diskuze@lists.l10n.cz>\n" | ||
16 | "Language: cs\n" | ||
17 | "MIME-Version: 1.0\n" | ||
18 | "Content-Type: text/plain; charset=UTF-8\n" | ||
19 | "Content-Transfer-Encoding: 8bit\n" | ||
20 | "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" | ||
21 | "X-Generator: KBabel 1.11.4\n" | ||
22 | |||
23 | #: utils/idle_monitor/nhm_idle.c:36 | ||
24 | msgid "Processor Core C3" | ||
25 | msgstr "" | ||
26 | |||
27 | #: utils/idle_monitor/nhm_idle.c:43 | ||
28 | msgid "Processor Core C6" | ||
29 | msgstr "" | ||
30 | |||
31 | #: utils/idle_monitor/nhm_idle.c:51 | ||
32 | msgid "Processor Package C3" | ||
33 | msgstr "" | ||
34 | |||
35 | #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 | ||
36 | msgid "Processor Package C6" | ||
37 | msgstr "" | ||
38 | |||
39 | #: utils/idle_monitor/snb_idle.c:33 | ||
40 | msgid "Processor Core C7" | ||
41 | msgstr "" | ||
42 | |||
43 | #: utils/idle_monitor/snb_idle.c:40 | ||
44 | msgid "Processor Package C2" | ||
45 | msgstr "" | ||
46 | |||
47 | #: utils/idle_monitor/snb_idle.c:47 | ||
48 | msgid "Processor Package C7" | ||
49 | msgstr "" | ||
50 | |||
51 | #: utils/idle_monitor/amd_fam14h_idle.c:56 | ||
52 | msgid "Package in sleep state (PC1 or deeper)" | ||
53 | msgstr "" | ||
54 | |||
55 | #: utils/idle_monitor/amd_fam14h_idle.c:63 | ||
56 | msgid "Processor Package C1" | ||
57 | msgstr "" | ||
58 | |||
59 | #: utils/idle_monitor/amd_fam14h_idle.c:77 | ||
60 | msgid "North Bridge P1 boolean counter (returns 0 or 1)" | ||
61 | msgstr "" | ||
62 | |||
63 | #: utils/idle_monitor/mperf_monitor.c:35 | ||
64 | msgid "Processor Core not idle" | ||
65 | msgstr "" | ||
66 | |||
67 | #: utils/idle_monitor/mperf_monitor.c:42 | ||
68 | msgid "Processor Core in an idle state" | ||
69 | msgstr "" | ||
70 | |||
71 | #: utils/idle_monitor/mperf_monitor.c:50 | ||
72 | msgid "Average Frequency (including boost) in MHz" | ||
73 | msgstr "" | ||
74 | |||
75 | #: utils/idle_monitor/cpupower-monitor.c:66 | ||
76 | #, c-format | ||
77 | msgid "" | ||
78 | "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
79 | "interval_sec | -c command ...]\n" | ||
80 | msgstr "" | ||
81 | |||
82 | #: utils/idle_monitor/cpupower-monitor.c:69 | ||
83 | #, c-format | ||
84 | msgid "" | ||
85 | "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
86 | "interval_sec | -c command ...]\n" | ||
87 | msgstr "" | ||
88 | |||
89 | #: utils/idle_monitor/cpupower-monitor.c:71 | ||
90 | #, c-format | ||
91 | msgid "\t -v: be more verbose\n" | ||
92 | msgstr "" | ||
93 | |||
94 | #: utils/idle_monitor/cpupower-monitor.c:73 | ||
95 | #, c-format | ||
96 | msgid "\t -h: print this help\n" | ||
97 | msgstr "" | ||
98 | |||
99 | #: utils/idle_monitor/cpupower-monitor.c:74 | ||
100 | #, c-format | ||
101 | msgid "\t -i: time intervall to measure for in seconds (default 1)\n" | ||
102 | msgstr "" | ||
103 | |||
104 | #: utils/idle_monitor/cpupower-monitor.c:75 | ||
105 | #, c-format | ||
106 | msgid "\t -t: show CPU topology/hierarchy\n" | ||
107 | msgstr "" | ||
108 | |||
109 | #: utils/idle_monitor/cpupower-monitor.c:76 | ||
110 | #, c-format | ||
111 | msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" | ||
112 | msgstr "" | ||
113 | |||
114 | #: utils/idle_monitor/cpupower-monitor.c:77 | ||
115 | #, c-format | ||
116 | msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" | ||
117 | msgstr "" | ||
118 | |||
119 | #: utils/idle_monitor/cpupower-monitor.c:79 | ||
120 | #, c-format | ||
121 | msgid "" | ||
122 | "only one of: -t, -l, -m are allowed\n" | ||
123 | "If none of them is passed," | ||
124 | msgstr "" | ||
125 | |||
126 | #: utils/idle_monitor/cpupower-monitor.c:80 | ||
127 | #, c-format | ||
128 | msgid " all supported monitors are shown\n" | ||
129 | msgstr "" | ||
130 | |||
131 | #: utils/idle_monitor/cpupower-monitor.c:197 | ||
132 | #, c-format | ||
133 | msgid "Monitor %s, Counter %s has no count function. Implementation error\n" | ||
134 | msgstr "" | ||
135 | |||
136 | #: utils/idle_monitor/cpupower-monitor.c:207 | ||
137 | #, c-format | ||
138 | msgid " *is offline\n" | ||
139 | msgstr "" | ||
140 | |||
141 | #: utils/idle_monitor/cpupower-monitor.c:236 | ||
142 | #, c-format | ||
143 | msgid "%s: max monitor name length (%d) exceeded\n" | ||
144 | msgstr "" | ||
145 | |||
146 | #: utils/idle_monitor/cpupower-monitor.c:250 | ||
147 | #, c-format | ||
148 | msgid "No matching monitor found in %s, try -l option\n" | ||
149 | msgstr "" | ||
150 | |||
151 | #: utils/idle_monitor/cpupower-monitor.c:266 | ||
152 | #, c-format | ||
153 | msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" | ||
154 | msgstr "" | ||
155 | |||
156 | #: utils/idle_monitor/cpupower-monitor.c:319 | ||
157 | #, c-format | ||
158 | msgid "%s took %.5f seconds and exited with status %d\n" | ||
159 | msgstr "" | ||
160 | |||
161 | #: utils/idle_monitor/cpupower-monitor.c:406 | ||
162 | #, c-format | ||
163 | msgid "Cannot read number of available processors\n" | ||
164 | msgstr "" | ||
165 | |||
166 | #: utils/idle_monitor/cpupower-monitor.c:417 | ||
167 | #, c-format | ||
168 | msgid "Available monitor %s needs root access\n" | ||
169 | msgstr "" | ||
170 | |||
171 | #: utils/idle_monitor/cpupower-monitor.c:428 | ||
172 | #, c-format | ||
173 | msgid "No HW Cstate monitors found\n" | ||
174 | msgstr "" | ||
175 | |||
176 | #: utils/cpupower.c:78 | ||
177 | #, c-format | ||
178 | msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" | ||
179 | msgstr "" | ||
180 | |||
181 | #: utils/cpupower.c:79 | ||
182 | #, c-format | ||
183 | msgid "cpupower --version\n" | ||
184 | msgstr "" | ||
185 | |||
186 | #: utils/cpupower.c:80 | ||
187 | #, c-format | ||
188 | msgid "Supported subcommands are:\n" | ||
189 | msgstr "" | ||
190 | |||
191 | #: utils/cpupower.c:83 | ||
192 | #, c-format | ||
193 | msgid "" | ||
194 | "\n" | ||
195 | "Some subcommands can make use of the -c cpulist option.\n" | ||
196 | msgstr "" | ||
197 | |||
198 | #: utils/cpupower.c:84 | ||
199 | #, c-format | ||
200 | msgid "Look at the general cpupower manpage how to use it\n" | ||
201 | msgstr "" | ||
202 | |||
203 | #: utils/cpupower.c:85 | ||
204 | #, c-format | ||
205 | msgid "and read up the subcommand's manpage whether it is supported.\n" | ||
206 | msgstr "" | ||
207 | |||
208 | #: utils/cpupower.c:86 | ||
209 | #, c-format | ||
210 | msgid "" | ||
211 | "\n" | ||
212 | "Use cpupower help subcommand for getting help for above subcommands.\n" | ||
213 | msgstr "" | ||
214 | |||
215 | #: utils/cpupower.c:91 | ||
216 | #, c-format | ||
217 | msgid "Report errors and bugs to %s, please.\n" | ||
218 | msgstr "" | ||
219 | "Chyby v programu prosÃm hlaste na %s (anglicky).\n" | ||
220 | "Chyby v pÅ™ekladu prosÃm hlaste na kavol@seznam.cz (Äesky ;-)\n" | ||
221 | |||
222 | #: utils/cpupower.c:114 | ||
223 | #, c-format | ||
224 | msgid "Error parsing cpu list\n" | ||
225 | msgstr "" | ||
226 | |||
227 | #: utils/cpupower.c:172 | ||
228 | #, c-format | ||
229 | msgid "Subcommand %s needs root privileges\n" | ||
230 | msgstr "" | ||
231 | |||
232 | #: utils/cpufreq-info.c:31 | ||
233 | #, c-format | ||
234 | msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" | ||
235 | msgstr "Nelze zjistit poÄet CPU (%s: %s), pÅ™edpokládá se 1.\n" | ||
236 | |||
237 | #: utils/cpufreq-info.c:63 | ||
238 | #, c-format | ||
239 | msgid "" | ||
240 | " minimum CPU frequency - maximum CPU frequency - governor\n" | ||
241 | msgstr "" | ||
242 | " minimálnà frekvence CPU - maximálnà frekvence CPU - regulátor\n" | ||
243 | |||
244 | #: utils/cpufreq-info.c:151 | ||
245 | #, c-format | ||
246 | msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" | ||
247 | msgstr "" | ||
248 | |||
249 | #. P state changes via MSR are identified via cpuid 80000007 | ||
250 | #. on Intel and AMD, but we assume boost capable machines can do that | ||
251 | #. if (cpuid_eax(0x80000000) >= 0x80000007 | ||
252 | #. && (cpuid_edx(0x80000007) & (1 << 7))) | ||
253 | #. | ||
254 | #: utils/cpufreq-info.c:161 | ||
255 | #, c-format | ||
256 | msgid " boost state support: \n" | ||
257 | msgstr "" | ||
258 | |||
259 | #: utils/cpufreq-info.c:163 | ||
260 | #, c-format | ||
261 | msgid " Supported: %s\n" | ||
262 | msgstr "" | ||
263 | |||
264 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
265 | msgid "yes" | ||
266 | msgstr "" | ||
267 | |||
268 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
269 | msgid "no" | ||
270 | msgstr "" | ||
271 | |||
272 | #: utils/cpufreq-info.c:164 | ||
273 | #, fuzzy, c-format | ||
274 | msgid " Active: %s\n" | ||
275 | msgstr " ovladaÄ: %s\n" | ||
276 | |||
277 | #: utils/cpufreq-info.c:177 | ||
278 | #, c-format | ||
279 | msgid " Boost States: %d\n" | ||
280 | msgstr "" | ||
281 | |||
282 | #: utils/cpufreq-info.c:178 | ||
283 | #, c-format | ||
284 | msgid " Total States: %d\n" | ||
285 | msgstr "" | ||
286 | |||
287 | #: utils/cpufreq-info.c:181 | ||
288 | #, c-format | ||
289 | msgid " Pstate-Pb%d: %luMHz (boost state)\n" | ||
290 | msgstr "" | ||
291 | |||
292 | #: utils/cpufreq-info.c:184 | ||
293 | #, c-format | ||
294 | msgid " Pstate-P%d: %luMHz\n" | ||
295 | msgstr "" | ||
296 | |||
297 | #: utils/cpufreq-info.c:211 | ||
298 | #, c-format | ||
299 | msgid " no or unknown cpufreq driver is active on this CPU\n" | ||
300 | msgstr " pro tento CPU nenà aktivnà žádný známý ovladaÄ cpufreq\n" | ||
301 | |||
302 | #: utils/cpufreq-info.c:213 | ||
303 | #, c-format | ||
304 | msgid " driver: %s\n" | ||
305 | msgstr " ovladaÄ: %s\n" | ||
306 | |||
307 | #: utils/cpufreq-info.c:219 | ||
308 | #, fuzzy, c-format | ||
309 | msgid " CPUs which run at the same hardware frequency: " | ||
310 | msgstr " CPU, které musà měnit frekvenci zároveň: " | ||
311 | |||
312 | #: utils/cpufreq-info.c:230 | ||
313 | #, fuzzy, c-format | ||
314 | msgid " CPUs which need to have their frequency coordinated by software: " | ||
315 | msgstr " CPU, které musà měnit frekvenci zároveň: " | ||
316 | |||
317 | #: utils/cpufreq-info.c:241 | ||
318 | #, c-format | ||
319 | msgid " maximum transition latency: " | ||
320 | msgstr "" | ||
321 | |||
322 | #: utils/cpufreq-info.c:247 | ||
323 | #, c-format | ||
324 | msgid " hardware limits: " | ||
325 | msgstr " hardwarové meze: " | ||
326 | |||
327 | #: utils/cpufreq-info.c:256 | ||
328 | #, c-format | ||
329 | msgid " available frequency steps: " | ||
330 | msgstr " dostupné frekvence: " | ||
331 | |||
332 | #: utils/cpufreq-info.c:269 | ||
333 | #, c-format | ||
334 | msgid " available cpufreq governors: " | ||
335 | msgstr " dostupné regulátory: " | ||
336 | |||
337 | #: utils/cpufreq-info.c:280 | ||
338 | #, c-format | ||
339 | msgid " current policy: frequency should be within " | ||
340 | msgstr " souÄasná taktika: frekvence by mÄ›la být mezi " | ||
341 | |||
342 | #: utils/cpufreq-info.c:282 | ||
343 | #, c-format | ||
344 | msgid " and " | ||
345 | msgstr " a " | ||
346 | |||
347 | #: utils/cpufreq-info.c:286 | ||
348 | #, c-format | ||
349 | msgid "" | ||
350 | "The governor \"%s\" may decide which speed to use\n" | ||
351 | " within this range.\n" | ||
352 | msgstr "" | ||
353 | " Regulátor \"%s\" může rozhodnout jakou frekvenci použÃt\n" | ||
354 | " v tÄ›chto mezÃch.\n" | ||
355 | |||
356 | #: utils/cpufreq-info.c:293 | ||
357 | #, c-format | ||
358 | msgid " current CPU frequency is " | ||
359 | msgstr " souÄasná frekvence CPU je " | ||
360 | |||
361 | #: utils/cpufreq-info.c:296 | ||
362 | #, c-format | ||
363 | msgid " (asserted by call to hardware)" | ||
364 | msgstr " (zjiÅ¡tÄ›no hardwarovým volánÃm)" | ||
365 | |||
366 | #: utils/cpufreq-info.c:304 | ||
367 | #, c-format | ||
368 | msgid " cpufreq stats: " | ||
369 | msgstr " statistika cpufreq: " | ||
370 | |||
371 | #: utils/cpufreq-info.c:472 | ||
372 | #, fuzzy, c-format | ||
373 | msgid "Usage: cpupower freqinfo [options]\n" | ||
374 | msgstr "UžitÃ: cpufreq-info [pÅ™epÃnaÄe]\n" | ||
375 | |||
376 | #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 | ||
377 | #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 | ||
378 | #, c-format | ||
379 | msgid "Options:\n" | ||
380 | msgstr "PÅ™epÃnaÄe:\n" | ||
381 | |||
382 | #: utils/cpufreq-info.c:474 | ||
383 | #, fuzzy, c-format | ||
384 | msgid " -e, --debug Prints out debug information [default]\n" | ||
385 | msgstr " -e, --debug VypÃÅ¡e ladicà informace\n" | ||
386 | |||
387 | #: utils/cpufreq-info.c:475 | ||
388 | #, c-format | ||
389 | msgid "" | ||
390 | " -f, --freq Get frequency the CPU currently runs at, according\n" | ||
391 | " to the cpufreq core *\n" | ||
392 | msgstr "" | ||
393 | " -f, --freq Zjistà aktuálnà frekvenci, na které CPU běžÃ\n" | ||
394 | " podle cpufreq *\n" | ||
395 | |||
396 | #: utils/cpufreq-info.c:477 | ||
397 | #, c-format | ||
398 | msgid "" | ||
399 | " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
400 | " it from hardware (only available to root) *\n" | ||
401 | msgstr "" | ||
402 | " -w, --hwfreq Zjistà aktuálnà frekvenci, na které CPU běžÃ\n" | ||
403 | " z hardware (dostupné jen uživateli root) *\n" | ||
404 | |||
405 | #: utils/cpufreq-info.c:479 | ||
406 | #, c-format | ||
407 | msgid "" | ||
408 | " -l, --hwlimits Determine the minimum and maximum CPU frequency " | ||
409 | "allowed *\n" | ||
410 | msgstr "" | ||
411 | " -l, --hwlimits Zjistà minimálnà a maximálnà dostupnou frekvenci CPU " | ||
412 | "*\n" | ||
413 | |||
414 | #: utils/cpufreq-info.c:480 | ||
415 | #, c-format | ||
416 | msgid " -d, --driver Determines the used cpufreq kernel driver *\n" | ||
417 | msgstr " -d, --driver Zjistà aktivnà ovladaÄ cpufreq *\n" | ||
418 | |||
419 | #: utils/cpufreq-info.c:481 | ||
420 | #, c-format | ||
421 | msgid " -p, --policy Gets the currently used cpufreq policy *\n" | ||
422 | msgstr " -p, --policy Zjistà aktuálnà taktiku cpufreq *\n" | ||
423 | |||
424 | #: utils/cpufreq-info.c:482 | ||
425 | #, c-format | ||
426 | msgid " -g, --governors Determines available cpufreq governors *\n" | ||
427 | msgstr " -g, --governors Zjistà dostupné regulátory cpufreq *\n" | ||
428 | |||
429 | #: utils/cpufreq-info.c:483 | ||
430 | #, fuzzy, c-format | ||
431 | msgid "" | ||
432 | " -r, --related-cpus Determines which CPUs run at the same hardware " | ||
433 | "frequency *\n" | ||
434 | msgstr "" | ||
435 | " -a, --affected-cpus ZjistÃ, které CPU musà mÄ›nit frekvenci zároveň *\n" | ||
436 | |||
437 | #: utils/cpufreq-info.c:484 | ||
438 | #, fuzzy, c-format | ||
439 | msgid "" | ||
440 | " -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
441 | " coordinated by software *\n" | ||
442 | msgstr "" | ||
443 | " -a, --affected-cpus ZjistÃ, které CPU musà mÄ›nit frekvenci zároveň *\n" | ||
444 | |||
445 | #: utils/cpufreq-info.c:486 | ||
446 | #, c-format | ||
447 | msgid " -s, --stats Shows cpufreq statistics if available\n" | ||
448 | msgstr " -s, --stats Zobrazà statistiku cpufreq, je-li dostupná\n" | ||
449 | |||
450 | #: utils/cpufreq-info.c:487 | ||
451 | #, fuzzy, c-format | ||
452 | msgid "" | ||
453 | " -y, --latency Determines the maximum latency on CPU frequency " | ||
454 | "changes *\n" | ||
455 | msgstr "" | ||
456 | " -l, --hwlimits Zjistà minimálnà a maximálnà dostupnou frekvenci CPU " | ||
457 | "*\n" | ||
458 | |||
459 | #: utils/cpufreq-info.c:488 | ||
460 | #, c-format | ||
461 | msgid " -b, --boost Checks for turbo or boost modes *\n" | ||
462 | msgstr "" | ||
463 | |||
464 | #: utils/cpufreq-info.c:489 | ||
465 | #, c-format | ||
466 | msgid "" | ||
467 | " -o, --proc Prints out information like provided by the /proc/" | ||
468 | "cpufreq\n" | ||
469 | " interface in 2.4. and early 2.6. kernels\n" | ||
470 | msgstr "" | ||
471 | " -o, --proc VypÃÅ¡e informace ve formátu, jaký použÃvalo rozhranÃ\n" | ||
472 | " /proc/cpufreq v kernelech Å™ady 2.4 a Äasné 2.6\n" | ||
473 | |||
474 | #: utils/cpufreq-info.c:491 | ||
475 | #, fuzzy, c-format | ||
476 | msgid "" | ||
477 | " -m, --human human-readable output for the -f, -w, -s and -y " | ||
478 | "parameters\n" | ||
479 | msgstr "" | ||
480 | " -m, --human Výstup parametrů -f, -w a -s v „lidmi Äitelném“ " | ||
481 | "formátu\n" | ||
482 | |||
483 | #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 | ||
484 | #, c-format | ||
485 | msgid " -h, --help Prints out this screen\n" | ||
486 | msgstr " -h, --help VypÃÅ¡e tuto nápovÄ›du\n" | ||
487 | |||
488 | #: utils/cpufreq-info.c:495 | ||
489 | #, c-format | ||
490 | msgid "" | ||
491 | "If no argument or only the -c, --cpu parameter is given, debug output about\n" | ||
492 | "cpufreq is printed which is useful e.g. for reporting bugs.\n" | ||
493 | msgstr "" | ||
494 | "NenÃ-li zadán žádný parametr nebo je-li zadán pouze pÅ™epÃnaÄ -c, --cpu, " | ||
495 | "jsou\n" | ||
496 | "vypsány ladicà informace, což může být užiteÄné napÅ™Ãklad pÅ™i hlášenà chyb.\n" | ||
497 | |||
498 | #: utils/cpufreq-info.c:497 | ||
499 | #, c-format | ||
500 | msgid "" | ||
501 | "For the arguments marked with *, omitting the -c or --cpu argument is\n" | ||
502 | "equivalent to setting it to zero\n" | ||
503 | msgstr "" | ||
504 | "NenÃ-li pÅ™i použità pÅ™epÃnaÄů oznaÄených * zadán parametr -c nebo --cpu,\n" | ||
505 | "předpokládá se jeho hodnota 0.\n" | ||
506 | |||
507 | #: utils/cpufreq-info.c:580 | ||
508 | #, c-format | ||
509 | msgid "" | ||
510 | "The argument passed to this tool can't be combined with passing a --cpu " | ||
511 | "argument\n" | ||
512 | msgstr "Zadaný parametr nemůže být použit zároveň s pÅ™epÃnaÄem -c nebo --cpu\n" | ||
513 | |||
514 | #: utils/cpufreq-info.c:596 | ||
515 | #, c-format | ||
516 | msgid "" | ||
517 | "You can't specify more than one --cpu parameter and/or\n" | ||
518 | "more than one output-specific argument\n" | ||
519 | msgstr "" | ||
520 | "Nelze zadat vÃce než jeden parametr -c nebo --cpu\n" | ||
521 | "anebo vÃce než jeden parametr urÄujÃcà výstup\n" | ||
522 | |||
523 | #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 | ||
524 | #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 | ||
525 | #, c-format | ||
526 | msgid "invalid or unknown argument\n" | ||
527 | msgstr "neplatný nebo neznámý parametr\n" | ||
528 | |||
529 | #: utils/cpufreq-info.c:617 | ||
530 | #, c-format | ||
531 | msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" | ||
532 | msgstr "nelze analyzovat CPU %d, vypadá to, že nenà pÅ™Ãtomen\n" | ||
533 | |||
534 | #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 | ||
535 | #, c-format | ||
536 | msgid "analyzing CPU %d:\n" | ||
537 | msgstr "analyzuji CPU %d:\n" | ||
538 | |||
539 | #: utils/cpufreq-set.c:25 | ||
540 | #, fuzzy, c-format | ||
541 | msgid "Usage: cpupower frequency-set [options]\n" | ||
542 | msgstr "UžitÃ: cpufreq-set [pÅ™epÃnaÄe]\n" | ||
543 | |||
544 | #: utils/cpufreq-set.c:27 | ||
545 | #, c-format | ||
546 | msgid "" | ||
547 | " -d FREQ, --min FREQ new minimum CPU frequency the governor may " | ||
548 | "select\n" | ||
549 | msgstr "" | ||
550 | " -d FREQ, --min FREQ Nová nejnižšà frekvence, kterou může regulátor " | ||
551 | "vybrat\n" | ||
552 | |||
553 | #: utils/cpufreq-set.c:28 | ||
554 | #, c-format | ||
555 | msgid "" | ||
556 | " -u FREQ, --max FREQ new maximum CPU frequency the governor may " | ||
557 | "select\n" | ||
558 | msgstr "" | ||
559 | " -u FREQ, --max FREQ Nová nejvyššà frekvence, kterou může regulátor " | ||
560 | "zvolit\n" | ||
561 | |||
562 | #: utils/cpufreq-set.c:29 | ||
563 | #, c-format | ||
564 | msgid " -g GOV, --governor GOV new cpufreq governor\n" | ||
565 | msgstr " -g GOV, --governors GOV Nový regulátor cpufreq\n" | ||
566 | |||
567 | #: utils/cpufreq-set.c:30 | ||
568 | #, c-format | ||
569 | msgid "" | ||
570 | " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
571 | " governor to be available and loaded\n" | ||
572 | msgstr "" | ||
573 | " -f FREQ, --freq FREQ Frekvence, která má být nastavena. Vyžaduje, aby " | ||
574 | "byl\n" | ||
575 | " v jádře nahrán regulátor ‚userspace‘.\n" | ||
576 | |||
577 | #: utils/cpufreq-set.c:32 | ||
578 | #, c-format | ||
579 | msgid " -r, --related Switches all hardware-related CPUs\n" | ||
580 | msgstr "" | ||
581 | |||
582 | #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 | ||
583 | #, fuzzy, c-format | ||
584 | msgid " -h, --help Prints out this screen\n" | ||
585 | msgstr " -h, --help VypÃÅ¡e tuto nápovÄ›du\n" | ||
586 | |||
587 | #: utils/cpufreq-set.c:35 | ||
588 | #, fuzzy, c-format | ||
589 | msgid "" | ||
590 | "Notes:\n" | ||
591 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" | ||
592 | msgstr "" | ||
593 | "NenÃ-li pÅ™i použità pÅ™epÃnaÄů oznaÄených * zadán parametr -c nebo --cpu,\n" | ||
594 | "předpokládá se jeho hodnota 0.\n" | ||
595 | |||
596 | #: utils/cpufreq-set.c:37 | ||
597 | #, fuzzy, c-format | ||
598 | msgid "" | ||
599 | "2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " | ||
600 | "parameter\n" | ||
601 | " except the -c CPU, --cpu CPU parameter\n" | ||
602 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
603 | " by postfixing the value with the wanted unit name, without any space\n" | ||
604 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
605 | msgstr "" | ||
606 | "Poznámky:\n" | ||
607 | "1. Vynechánà parametru -c nebo --cpu je ekvivalentnà jeho nastavenà na 0\n" | ||
608 | "2. PÅ™epÃnaÄ -f nebo --freq nemůže být použit zároveň s žádným jiným vyjma -" | ||
609 | "c\n" | ||
610 | " nebo --cpu\n" | ||
611 | "3. Frekvence (FREQ) mohou být zadány v Hz, kHz (výchozÃ), MHz, GHz nebo THz\n" | ||
612 | " pÅ™ipojenÃm názvu jednotky bez mezery mezi ÄÃslem a jednotkou\n" | ||
613 | " (FREQ v kHz =^ Hz * 0,001 = ^ MHz * 1000 =^ GHz * 1000000)\n" | ||
614 | |||
615 | #: utils/cpufreq-set.c:57 | ||
616 | #, c-format | ||
617 | msgid "" | ||
618 | "Error setting new values. Common errors:\n" | ||
619 | "- Do you have proper administration rights? (super-user?)\n" | ||
620 | "- Is the governor you requested available and modprobed?\n" | ||
621 | "- Trying to set an invalid policy?\n" | ||
622 | "- Trying to set a specific frequency, but userspace governor is not " | ||
623 | "available,\n" | ||
624 | " for example because of hardware which cannot be set to a specific " | ||
625 | "frequency\n" | ||
626 | " or because the userspace governor isn't loaded?\n" | ||
627 | msgstr "" | ||
628 | "Chyba při nastavovánà nových hodnot. Obvyklé problémy:\n" | ||
629 | "- Máte patÅ™iÄná administrátorská práva? (root?)\n" | ||
630 | "- Je požadovaný regulátor dostupný v jádře? (modprobe?)\n" | ||
631 | "- SnažÃte se nastavit neplatnou taktiku?\n" | ||
632 | "- SnažÃte se nastavit urÄitou frekvenci, ale nenà dostupný\n" | ||
633 | " regulátor ‚userspace‘, napÅ™Ãklad protože nenà nahrán v jádÅ™e,\n" | ||
634 | " nebo nelze na tomto hardware nastavit urÄitou frekvenci?\n" | ||
635 | |||
636 | #: utils/cpufreq-set.c:170 | ||
637 | #, c-format | ||
638 | msgid "wrong, unknown or unhandled CPU?\n" | ||
639 | msgstr "neznámý nebo nepodporovaný CPU?\n" | ||
640 | |||
641 | #: utils/cpufreq-set.c:302 | ||
642 | #, c-format | ||
643 | msgid "" | ||
644 | "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
645 | "-g/--governor parameters\n" | ||
646 | msgstr "" | ||
647 | "pÅ™epÃnaÄ -f/--freq nemůže být použit zároveň\n" | ||
648 | "s pÅ™epÃnaÄem -d/--min, -u/--max nebo -g/--governor\n" | ||
649 | |||
650 | #: utils/cpufreq-set.c:308 | ||
651 | #, c-format | ||
652 | msgid "" | ||
653 | "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
654 | "-g/--governor must be passed\n" | ||
655 | msgstr "" | ||
656 | "Musà být zadán alespoň jeden pÅ™epÃnaÄ\n" | ||
657 | "-f/--freq, -d/--min, -u/--max nebo -g/--governor\n" | ||
658 | |||
659 | #: utils/cpufreq-set.c:347 | ||
660 | #, c-format | ||
661 | msgid "Setting cpu: %d\n" | ||
662 | msgstr "" | ||
663 | |||
664 | #: utils/cpupower-set.c:22 | ||
665 | #, c-format | ||
666 | msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" | ||
667 | msgstr "" | ||
668 | |||
669 | #: utils/cpupower-set.c:24 | ||
670 | #, c-format | ||
671 | msgid "" | ||
672 | " -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
673 | " Intel models [0-15], see manpage for details\n" | ||
674 | msgstr "" | ||
675 | |||
676 | #: utils/cpupower-set.c:26 | ||
677 | #, c-format | ||
678 | msgid "" | ||
679 | " -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n" | ||
680 | msgstr "" | ||
681 | |||
682 | #: utils/cpupower-set.c:27 | ||
683 | #, c-format | ||
684 | msgid "" | ||
685 | " -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler " | ||
686 | "policy.\n" | ||
687 | msgstr "" | ||
688 | |||
689 | #: utils/cpupower-set.c:80 | ||
690 | #, c-format | ||
691 | msgid "--perf-bias param out of range [0-%d]\n" | ||
692 | msgstr "" | ||
693 | |||
694 | #: utils/cpupower-set.c:91 | ||
695 | #, c-format | ||
696 | msgid "--sched-mc param out of range [0-%d]\n" | ||
697 | msgstr "" | ||
698 | |||
699 | #: utils/cpupower-set.c:102 | ||
700 | #, c-format | ||
701 | msgid "--sched-smt param out of range [0-%d]\n" | ||
702 | msgstr "" | ||
703 | |||
704 | #: utils/cpupower-set.c:121 | ||
705 | #, c-format | ||
706 | msgid "Error setting sched-mc %s\n" | ||
707 | msgstr "" | ||
708 | |||
709 | #: utils/cpupower-set.c:127 | ||
710 | #, c-format | ||
711 | msgid "Error setting sched-smt %s\n" | ||
712 | msgstr "" | ||
713 | |||
714 | #: utils/cpupower-set.c:146 | ||
715 | #, c-format | ||
716 | msgid "Error setting perf-bias value on CPU %d\n" | ||
717 | msgstr "" | ||
718 | |||
719 | #: utils/cpupower-info.c:21 | ||
720 | #, c-format | ||
721 | msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" | ||
722 | msgstr "" | ||
723 | |||
724 | #: utils/cpupower-info.c:23 | ||
725 | #, c-format | ||
726 | msgid "" | ||
727 | " -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
728 | " Intel models [0-15], see manpage for details\n" | ||
729 | msgstr "" | ||
730 | |||
731 | #: utils/cpupower-info.c:25 | ||
732 | #, fuzzy, c-format | ||
733 | msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n" | ||
734 | msgstr " -p, --policy Zjistà aktuálnà taktiku cpufreq *\n" | ||
735 | |||
736 | #: utils/cpupower-info.c:26 | ||
737 | #, c-format | ||
738 | msgid "" | ||
739 | " -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n" | ||
740 | msgstr "" | ||
741 | |||
742 | #: utils/cpupower-info.c:28 | ||
743 | #, c-format | ||
744 | msgid "" | ||
745 | "\n" | ||
746 | "Passing no option will show all info, by default only on core 0\n" | ||
747 | msgstr "" | ||
748 | |||
749 | #: utils/cpupower-info.c:102 | ||
750 | #, c-format | ||
751 | msgid "System's multi core scheduler setting: " | ||
752 | msgstr "" | ||
753 | |||
754 | #. if sysfs file is missing it's: errno == ENOENT | ||
755 | #: utils/cpupower-info.c:105 utils/cpupower-info.c:114 | ||
756 | #, c-format | ||
757 | msgid "not supported\n" | ||
758 | msgstr "" | ||
759 | |||
760 | #: utils/cpupower-info.c:111 | ||
761 | #, c-format | ||
762 | msgid "System's thread sibling scheduler setting: " | ||
763 | msgstr "" | ||
764 | |||
765 | #: utils/cpupower-info.c:126 | ||
766 | #, c-format | ||
767 | msgid "Intel's performance bias setting needs root privileges\n" | ||
768 | msgstr "" | ||
769 | |||
770 | #: utils/cpupower-info.c:128 | ||
771 | #, c-format | ||
772 | msgid "System does not support Intel's performance bias setting\n" | ||
773 | msgstr "" | ||
774 | |||
775 | #: utils/cpupower-info.c:147 | ||
776 | #, c-format | ||
777 | msgid "Could not read perf-bias value\n" | ||
778 | msgstr "" | ||
779 | |||
780 | #: utils/cpupower-info.c:150 | ||
781 | #, c-format | ||
782 | msgid "perf-bias: %d\n" | ||
783 | msgstr "" | ||
784 | |||
785 | #: utils/cpuidle-info.c:28 | ||
786 | #, fuzzy, c-format | ||
787 | msgid "Analyzing CPU %d:\n" | ||
788 | msgstr "analyzuji CPU %d:\n" | ||
789 | |||
790 | #: utils/cpuidle-info.c:32 | ||
791 | #, c-format | ||
792 | msgid "CPU %u: No idle states\n" | ||
793 | msgstr "" | ||
794 | |||
795 | #: utils/cpuidle-info.c:36 | ||
796 | #, c-format | ||
797 | msgid "CPU %u: Can't read idle state info\n" | ||
798 | msgstr "" | ||
799 | |||
800 | #: utils/cpuidle-info.c:41 | ||
801 | #, c-format | ||
802 | msgid "Could not determine max idle state %u\n" | ||
803 | msgstr "" | ||
804 | |||
805 | #: utils/cpuidle-info.c:46 | ||
806 | #, c-format | ||
807 | msgid "Number of idle states: %d\n" | ||
808 | msgstr "" | ||
809 | |||
810 | #: utils/cpuidle-info.c:48 | ||
811 | #, fuzzy, c-format | ||
812 | msgid "Available idle states:" | ||
813 | msgstr " dostupné frekvence: " | ||
814 | |||
815 | #: utils/cpuidle-info.c:71 | ||
816 | #, c-format | ||
817 | msgid "Flags/Description: %s\n" | ||
818 | msgstr "" | ||
819 | |||
820 | #: utils/cpuidle-info.c:74 | ||
821 | #, c-format | ||
822 | msgid "Latency: %lu\n" | ||
823 | msgstr "" | ||
824 | |||
825 | #: utils/cpuidle-info.c:76 | ||
826 | #, c-format | ||
827 | msgid "Usage: %lu\n" | ||
828 | msgstr "" | ||
829 | |||
830 | #: utils/cpuidle-info.c:78 | ||
831 | #, c-format | ||
832 | msgid "Duration: %llu\n" | ||
833 | msgstr "" | ||
834 | |||
835 | #: utils/cpuidle-info.c:90 | ||
836 | #, c-format | ||
837 | msgid "Could not determine cpuidle driver\n" | ||
838 | msgstr "" | ||
839 | |||
840 | #: utils/cpuidle-info.c:94 | ||
841 | #, fuzzy, c-format | ||
842 | msgid "CPUidle driver: %s\n" | ||
843 | msgstr " ovladaÄ: %s\n" | ||
844 | |||
845 | #: utils/cpuidle-info.c:99 | ||
846 | #, c-format | ||
847 | msgid "Could not determine cpuidle governor\n" | ||
848 | msgstr "" | ||
849 | |||
850 | #: utils/cpuidle-info.c:103 | ||
851 | #, c-format | ||
852 | msgid "CPUidle governor: %s\n" | ||
853 | msgstr "" | ||
854 | |||
855 | #: utils/cpuidle-info.c:122 | ||
856 | #, c-format | ||
857 | msgid "CPU %u: Can't read C-state info\n" | ||
858 | msgstr "" | ||
859 | |||
860 | #. printf("Cstates: %d\n", cstates); | ||
861 | #: utils/cpuidle-info.c:127 | ||
862 | #, c-format | ||
863 | msgid "active state: C0\n" | ||
864 | msgstr "" | ||
865 | |||
866 | #: utils/cpuidle-info.c:128 | ||
867 | #, c-format | ||
868 | msgid "max_cstate: C%u\n" | ||
869 | msgstr "" | ||
870 | |||
871 | #: utils/cpuidle-info.c:129 | ||
872 | #, c-format | ||
873 | msgid "maximum allowed latency: %lu usec\n" | ||
874 | msgstr "" | ||
875 | |||
876 | #: utils/cpuidle-info.c:130 | ||
877 | #, c-format | ||
878 | msgid "states:\t\n" | ||
879 | msgstr "" | ||
880 | |||
881 | #: utils/cpuidle-info.c:132 | ||
882 | #, c-format | ||
883 | msgid " C%d: type[C%d] " | ||
884 | msgstr "" | ||
885 | |||
886 | #: utils/cpuidle-info.c:134 | ||
887 | #, c-format | ||
888 | msgid "promotion[--] demotion[--] " | ||
889 | msgstr "" | ||
890 | |||
891 | #: utils/cpuidle-info.c:135 | ||
892 | #, c-format | ||
893 | msgid "latency[%03lu] " | ||
894 | msgstr "" | ||
895 | |||
896 | #: utils/cpuidle-info.c:137 | ||
897 | #, c-format | ||
898 | msgid "usage[%08lu] " | ||
899 | msgstr "" | ||
900 | |||
901 | #: utils/cpuidle-info.c:139 | ||
902 | #, c-format | ||
903 | msgid "duration[%020Lu] \n" | ||
904 | msgstr "" | ||
905 | |||
906 | #: utils/cpuidle-info.c:147 | ||
907 | #, fuzzy, c-format | ||
908 | msgid "Usage: cpupower idleinfo [options]\n" | ||
909 | msgstr "UžitÃ: cpufreq-info [pÅ™epÃnaÄe]\n" | ||
910 | |||
911 | #: utils/cpuidle-info.c:149 | ||
912 | #, fuzzy, c-format | ||
913 | msgid " -s, --silent Only show general C-state information\n" | ||
914 | msgstr " -e, --debug VypÃÅ¡e ladicà informace\n" | ||
915 | |||
916 | #: utils/cpuidle-info.c:150 | ||
917 | #, fuzzy, c-format | ||
918 | msgid "" | ||
919 | " -o, --proc Prints out information like provided by the /proc/" | ||
920 | "acpi/processor/*/power\n" | ||
921 | " interface in older kernels\n" | ||
922 | msgstr "" | ||
923 | " -o, --proc VypÃÅ¡e informace ve formátu, jaký použÃvalo rozhranÃ\n" | ||
924 | " /proc/cpufreq v kernelech Å™ady 2.4 a Äasné 2.6\n" | ||
925 | |||
926 | #: utils/cpuidle-info.c:209 | ||
927 | #, fuzzy, c-format | ||
928 | msgid "You can't specify more than one output-specific argument\n" | ||
929 | msgstr "" | ||
930 | "Nelze zadat vÃce než jeden parametr -c nebo --cpu\n" | ||
931 | "anebo vÃce než jeden parametr urÄujÃcà výstup\n" | ||
932 | |||
933 | #~ msgid "" | ||
934 | #~ " -c CPU, --cpu CPU CPU number which information shall be determined " | ||
935 | #~ "about\n" | ||
936 | #~ msgstr "" | ||
937 | #~ " -c CPU, --cpu CPU ÄŒÃslo CPU, o kterém se majà zjistit informace\n" | ||
938 | |||
939 | #~ msgid "" | ||
940 | #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " | ||
941 | #~ "modified\n" | ||
942 | #~ msgstr "" | ||
943 | #~ " -c CPU, --cpu CPU ÄŒÃslo CPU pro který se má provést nastavenà " | ||
944 | #~ "cpufreq\n" | ||
diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po new file mode 100644 index 000000000000..78c09e51663a --- /dev/null +++ b/tools/power/cpupower/po/de.po | |||
@@ -0,0 +1,961 @@ | |||
1 | # German translations for cpufrequtils package | ||
2 | # German messages for cpufrequtils. | ||
3 | # Copyright (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.net> | ||
4 | # This file is distributed under the same license as the cpufrequtils package. | ||
5 | # | ||
6 | msgid "" | ||
7 | msgstr "" | ||
8 | "Project-Id-Version: cpufrequtils 006\n" | ||
9 | "Report-Msgid-Bugs-To: \n" | ||
10 | "POT-Creation-Date: 2011-03-08 17:03+0100\n" | ||
11 | "PO-Revision-Date: 2009-08-08 17:18+0100\n" | ||
12 | "Last-Translator: <linux@dominikbrodowski.net>\n" | ||
13 | "Language-Team: NONE\n" | ||
14 | "Language: \n" | ||
15 | "MIME-Version: 1.0\n" | ||
16 | "Content-Type: text/plain; charset=ISO-8859-1\n" | ||
17 | "Content-Transfer-Encoding: 8bit\n" | ||
18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" | ||
19 | |||
20 | #: utils/idle_monitor/nhm_idle.c:36 | ||
21 | msgid "Processor Core C3" | ||
22 | msgstr "" | ||
23 | |||
24 | #: utils/idle_monitor/nhm_idle.c:43 | ||
25 | msgid "Processor Core C6" | ||
26 | msgstr "" | ||
27 | |||
28 | #: utils/idle_monitor/nhm_idle.c:51 | ||
29 | msgid "Processor Package C3" | ||
30 | msgstr "" | ||
31 | |||
32 | #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 | ||
33 | msgid "Processor Package C6" | ||
34 | msgstr "" | ||
35 | |||
36 | #: utils/idle_monitor/snb_idle.c:33 | ||
37 | msgid "Processor Core C7" | ||
38 | msgstr "" | ||
39 | |||
40 | #: utils/idle_monitor/snb_idle.c:40 | ||
41 | msgid "Processor Package C2" | ||
42 | msgstr "" | ||
43 | |||
44 | #: utils/idle_monitor/snb_idle.c:47 | ||
45 | msgid "Processor Package C7" | ||
46 | msgstr "" | ||
47 | |||
48 | #: utils/idle_monitor/amd_fam14h_idle.c:56 | ||
49 | msgid "Package in sleep state (PC1 or deeper)" | ||
50 | msgstr "" | ||
51 | |||
52 | #: utils/idle_monitor/amd_fam14h_idle.c:63 | ||
53 | msgid "Processor Package C1" | ||
54 | msgstr "" | ||
55 | |||
56 | #: utils/idle_monitor/amd_fam14h_idle.c:77 | ||
57 | msgid "North Bridge P1 boolean counter (returns 0 or 1)" | ||
58 | msgstr "" | ||
59 | |||
60 | #: utils/idle_monitor/mperf_monitor.c:35 | ||
61 | msgid "Processor Core not idle" | ||
62 | msgstr "" | ||
63 | |||
64 | #: utils/idle_monitor/mperf_monitor.c:42 | ||
65 | msgid "Processor Core in an idle state" | ||
66 | msgstr "" | ||
67 | |||
68 | #: utils/idle_monitor/mperf_monitor.c:50 | ||
69 | msgid "Average Frequency (including boost) in MHz" | ||
70 | msgstr "" | ||
71 | |||
72 | #: utils/idle_monitor/cpupower-monitor.c:66 | ||
73 | #, c-format | ||
74 | msgid "" | ||
75 | "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
76 | "interval_sec | -c command ...]\n" | ||
77 | msgstr "" | ||
78 | |||
79 | #: utils/idle_monitor/cpupower-monitor.c:69 | ||
80 | #, c-format | ||
81 | msgid "" | ||
82 | "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
83 | "interval_sec | -c command ...]\n" | ||
84 | msgstr "" | ||
85 | |||
86 | #: utils/idle_monitor/cpupower-monitor.c:71 | ||
87 | #, c-format | ||
88 | msgid "\t -v: be more verbose\n" | ||
89 | msgstr "" | ||
90 | |||
91 | #: utils/idle_monitor/cpupower-monitor.c:73 | ||
92 | #, c-format | ||
93 | msgid "\t -h: print this help\n" | ||
94 | msgstr "" | ||
95 | |||
96 | #: utils/idle_monitor/cpupower-monitor.c:74 | ||
97 | #, c-format | ||
98 | msgid "\t -i: time intervall to measure for in seconds (default 1)\n" | ||
99 | msgstr "" | ||
100 | |||
101 | #: utils/idle_monitor/cpupower-monitor.c:75 | ||
102 | #, c-format | ||
103 | msgid "\t -t: show CPU topology/hierarchy\n" | ||
104 | msgstr "" | ||
105 | |||
106 | #: utils/idle_monitor/cpupower-monitor.c:76 | ||
107 | #, c-format | ||
108 | msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" | ||
109 | msgstr "" | ||
110 | |||
111 | #: utils/idle_monitor/cpupower-monitor.c:77 | ||
112 | #, c-format | ||
113 | msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" | ||
114 | msgstr "" | ||
115 | |||
116 | #: utils/idle_monitor/cpupower-monitor.c:79 | ||
117 | #, c-format | ||
118 | msgid "" | ||
119 | "only one of: -t, -l, -m are allowed\n" | ||
120 | "If none of them is passed," | ||
121 | msgstr "" | ||
122 | |||
123 | #: utils/idle_monitor/cpupower-monitor.c:80 | ||
124 | #, c-format | ||
125 | msgid " all supported monitors are shown\n" | ||
126 | msgstr "" | ||
127 | |||
128 | #: utils/idle_monitor/cpupower-monitor.c:197 | ||
129 | #, c-format | ||
130 | msgid "Monitor %s, Counter %s has no count function. Implementation error\n" | ||
131 | msgstr "" | ||
132 | |||
133 | #: utils/idle_monitor/cpupower-monitor.c:207 | ||
134 | #, c-format | ||
135 | msgid " *is offline\n" | ||
136 | msgstr "" | ||
137 | |||
138 | #: utils/idle_monitor/cpupower-monitor.c:236 | ||
139 | #, c-format | ||
140 | msgid "%s: max monitor name length (%d) exceeded\n" | ||
141 | msgstr "" | ||
142 | |||
143 | #: utils/idle_monitor/cpupower-monitor.c:250 | ||
144 | #, c-format | ||
145 | msgid "No matching monitor found in %s, try -l option\n" | ||
146 | msgstr "" | ||
147 | |||
148 | #: utils/idle_monitor/cpupower-monitor.c:266 | ||
149 | #, c-format | ||
150 | msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" | ||
151 | msgstr "" | ||
152 | |||
153 | #: utils/idle_monitor/cpupower-monitor.c:319 | ||
154 | #, c-format | ||
155 | msgid "%s took %.5f seconds and exited with status %d\n" | ||
156 | msgstr "" | ||
157 | |||
158 | #: utils/idle_monitor/cpupower-monitor.c:406 | ||
159 | #, c-format | ||
160 | msgid "Cannot read number of available processors\n" | ||
161 | msgstr "" | ||
162 | |||
163 | #: utils/idle_monitor/cpupower-monitor.c:417 | ||
164 | #, c-format | ||
165 | msgid "Available monitor %s needs root access\n" | ||
166 | msgstr "" | ||
167 | |||
168 | #: utils/idle_monitor/cpupower-monitor.c:428 | ||
169 | #, c-format | ||
170 | msgid "No HW Cstate monitors found\n" | ||
171 | msgstr "" | ||
172 | |||
173 | #: utils/cpupower.c:78 | ||
174 | #, c-format | ||
175 | msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" | ||
176 | msgstr "" | ||
177 | |||
178 | #: utils/cpupower.c:79 | ||
179 | #, c-format | ||
180 | msgid "cpupower --version\n" | ||
181 | msgstr "" | ||
182 | |||
183 | #: utils/cpupower.c:80 | ||
184 | #, c-format | ||
185 | msgid "Supported subcommands are:\n" | ||
186 | msgstr "" | ||
187 | |||
188 | #: utils/cpupower.c:83 | ||
189 | #, c-format | ||
190 | msgid "" | ||
191 | "\n" | ||
192 | "Some subcommands can make use of the -c cpulist option.\n" | ||
193 | msgstr "" | ||
194 | |||
195 | #: utils/cpupower.c:84 | ||
196 | #, c-format | ||
197 | msgid "Look at the general cpupower manpage how to use it\n" | ||
198 | msgstr "" | ||
199 | |||
200 | #: utils/cpupower.c:85 | ||
201 | #, c-format | ||
202 | msgid "and read up the subcommand's manpage whether it is supported.\n" | ||
203 | msgstr "" | ||
204 | |||
205 | #: utils/cpupower.c:86 | ||
206 | #, c-format | ||
207 | msgid "" | ||
208 | "\n" | ||
209 | "Use cpupower help subcommand for getting help for above subcommands.\n" | ||
210 | msgstr "" | ||
211 | |||
212 | #: utils/cpupower.c:91 | ||
213 | #, c-format | ||
214 | msgid "Report errors and bugs to %s, please.\n" | ||
215 | msgstr "Bitte melden Sie Fehler an %s.\n" | ||
216 | |||
217 | #: utils/cpupower.c:114 | ||
218 | #, c-format | ||
219 | msgid "Error parsing cpu list\n" | ||
220 | msgstr "" | ||
221 | |||
222 | #: utils/cpupower.c:172 | ||
223 | #, c-format | ||
224 | msgid "Subcommand %s needs root privileges\n" | ||
225 | msgstr "" | ||
226 | |||
227 | #: utils/cpufreq-info.c:31 | ||
228 | #, c-format | ||
229 | msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" | ||
230 | msgstr "" | ||
231 | "Konnte nicht die Anzahl der CPUs herausfinden (%s : %s), nehme daher 1 an.\n" | ||
232 | |||
233 | #: utils/cpufreq-info.c:63 | ||
234 | #, c-format | ||
235 | msgid "" | ||
236 | " minimum CPU frequency - maximum CPU frequency - governor\n" | ||
237 | msgstr "" | ||
238 | " minimale CPU-Taktfreq. - maximale CPU-Taktfreq. - Regler \n" | ||
239 | |||
240 | #: utils/cpufreq-info.c:151 | ||
241 | #, c-format | ||
242 | msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" | ||
243 | msgstr "" | ||
244 | |||
245 | #. P state changes via MSR are identified via cpuid 80000007 | ||
246 | #. on Intel and AMD, but we assume boost capable machines can do that | ||
247 | #. if (cpuid_eax(0x80000000) >= 0x80000007 | ||
248 | #. && (cpuid_edx(0x80000007) & (1 << 7))) | ||
249 | #. | ||
250 | #: utils/cpufreq-info.c:161 | ||
251 | #, c-format | ||
252 | msgid " boost state support: \n" | ||
253 | msgstr "" | ||
254 | |||
255 | #: utils/cpufreq-info.c:163 | ||
256 | #, c-format | ||
257 | msgid " Supported: %s\n" | ||
258 | msgstr "" | ||
259 | |||
260 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
261 | msgid "yes" | ||
262 | msgstr "" | ||
263 | |||
264 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
265 | msgid "no" | ||
266 | msgstr "" | ||
267 | |||
268 | #: utils/cpufreq-info.c:164 | ||
269 | #, fuzzy, c-format | ||
270 | msgid " Active: %s\n" | ||
271 | msgstr " Treiber: %s\n" | ||
272 | |||
273 | #: utils/cpufreq-info.c:177 | ||
274 | #, c-format | ||
275 | msgid " Boost States: %d\n" | ||
276 | msgstr "" | ||
277 | |||
278 | #: utils/cpufreq-info.c:178 | ||
279 | #, c-format | ||
280 | msgid " Total States: %d\n" | ||
281 | msgstr "" | ||
282 | |||
283 | #: utils/cpufreq-info.c:181 | ||
284 | #, c-format | ||
285 | msgid " Pstate-Pb%d: %luMHz (boost state)\n" | ||
286 | msgstr "" | ||
287 | |||
288 | #: utils/cpufreq-info.c:184 | ||
289 | #, c-format | ||
290 | msgid " Pstate-P%d: %luMHz\n" | ||
291 | msgstr "" | ||
292 | |||
293 | #: utils/cpufreq-info.c:211 | ||
294 | #, c-format | ||
295 | msgid " no or unknown cpufreq driver is active on this CPU\n" | ||
296 | msgstr " kein oder nicht bestimmbarer cpufreq-Treiber aktiv\n" | ||
297 | |||
298 | #: utils/cpufreq-info.c:213 | ||
299 | #, c-format | ||
300 | msgid " driver: %s\n" | ||
301 | msgstr " Treiber: %s\n" | ||
302 | |||
303 | #: utils/cpufreq-info.c:219 | ||
304 | #, c-format | ||
305 | msgid " CPUs which run at the same hardware frequency: " | ||
306 | msgstr " Folgende CPUs laufen mit der gleichen Hardware-Taktfrequenz: " | ||
307 | |||
308 | #: utils/cpufreq-info.c:230 | ||
309 | #, c-format | ||
310 | msgid " CPUs which need to have their frequency coordinated by software: " | ||
311 | msgstr " Die Taktfrequenz folgender CPUs werden per Software koordiniert: " | ||
312 | |||
313 | #: utils/cpufreq-info.c:241 | ||
314 | #, c-format | ||
315 | msgid " maximum transition latency: " | ||
316 | msgstr " Maximale Dauer eines Taktfrequenzwechsels: " | ||
317 | |||
318 | #: utils/cpufreq-info.c:247 | ||
319 | #, c-format | ||
320 | msgid " hardware limits: " | ||
321 | msgstr " Hardwarebedingte Grenzen der Taktfrequenz: " | ||
322 | |||
323 | #: utils/cpufreq-info.c:256 | ||
324 | #, c-format | ||
325 | msgid " available frequency steps: " | ||
326 | msgstr " mögliche Taktfrequenzen: " | ||
327 | |||
328 | #: utils/cpufreq-info.c:269 | ||
329 | #, c-format | ||
330 | msgid " available cpufreq governors: " | ||
331 | msgstr " mögliche Regler: " | ||
332 | |||
333 | #: utils/cpufreq-info.c:280 | ||
334 | #, c-format | ||
335 | msgid " current policy: frequency should be within " | ||
336 | msgstr " momentane Taktik: die Frequenz soll innerhalb " | ||
337 | |||
338 | #: utils/cpufreq-info.c:282 | ||
339 | #, c-format | ||
340 | msgid " and " | ||
341 | msgstr " und " | ||
342 | |||
343 | #: utils/cpufreq-info.c:286 | ||
344 | #, c-format | ||
345 | msgid "" | ||
346 | "The governor \"%s\" may decide which speed to use\n" | ||
347 | " within this range.\n" | ||
348 | msgstr "" | ||
349 | " liegen. Der Regler \"%s\" kann frei entscheiden,\n" | ||
350 | " welche Taktfrequenz innerhalb dieser Grenze verwendet " | ||
351 | "wird.\n" | ||
352 | |||
353 | #: utils/cpufreq-info.c:293 | ||
354 | #, c-format | ||
355 | msgid " current CPU frequency is " | ||
356 | msgstr " momentane Taktfrequenz ist " | ||
357 | |||
358 | #: utils/cpufreq-info.c:296 | ||
359 | #, c-format | ||
360 | msgid " (asserted by call to hardware)" | ||
361 | msgstr " (verifiziert durch Nachfrage bei der Hardware)" | ||
362 | |||
363 | #: utils/cpufreq-info.c:304 | ||
364 | #, c-format | ||
365 | msgid " cpufreq stats: " | ||
366 | msgstr " Statistik:" | ||
367 | |||
368 | #: utils/cpufreq-info.c:472 | ||
369 | #, fuzzy, c-format | ||
370 | msgid "Usage: cpupower freqinfo [options]\n" | ||
371 | msgstr "Aufruf: cpufreq-info [Optionen]\n" | ||
372 | |||
373 | #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 | ||
374 | #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 | ||
375 | #, c-format | ||
376 | msgid "Options:\n" | ||
377 | msgstr "Optionen:\n" | ||
378 | |||
379 | #: utils/cpufreq-info.c:474 | ||
380 | #, fuzzy, c-format | ||
381 | msgid " -e, --debug Prints out debug information [default]\n" | ||
382 | msgstr "" | ||
383 | " -e, --debug Erzeugt detaillierte Informationen, hilfreich\n" | ||
384 | " zum Aufspüren von Fehlern\n" | ||
385 | |||
386 | #: utils/cpufreq-info.c:475 | ||
387 | #, c-format | ||
388 | msgid "" | ||
389 | " -f, --freq Get frequency the CPU currently runs at, according\n" | ||
390 | " to the cpufreq core *\n" | ||
391 | msgstr "" | ||
392 | " -f, --freq Findet die momentane CPU-Taktfrquenz heraus (nach\n" | ||
393 | " Meinung des Betriebssystems) *\n" | ||
394 | |||
395 | #: utils/cpufreq-info.c:477 | ||
396 | #, c-format | ||
397 | msgid "" | ||
398 | " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
399 | " it from hardware (only available to root) *\n" | ||
400 | msgstr "" | ||
401 | " -w, --hwfreq Findet die momentane CPU-Taktfrequenz heraus\n" | ||
402 | " (verifiziert durch Nachfrage bei der Hardware)\n" | ||
403 | " [nur der Administrator kann dies tun] *\n" | ||
404 | |||
405 | #: utils/cpufreq-info.c:479 | ||
406 | #, c-format | ||
407 | msgid "" | ||
408 | " -l, --hwlimits Determine the minimum and maximum CPU frequency " | ||
409 | "allowed *\n" | ||
410 | msgstr "" | ||
411 | " -l, --hwlimits Findet die minimale und maximale Taktfrequenz heraus " | ||
412 | "*\n" | ||
413 | |||
414 | #: utils/cpufreq-info.c:480 | ||
415 | #, c-format | ||
416 | msgid " -d, --driver Determines the used cpufreq kernel driver *\n" | ||
417 | msgstr " -d, --driver Findet den momentanen Treiber heraus *\n" | ||
418 | |||
419 | #: utils/cpufreq-info.c:481 | ||
420 | #, c-format | ||
421 | msgid " -p, --policy Gets the currently used cpufreq policy *\n" | ||
422 | msgstr " -p, --policy Findet die momentane Taktik heraus *\n" | ||
423 | |||
424 | #: utils/cpufreq-info.c:482 | ||
425 | #, c-format | ||
426 | msgid " -g, --governors Determines available cpufreq governors *\n" | ||
427 | msgstr " -g, --governors Erzeugt eine Liste mit verfügbaren Reglern *\n" | ||
428 | |||
429 | #: utils/cpufreq-info.c:483 | ||
430 | #, c-format | ||
431 | msgid "" | ||
432 | " -r, --related-cpus Determines which CPUs run at the same hardware " | ||
433 | "frequency *\n" | ||
434 | msgstr "" | ||
435 | " -r, --related-cpus Findet heraus, welche CPUs mit derselben " | ||
436 | "physikalischen\n" | ||
437 | " Taktfrequenz laufen *\n" | ||
438 | |||
439 | #: utils/cpufreq-info.c:484 | ||
440 | #, c-format | ||
441 | msgid "" | ||
442 | " -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
443 | " coordinated by software *\n" | ||
444 | msgstr "" | ||
445 | " -a, --affected-cpus Findet heraus, von welchen CPUs die Taktfrequenz " | ||
446 | "durch\n" | ||
447 | " Software koordiniert werden muss *\n" | ||
448 | |||
449 | #: utils/cpufreq-info.c:486 | ||
450 | #, c-format | ||
451 | msgid " -s, --stats Shows cpufreq statistics if available\n" | ||
452 | msgstr "" | ||
453 | " -s, --stats Zeigt, sofern möglich, Statistiken über cpufreq an.\n" | ||
454 | |||
455 | #: utils/cpufreq-info.c:487 | ||
456 | #, c-format | ||
457 | msgid "" | ||
458 | " -y, --latency Determines the maximum latency on CPU frequency " | ||
459 | "changes *\n" | ||
460 | msgstr "" | ||
461 | " -y, --latency Findet die maximale Dauer eines Taktfrequenzwechsels " | ||
462 | "heraus *\n" | ||
463 | |||
464 | #: utils/cpufreq-info.c:488 | ||
465 | #, c-format | ||
466 | msgid " -b, --boost Checks for turbo or boost modes *\n" | ||
467 | msgstr "" | ||
468 | |||
469 | #: utils/cpufreq-info.c:489 | ||
470 | #, c-format | ||
471 | msgid "" | ||
472 | " -o, --proc Prints out information like provided by the /proc/" | ||
473 | "cpufreq\n" | ||
474 | " interface in 2.4. and early 2.6. kernels\n" | ||
475 | msgstr "" | ||
476 | " -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " | ||
477 | "dem\n" | ||
478 | " der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" | ||
479 | " Kernel-Versionen\n" | ||
480 | |||
481 | #: utils/cpufreq-info.c:491 | ||
482 | #, c-format | ||
483 | msgid "" | ||
484 | " -m, --human human-readable output for the -f, -w, -s and -y " | ||
485 | "parameters\n" | ||
486 | msgstr "" | ||
487 | " -m, --human Formatiert Taktfrequenz- und Zeitdauerangaben in " | ||
488 | "besser\n" | ||
489 | " lesbarer Form (MHz, GHz; us, ms)\n" | ||
490 | |||
491 | #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 | ||
492 | #, c-format | ||
493 | msgid " -h, --help Prints out this screen\n" | ||
494 | msgstr " -h, --help Gibt diese Kurzübersicht aus\n" | ||
495 | |||
496 | #: utils/cpufreq-info.c:495 | ||
497 | #, c-format | ||
498 | msgid "" | ||
499 | "If no argument or only the -c, --cpu parameter is given, debug output about\n" | ||
500 | "cpufreq is printed which is useful e.g. for reporting bugs.\n" | ||
501 | msgstr "" | ||
502 | "Sofern kein anderer Parameter als '-c, --cpu' angegeben wird, liefert " | ||
503 | "dieses\n" | ||
504 | "Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n" | ||
505 | |||
506 | #: utils/cpufreq-info.c:497 | ||
507 | #, c-format | ||
508 | msgid "" | ||
509 | "For the arguments marked with *, omitting the -c or --cpu argument is\n" | ||
510 | "equivalent to setting it to zero\n" | ||
511 | msgstr "" | ||
512 | "Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n" | ||
513 | "mittels -c oder --cpu etwas anderes angegeben wird\n" | ||
514 | |||
515 | #: utils/cpufreq-info.c:580 | ||
516 | #, c-format | ||
517 | msgid "" | ||
518 | "The argument passed to this tool can't be combined with passing a --cpu " | ||
519 | "argument\n" | ||
520 | msgstr "Diese Option kann nicht mit der --cpu-Option kombiniert werden\n" | ||
521 | |||
522 | #: utils/cpufreq-info.c:596 | ||
523 | #, c-format | ||
524 | msgid "" | ||
525 | "You can't specify more than one --cpu parameter and/or\n" | ||
526 | "more than one output-specific argument\n" | ||
527 | msgstr "" | ||
528 | "Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n" | ||
529 | "informationsspezifischen Parameter gleichzeitig angeben\n" | ||
530 | |||
531 | #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 | ||
532 | #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 | ||
533 | #, c-format | ||
534 | msgid "invalid or unknown argument\n" | ||
535 | msgstr "unbekannter oder falscher Parameter\n" | ||
536 | |||
537 | #: utils/cpufreq-info.c:617 | ||
538 | #, c-format | ||
539 | msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" | ||
540 | msgstr "" | ||
541 | "Konnte nicht die CPU %d analysieren, da sie (scheinbar?) nicht existiert.\n" | ||
542 | |||
543 | #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 | ||
544 | #, c-format | ||
545 | msgid "analyzing CPU %d:\n" | ||
546 | msgstr "analysiere CPU %d:\n" | ||
547 | |||
548 | #: utils/cpufreq-set.c:25 | ||
549 | #, fuzzy, c-format | ||
550 | msgid "Usage: cpupower frequency-set [options]\n" | ||
551 | msgstr "Aufruf: cpufreq-set [Optionen]\n" | ||
552 | |||
553 | #: utils/cpufreq-set.c:27 | ||
554 | #, c-format | ||
555 | msgid "" | ||
556 | " -d FREQ, --min FREQ new minimum CPU frequency the governor may " | ||
557 | "select\n" | ||
558 | msgstr "" | ||
559 | " -d FREQ, --min FREQ neue minimale Taktfrequenz, die der Regler\n" | ||
560 | " auswählen darf\n" | ||
561 | |||
562 | #: utils/cpufreq-set.c:28 | ||
563 | #, c-format | ||
564 | msgid "" | ||
565 | " -u FREQ, --max FREQ new maximum CPU frequency the governor may " | ||
566 | "select\n" | ||
567 | msgstr "" | ||
568 | " -u FREQ, --max FREQ neue maximale Taktfrequenz, die der Regler\n" | ||
569 | " auswählen darf\n" | ||
570 | |||
571 | #: utils/cpufreq-set.c:29 | ||
572 | #, c-format | ||
573 | msgid " -g GOV, --governor GOV new cpufreq governor\n" | ||
574 | msgstr " -g GOV, --governors GOV wechsle zu Regler GOV\n" | ||
575 | |||
576 | #: utils/cpufreq-set.c:30 | ||
577 | #, c-format | ||
578 | msgid "" | ||
579 | " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
580 | " governor to be available and loaded\n" | ||
581 | msgstr "" | ||
582 | " -f FREQ, --freq FREQ setze exakte Taktfrequenz. Benötigt den Regler\n" | ||
583 | " 'userspace'.\n" | ||
584 | |||
585 | #: utils/cpufreq-set.c:32 | ||
586 | #, c-format | ||
587 | msgid " -r, --related Switches all hardware-related CPUs\n" | ||
588 | msgstr "" | ||
589 | " -r, --related Setze Werte für alle CPUs, deren Taktfrequenz\n" | ||
590 | " hardwarebedingt identisch ist.\n" | ||
591 | |||
592 | #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 | ||
593 | #, c-format | ||
594 | msgid " -h, --help Prints out this screen\n" | ||
595 | msgstr " -h, --help Gibt diese Kurzübersicht aus\n" | ||
596 | |||
597 | #: utils/cpufreq-set.c:35 | ||
598 | #, fuzzy, c-format | ||
599 | msgid "" | ||
600 | "Notes:\n" | ||
601 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" | ||
602 | msgstr "" | ||
603 | "Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n" | ||
604 | "mittels -c oder --cpu etwas anderes angegeben wird\n" | ||
605 | |||
606 | #: utils/cpufreq-set.c:37 | ||
607 | #, fuzzy, c-format | ||
608 | msgid "" | ||
609 | "2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " | ||
610 | "parameter\n" | ||
611 | " except the -c CPU, --cpu CPU parameter\n" | ||
612 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
613 | " by postfixing the value with the wanted unit name, without any space\n" | ||
614 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
615 | msgstr "" | ||
616 | "Hinweise:\n" | ||
617 | "1. Sofern kein -c oder --cpu-Parameter angegeben ist, wird '--cpu 0'\n" | ||
618 | " angenommen\n" | ||
619 | "2. Der Parameter -f bzw. --freq kann mit keinem anderen als dem Parameter\n" | ||
620 | " -c bzw. --cpu kombiniert werden\n" | ||
621 | "3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n" | ||
622 | " werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n" | ||
623 | " die Einheit angegeben werden. (Bsp: 1GHz )\n" | ||
624 | " (FREQuenz in kHz =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
625 | |||
626 | #: utils/cpufreq-set.c:57 | ||
627 | #, c-format | ||
628 | msgid "" | ||
629 | "Error setting new values. Common errors:\n" | ||
630 | "- Do you have proper administration rights? (super-user?)\n" | ||
631 | "- Is the governor you requested available and modprobed?\n" | ||
632 | "- Trying to set an invalid policy?\n" | ||
633 | "- Trying to set a specific frequency, but userspace governor is not " | ||
634 | "available,\n" | ||
635 | " for example because of hardware which cannot be set to a specific " | ||
636 | "frequency\n" | ||
637 | " or because the userspace governor isn't loaded?\n" | ||
638 | msgstr "" | ||
639 | "Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n" | ||
640 | "- nicht ausreichende Rechte (Administrator)\n" | ||
641 | "- der Regler ist nicht verfügbar bzw. nicht geladen\n" | ||
642 | "- die angegebene Taktik ist inkorrekt\n" | ||
643 | "- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n" | ||
644 | " kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n" | ||
645 | |||
646 | #: utils/cpufreq-set.c:170 | ||
647 | #, c-format | ||
648 | msgid "wrong, unknown or unhandled CPU?\n" | ||
649 | msgstr "unbekannte oder nicht regelbare CPU\n" | ||
650 | |||
651 | #: utils/cpufreq-set.c:302 | ||
652 | #, c-format | ||
653 | msgid "" | ||
654 | "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
655 | "-g/--governor parameters\n" | ||
656 | msgstr "" | ||
657 | "Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, -u/--" | ||
658 | "max\n" | ||
659 | "oder -g/--governor kombiniert werden\n" | ||
660 | |||
661 | #: utils/cpufreq-set.c:308 | ||
662 | #, c-format | ||
663 | msgid "" | ||
664 | "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
665 | "-g/--governor must be passed\n" | ||
666 | msgstr "" | ||
667 | "Es muss mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max oder\n" | ||
668 | "-g/--governor angegeben werden.\n" | ||
669 | |||
670 | #: utils/cpufreq-set.c:347 | ||
671 | #, c-format | ||
672 | msgid "Setting cpu: %d\n" | ||
673 | msgstr "" | ||
674 | |||
675 | #: utils/cpupower-set.c:22 | ||
676 | #, c-format | ||
677 | msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" | ||
678 | msgstr "" | ||
679 | |||
680 | #: utils/cpupower-set.c:24 | ||
681 | #, c-format | ||
682 | msgid "" | ||
683 | " -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
684 | " Intel models [0-15], see manpage for details\n" | ||
685 | msgstr "" | ||
686 | |||
687 | #: utils/cpupower-set.c:26 | ||
688 | #, c-format | ||
689 | msgid "" | ||
690 | " -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n" | ||
691 | msgstr "" | ||
692 | |||
693 | #: utils/cpupower-set.c:27 | ||
694 | #, c-format | ||
695 | msgid "" | ||
696 | " -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler " | ||
697 | "policy.\n" | ||
698 | msgstr "" | ||
699 | |||
700 | #: utils/cpupower-set.c:80 | ||
701 | #, c-format | ||
702 | msgid "--perf-bias param out of range [0-%d]\n" | ||
703 | msgstr "" | ||
704 | |||
705 | #: utils/cpupower-set.c:91 | ||
706 | #, c-format | ||
707 | msgid "--sched-mc param out of range [0-%d]\n" | ||
708 | msgstr "" | ||
709 | |||
710 | #: utils/cpupower-set.c:102 | ||
711 | #, c-format | ||
712 | msgid "--sched-smt param out of range [0-%d]\n" | ||
713 | msgstr "" | ||
714 | |||
715 | #: utils/cpupower-set.c:121 | ||
716 | #, c-format | ||
717 | msgid "Error setting sched-mc %s\n" | ||
718 | msgstr "" | ||
719 | |||
720 | #: utils/cpupower-set.c:127 | ||
721 | #, c-format | ||
722 | msgid "Error setting sched-smt %s\n" | ||
723 | msgstr "" | ||
724 | |||
725 | #: utils/cpupower-set.c:146 | ||
726 | #, c-format | ||
727 | msgid "Error setting perf-bias value on CPU %d\n" | ||
728 | msgstr "" | ||
729 | |||
730 | #: utils/cpupower-info.c:21 | ||
731 | #, c-format | ||
732 | msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" | ||
733 | msgstr "" | ||
734 | |||
735 | #: utils/cpupower-info.c:23 | ||
736 | #, c-format | ||
737 | msgid "" | ||
738 | " -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
739 | " Intel models [0-15], see manpage for details\n" | ||
740 | msgstr "" | ||
741 | |||
742 | #: utils/cpupower-info.c:25 | ||
743 | #, fuzzy, c-format | ||
744 | msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n" | ||
745 | msgstr " -p, --policy Findet die momentane Taktik heraus *\n" | ||
746 | |||
747 | #: utils/cpupower-info.c:26 | ||
748 | #, c-format | ||
749 | msgid "" | ||
750 | " -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n" | ||
751 | msgstr "" | ||
752 | |||
753 | #: utils/cpupower-info.c:28 | ||
754 | #, c-format | ||
755 | msgid "" | ||
756 | "\n" | ||
757 | "Passing no option will show all info, by default only on core 0\n" | ||
758 | msgstr "" | ||
759 | |||
760 | #: utils/cpupower-info.c:102 | ||
761 | #, c-format | ||
762 | msgid "System's multi core scheduler setting: " | ||
763 | msgstr "" | ||
764 | |||
765 | #. if sysfs file is missing it's: errno == ENOENT | ||
766 | #: utils/cpupower-info.c:105 utils/cpupower-info.c:114 | ||
767 | #, c-format | ||
768 | msgid "not supported\n" | ||
769 | msgstr "" | ||
770 | |||
771 | #: utils/cpupower-info.c:111 | ||
772 | #, c-format | ||
773 | msgid "System's thread sibling scheduler setting: " | ||
774 | msgstr "" | ||
775 | |||
776 | #: utils/cpupower-info.c:126 | ||
777 | #, c-format | ||
778 | msgid "Intel's performance bias setting needs root privileges\n" | ||
779 | msgstr "" | ||
780 | |||
781 | #: utils/cpupower-info.c:128 | ||
782 | #, c-format | ||
783 | msgid "System does not support Intel's performance bias setting\n" | ||
784 | msgstr "" | ||
785 | |||
786 | #: utils/cpupower-info.c:147 | ||
787 | #, c-format | ||
788 | msgid "Could not read perf-bias value\n" | ||
789 | msgstr "" | ||
790 | |||
791 | #: utils/cpupower-info.c:150 | ||
792 | #, c-format | ||
793 | msgid "perf-bias: %d\n" | ||
794 | msgstr "" | ||
795 | |||
796 | #: utils/cpuidle-info.c:28 | ||
797 | #, fuzzy, c-format | ||
798 | msgid "Analyzing CPU %d:\n" | ||
799 | msgstr "analysiere CPU %d:\n" | ||
800 | |||
801 | #: utils/cpuidle-info.c:32 | ||
802 | #, c-format | ||
803 | msgid "CPU %u: No idle states\n" | ||
804 | msgstr "" | ||
805 | |||
806 | #: utils/cpuidle-info.c:36 | ||
807 | #, c-format | ||
808 | msgid "CPU %u: Can't read idle state info\n" | ||
809 | msgstr "" | ||
810 | |||
811 | #: utils/cpuidle-info.c:41 | ||
812 | #, c-format | ||
813 | msgid "Could not determine max idle state %u\n" | ||
814 | msgstr "" | ||
815 | |||
816 | #: utils/cpuidle-info.c:46 | ||
817 | #, c-format | ||
818 | msgid "Number of idle states: %d\n" | ||
819 | msgstr "" | ||
820 | |||
821 | #: utils/cpuidle-info.c:48 | ||
822 | #, fuzzy, c-format | ||
823 | msgid "Available idle states:" | ||
824 | msgstr " mögliche Taktfrequenzen: " | ||
825 | |||
826 | #: utils/cpuidle-info.c:71 | ||
827 | #, c-format | ||
828 | msgid "Flags/Description: %s\n" | ||
829 | msgstr "" | ||
830 | |||
831 | #: utils/cpuidle-info.c:74 | ||
832 | #, c-format | ||
833 | msgid "Latency: %lu\n" | ||
834 | msgstr "" | ||
835 | |||
836 | #: utils/cpuidle-info.c:76 | ||
837 | #, c-format | ||
838 | msgid "Usage: %lu\n" | ||
839 | msgstr "" | ||
840 | |||
841 | #: utils/cpuidle-info.c:78 | ||
842 | #, c-format | ||
843 | msgid "Duration: %llu\n" | ||
844 | msgstr "" | ||
845 | |||
846 | #: utils/cpuidle-info.c:90 | ||
847 | #, c-format | ||
848 | msgid "Could not determine cpuidle driver\n" | ||
849 | msgstr "" | ||
850 | |||
851 | #: utils/cpuidle-info.c:94 | ||
852 | #, fuzzy, c-format | ||
853 | msgid "CPUidle driver: %s\n" | ||
854 | msgstr " Treiber: %s\n" | ||
855 | |||
856 | #: utils/cpuidle-info.c:99 | ||
857 | #, c-format | ||
858 | msgid "Could not determine cpuidle governor\n" | ||
859 | msgstr "" | ||
860 | |||
861 | #: utils/cpuidle-info.c:103 | ||
862 | #, c-format | ||
863 | msgid "CPUidle governor: %s\n" | ||
864 | msgstr "" | ||
865 | |||
866 | #: utils/cpuidle-info.c:122 | ||
867 | #, c-format | ||
868 | msgid "CPU %u: Can't read C-state info\n" | ||
869 | msgstr "" | ||
870 | |||
871 | #. printf("Cstates: %d\n", cstates); | ||
872 | #: utils/cpuidle-info.c:127 | ||
873 | #, c-format | ||
874 | msgid "active state: C0\n" | ||
875 | msgstr "" | ||
876 | |||
877 | #: utils/cpuidle-info.c:128 | ||
878 | #, c-format | ||
879 | msgid "max_cstate: C%u\n" | ||
880 | msgstr "" | ||
881 | |||
882 | #: utils/cpuidle-info.c:129 | ||
883 | #, fuzzy, c-format | ||
884 | msgid "maximum allowed latency: %lu usec\n" | ||
885 | msgstr " Maximale Dauer eines Taktfrequenzwechsels: " | ||
886 | |||
887 | #: utils/cpuidle-info.c:130 | ||
888 | #, c-format | ||
889 | msgid "states:\t\n" | ||
890 | msgstr "" | ||
891 | |||
892 | #: utils/cpuidle-info.c:132 | ||
893 | #, c-format | ||
894 | msgid " C%d: type[C%d] " | ||
895 | msgstr "" | ||
896 | |||
897 | #: utils/cpuidle-info.c:134 | ||
898 | #, c-format | ||
899 | msgid "promotion[--] demotion[--] " | ||
900 | msgstr "" | ||
901 | |||
902 | #: utils/cpuidle-info.c:135 | ||
903 | #, c-format | ||
904 | msgid "latency[%03lu] " | ||
905 | msgstr "" | ||
906 | |||
907 | #: utils/cpuidle-info.c:137 | ||
908 | #, c-format | ||
909 | msgid "usage[%08lu] " | ||
910 | msgstr "" | ||
911 | |||
912 | #: utils/cpuidle-info.c:139 | ||
913 | #, c-format | ||
914 | msgid "duration[%020Lu] \n" | ||
915 | msgstr "" | ||
916 | |||
917 | #: utils/cpuidle-info.c:147 | ||
918 | #, fuzzy, c-format | ||
919 | msgid "Usage: cpupower idleinfo [options]\n" | ||
920 | msgstr "Aufruf: cpufreq-info [Optionen]\n" | ||
921 | |||
922 | #: utils/cpuidle-info.c:149 | ||
923 | #, fuzzy, c-format | ||
924 | msgid " -s, --silent Only show general C-state information\n" | ||
925 | msgstr "" | ||
926 | " -e, --debug Erzeugt detaillierte Informationen, hilfreich\n" | ||
927 | " zum Aufspüren von Fehlern\n" | ||
928 | |||
929 | #: utils/cpuidle-info.c:150 | ||
930 | #, fuzzy, c-format | ||
931 | msgid "" | ||
932 | " -o, --proc Prints out information like provided by the /proc/" | ||
933 | "acpi/processor/*/power\n" | ||
934 | " interface in older kernels\n" | ||
935 | msgstr "" | ||
936 | " -o, --proc Erzeugt Informationen in einem ähnlichem Format zu " | ||
937 | "dem\n" | ||
938 | " der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" | ||
939 | " Kernel-Versionen\n" | ||
940 | |||
941 | #: utils/cpuidle-info.c:209 | ||
942 | #, fuzzy, c-format | ||
943 | msgid "You can't specify more than one output-specific argument\n" | ||
944 | msgstr "" | ||
945 | "Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n" | ||
946 | "informationsspezifischen Parameter gleichzeitig angeben\n" | ||
947 | |||
948 | #~ msgid "" | ||
949 | #~ " -c CPU, --cpu CPU CPU number which information shall be determined " | ||
950 | #~ "about\n" | ||
951 | #~ msgstr "" | ||
952 | #~ " -c CPU, --cpu CPU Nummer der CPU, über die Informationen " | ||
953 | #~ "herausgefunden werden sollen\n" | ||
954 | |||
955 | #~ msgid "" | ||
956 | #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " | ||
957 | #~ "modified\n" | ||
958 | #~ msgstr "" | ||
959 | #~ " -c CPU, --cpu CPU Nummer der CPU, deren Taktfrequenz-" | ||
960 | #~ "Einstellung\n" | ||
961 | #~ " werden soll\n" | ||
diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po new file mode 100644 index 000000000000..245ad20a9bf9 --- /dev/null +++ b/tools/power/cpupower/po/fr.po | |||
@@ -0,0 +1,947 @@ | |||
1 | # French translations for cpufrequtils package | ||
2 | # Copyright (C) 2004 THE PACKAGE'S COPYRIGHT HOLDER | ||
3 | # This file is distributed under the same license as the cpufrequtils package. | ||
4 | # Ducrot Bruno <ducrot@poupinou.org>, 2004. | ||
5 | # | ||
6 | #, fuzzy | ||
7 | msgid "" | ||
8 | msgstr "" | ||
9 | "Project-Id-Version: cpufrequtils 0.1-pre2\n" | ||
10 | "Report-Msgid-Bugs-To: \n" | ||
11 | "POT-Creation-Date: 2011-03-08 17:03+0100\n" | ||
12 | "PO-Revision-Date: 2004-11-17 15:53+1000\n" | ||
13 | "Last-Translator: Bruno Ducrot <ducrot@poupinou.org>\n" | ||
14 | "Language-Team: NONE\n" | ||
15 | "Language: \n" | ||
16 | "MIME-Version: 1.0\n" | ||
17 | "Content-Type: text/plain; charset=ISO-8859-1\n" | ||
18 | "Content-Transfer-Encoding: 8bit\n" | ||
19 | |||
20 | #: utils/idle_monitor/nhm_idle.c:36 | ||
21 | msgid "Processor Core C3" | ||
22 | msgstr "" | ||
23 | |||
24 | #: utils/idle_monitor/nhm_idle.c:43 | ||
25 | msgid "Processor Core C6" | ||
26 | msgstr "" | ||
27 | |||
28 | #: utils/idle_monitor/nhm_idle.c:51 | ||
29 | msgid "Processor Package C3" | ||
30 | msgstr "" | ||
31 | |||
32 | #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 | ||
33 | msgid "Processor Package C6" | ||
34 | msgstr "" | ||
35 | |||
36 | #: utils/idle_monitor/snb_idle.c:33 | ||
37 | msgid "Processor Core C7" | ||
38 | msgstr "" | ||
39 | |||
40 | #: utils/idle_monitor/snb_idle.c:40 | ||
41 | msgid "Processor Package C2" | ||
42 | msgstr "" | ||
43 | |||
44 | #: utils/idle_monitor/snb_idle.c:47 | ||
45 | msgid "Processor Package C7" | ||
46 | msgstr "" | ||
47 | |||
48 | #: utils/idle_monitor/amd_fam14h_idle.c:56 | ||
49 | msgid "Package in sleep state (PC1 or deeper)" | ||
50 | msgstr "" | ||
51 | |||
52 | #: utils/idle_monitor/amd_fam14h_idle.c:63 | ||
53 | msgid "Processor Package C1" | ||
54 | msgstr "" | ||
55 | |||
56 | #: utils/idle_monitor/amd_fam14h_idle.c:77 | ||
57 | msgid "North Bridge P1 boolean counter (returns 0 or 1)" | ||
58 | msgstr "" | ||
59 | |||
60 | #: utils/idle_monitor/mperf_monitor.c:35 | ||
61 | msgid "Processor Core not idle" | ||
62 | msgstr "" | ||
63 | |||
64 | #: utils/idle_monitor/mperf_monitor.c:42 | ||
65 | msgid "Processor Core in an idle state" | ||
66 | msgstr "" | ||
67 | |||
68 | #: utils/idle_monitor/mperf_monitor.c:50 | ||
69 | msgid "Average Frequency (including boost) in MHz" | ||
70 | msgstr "" | ||
71 | |||
72 | #: utils/idle_monitor/cpupower-monitor.c:66 | ||
73 | #, c-format | ||
74 | msgid "" | ||
75 | "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
76 | "interval_sec | -c command ...]\n" | ||
77 | msgstr "" | ||
78 | |||
79 | #: utils/idle_monitor/cpupower-monitor.c:69 | ||
80 | #, c-format | ||
81 | msgid "" | ||
82 | "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
83 | "interval_sec | -c command ...]\n" | ||
84 | msgstr "" | ||
85 | |||
86 | #: utils/idle_monitor/cpupower-monitor.c:71 | ||
87 | #, c-format | ||
88 | msgid "\t -v: be more verbose\n" | ||
89 | msgstr "" | ||
90 | |||
91 | #: utils/idle_monitor/cpupower-monitor.c:73 | ||
92 | #, c-format | ||
93 | msgid "\t -h: print this help\n" | ||
94 | msgstr "" | ||
95 | |||
96 | #: utils/idle_monitor/cpupower-monitor.c:74 | ||
97 | #, c-format | ||
98 | msgid "\t -i: time intervall to measure for in seconds (default 1)\n" | ||
99 | msgstr "" | ||
100 | |||
101 | #: utils/idle_monitor/cpupower-monitor.c:75 | ||
102 | #, c-format | ||
103 | msgid "\t -t: show CPU topology/hierarchy\n" | ||
104 | msgstr "" | ||
105 | |||
106 | #: utils/idle_monitor/cpupower-monitor.c:76 | ||
107 | #, c-format | ||
108 | msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" | ||
109 | msgstr "" | ||
110 | |||
111 | #: utils/idle_monitor/cpupower-monitor.c:77 | ||
112 | #, c-format | ||
113 | msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" | ||
114 | msgstr "" | ||
115 | |||
116 | #: utils/idle_monitor/cpupower-monitor.c:79 | ||
117 | #, c-format | ||
118 | msgid "" | ||
119 | "only one of: -t, -l, -m are allowed\n" | ||
120 | "If none of them is passed," | ||
121 | msgstr "" | ||
122 | |||
123 | #: utils/idle_monitor/cpupower-monitor.c:80 | ||
124 | #, c-format | ||
125 | msgid " all supported monitors are shown\n" | ||
126 | msgstr "" | ||
127 | |||
128 | #: utils/idle_monitor/cpupower-monitor.c:197 | ||
129 | #, c-format | ||
130 | msgid "Monitor %s, Counter %s has no count function. Implementation error\n" | ||
131 | msgstr "" | ||
132 | |||
133 | #: utils/idle_monitor/cpupower-monitor.c:207 | ||
134 | #, c-format | ||
135 | msgid " *is offline\n" | ||
136 | msgstr "" | ||
137 | |||
138 | #: utils/idle_monitor/cpupower-monitor.c:236 | ||
139 | #, c-format | ||
140 | msgid "%s: max monitor name length (%d) exceeded\n" | ||
141 | msgstr "" | ||
142 | |||
143 | #: utils/idle_monitor/cpupower-monitor.c:250 | ||
144 | #, c-format | ||
145 | msgid "No matching monitor found in %s, try -l option\n" | ||
146 | msgstr "" | ||
147 | |||
148 | #: utils/idle_monitor/cpupower-monitor.c:266 | ||
149 | #, c-format | ||
150 | msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" | ||
151 | msgstr "" | ||
152 | |||
153 | #: utils/idle_monitor/cpupower-monitor.c:319 | ||
154 | #, c-format | ||
155 | msgid "%s took %.5f seconds and exited with status %d\n" | ||
156 | msgstr "" | ||
157 | |||
158 | #: utils/idle_monitor/cpupower-monitor.c:406 | ||
159 | #, c-format | ||
160 | msgid "Cannot read number of available processors\n" | ||
161 | msgstr "" | ||
162 | |||
163 | #: utils/idle_monitor/cpupower-monitor.c:417 | ||
164 | #, c-format | ||
165 | msgid "Available monitor %s needs root access\n" | ||
166 | msgstr "" | ||
167 | |||
168 | #: utils/idle_monitor/cpupower-monitor.c:428 | ||
169 | #, c-format | ||
170 | msgid "No HW Cstate monitors found\n" | ||
171 | msgstr "" | ||
172 | |||
173 | #: utils/cpupower.c:78 | ||
174 | #, c-format | ||
175 | msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" | ||
176 | msgstr "" | ||
177 | |||
178 | #: utils/cpupower.c:79 | ||
179 | #, c-format | ||
180 | msgid "cpupower --version\n" | ||
181 | msgstr "" | ||
182 | |||
183 | #: utils/cpupower.c:80 | ||
184 | #, c-format | ||
185 | msgid "Supported subcommands are:\n" | ||
186 | msgstr "" | ||
187 | |||
188 | #: utils/cpupower.c:83 | ||
189 | #, c-format | ||
190 | msgid "" | ||
191 | "\n" | ||
192 | "Some subcommands can make use of the -c cpulist option.\n" | ||
193 | msgstr "" | ||
194 | |||
195 | #: utils/cpupower.c:84 | ||
196 | #, c-format | ||
197 | msgid "Look at the general cpupower manpage how to use it\n" | ||
198 | msgstr "" | ||
199 | |||
200 | #: utils/cpupower.c:85 | ||
201 | #, c-format | ||
202 | msgid "and read up the subcommand's manpage whether it is supported.\n" | ||
203 | msgstr "" | ||
204 | |||
205 | #: utils/cpupower.c:86 | ||
206 | #, c-format | ||
207 | msgid "" | ||
208 | "\n" | ||
209 | "Use cpupower help subcommand for getting help for above subcommands.\n" | ||
210 | msgstr "" | ||
211 | |||
212 | #: utils/cpupower.c:91 | ||
213 | #, c-format | ||
214 | msgid "Report errors and bugs to %s, please.\n" | ||
215 | msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n" | ||
216 | |||
217 | #: utils/cpupower.c:114 | ||
218 | #, c-format | ||
219 | msgid "Error parsing cpu list\n" | ||
220 | msgstr "" | ||
221 | |||
222 | #: utils/cpupower.c:172 | ||
223 | #, c-format | ||
224 | msgid "Subcommand %s needs root privileges\n" | ||
225 | msgstr "" | ||
226 | |||
227 | #: utils/cpufreq-info.c:31 | ||
228 | #, c-format | ||
229 | msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" | ||
230 | msgstr "Détermination du nombre de CPUs (%s : %s) impossible. Assume 1\n" | ||
231 | |||
232 | #: utils/cpufreq-info.c:63 | ||
233 | #, c-format | ||
234 | msgid "" | ||
235 | " minimum CPU frequency - maximum CPU frequency - governor\n" | ||
236 | msgstr "" | ||
237 | " Fréquence CPU minimale - Fréquence CPU maximale - régulateur\n" | ||
238 | |||
239 | #: utils/cpufreq-info.c:151 | ||
240 | #, c-format | ||
241 | msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" | ||
242 | msgstr "" | ||
243 | |||
244 | #. P state changes via MSR are identified via cpuid 80000007 | ||
245 | #. on Intel and AMD, but we assume boost capable machines can do that | ||
246 | #. if (cpuid_eax(0x80000000) >= 0x80000007 | ||
247 | #. && (cpuid_edx(0x80000007) & (1 << 7))) | ||
248 | #. | ||
249 | #: utils/cpufreq-info.c:161 | ||
250 | #, c-format | ||
251 | msgid " boost state support: \n" | ||
252 | msgstr "" | ||
253 | |||
254 | #: utils/cpufreq-info.c:163 | ||
255 | #, c-format | ||
256 | msgid " Supported: %s\n" | ||
257 | msgstr "" | ||
258 | |||
259 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
260 | msgid "yes" | ||
261 | msgstr "" | ||
262 | |||
263 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
264 | msgid "no" | ||
265 | msgstr "" | ||
266 | |||
267 | #: utils/cpufreq-info.c:164 | ||
268 | #, fuzzy, c-format | ||
269 | msgid " Active: %s\n" | ||
270 | msgstr " pilote : %s\n" | ||
271 | |||
272 | #: utils/cpufreq-info.c:177 | ||
273 | #, c-format | ||
274 | msgid " Boost States: %d\n" | ||
275 | msgstr "" | ||
276 | |||
277 | #: utils/cpufreq-info.c:178 | ||
278 | #, c-format | ||
279 | msgid " Total States: %d\n" | ||
280 | msgstr "" | ||
281 | |||
282 | #: utils/cpufreq-info.c:181 | ||
283 | #, c-format | ||
284 | msgid " Pstate-Pb%d: %luMHz (boost state)\n" | ||
285 | msgstr "" | ||
286 | |||
287 | #: utils/cpufreq-info.c:184 | ||
288 | #, c-format | ||
289 | msgid " Pstate-P%d: %luMHz\n" | ||
290 | msgstr "" | ||
291 | |||
292 | #: utils/cpufreq-info.c:211 | ||
293 | #, c-format | ||
294 | msgid " no or unknown cpufreq driver is active on this CPU\n" | ||
295 | msgstr " pas de pilotes cpufreq reconnu pour ce CPU\n" | ||
296 | |||
297 | #: utils/cpufreq-info.c:213 | ||
298 | #, c-format | ||
299 | msgid " driver: %s\n" | ||
300 | msgstr " pilote : %s\n" | ||
301 | |||
302 | #: utils/cpufreq-info.c:219 | ||
303 | #, fuzzy, c-format | ||
304 | msgid " CPUs which run at the same hardware frequency: " | ||
305 | msgstr " CPUs qui doivent changer de fréquences en même temps : " | ||
306 | |||
307 | #: utils/cpufreq-info.c:230 | ||
308 | #, fuzzy, c-format | ||
309 | msgid " CPUs which need to have their frequency coordinated by software: " | ||
310 | msgstr " CPUs qui doivent changer de fréquences en même temps : " | ||
311 | |||
312 | #: utils/cpufreq-info.c:241 | ||
313 | #, c-format | ||
314 | msgid " maximum transition latency: " | ||
315 | msgstr "" | ||
316 | |||
317 | #: utils/cpufreq-info.c:247 | ||
318 | #, c-format | ||
319 | msgid " hardware limits: " | ||
320 | msgstr " limitation matérielle : " | ||
321 | |||
322 | #: utils/cpufreq-info.c:256 | ||
323 | #, c-format | ||
324 | msgid " available frequency steps: " | ||
325 | msgstr " plage de fréquence : " | ||
326 | |||
327 | #: utils/cpufreq-info.c:269 | ||
328 | #, c-format | ||
329 | msgid " available cpufreq governors: " | ||
330 | msgstr " régulateurs disponibles : " | ||
331 | |||
332 | #: utils/cpufreq-info.c:280 | ||
333 | #, c-format | ||
334 | msgid " current policy: frequency should be within " | ||
335 | msgstr " tactique actuelle : la fréquence doit être comprise entre " | ||
336 | |||
337 | #: utils/cpufreq-info.c:282 | ||
338 | #, c-format | ||
339 | msgid " and " | ||
340 | msgstr " et " | ||
341 | |||
342 | #: utils/cpufreq-info.c:286 | ||
343 | #, c-format | ||
344 | msgid "" | ||
345 | "The governor \"%s\" may decide which speed to use\n" | ||
346 | " within this range.\n" | ||
347 | msgstr "" | ||
348 | "Le régulateur \"%s\" est libre de choisir la vitesse\n" | ||
349 | " dans cette plage de fréquences.\n" | ||
350 | |||
351 | #: utils/cpufreq-info.c:293 | ||
352 | #, c-format | ||
353 | msgid " current CPU frequency is " | ||
354 | msgstr " la fréquence actuelle de ce CPU est " | ||
355 | |||
356 | #: utils/cpufreq-info.c:296 | ||
357 | #, c-format | ||
358 | msgid " (asserted by call to hardware)" | ||
359 | msgstr " (vérifié par un appel direct du matériel)" | ||
360 | |||
361 | #: utils/cpufreq-info.c:304 | ||
362 | #, c-format | ||
363 | msgid " cpufreq stats: " | ||
364 | msgstr " des statistique concernant cpufreq:" | ||
365 | |||
366 | #: utils/cpufreq-info.c:472 | ||
367 | #, fuzzy, c-format | ||
368 | msgid "Usage: cpupower freqinfo [options]\n" | ||
369 | msgstr "Usage : cpufreq-info [options]\n" | ||
370 | |||
371 | #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 | ||
372 | #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 | ||
373 | #, c-format | ||
374 | msgid "Options:\n" | ||
375 | msgstr "Options :\n" | ||
376 | |||
377 | #: utils/cpufreq-info.c:474 | ||
378 | #, fuzzy, c-format | ||
379 | msgid " -e, --debug Prints out debug information [default]\n" | ||
380 | msgstr " -e, --debug Afficher les informations de déboguage\n" | ||
381 | |||
382 | #: utils/cpufreq-info.c:475 | ||
383 | #, c-format | ||
384 | msgid "" | ||
385 | " -f, --freq Get frequency the CPU currently runs at, according\n" | ||
386 | " to the cpufreq core *\n" | ||
387 | msgstr "" | ||
388 | " -f, --freq Obtenir la fréquence actuelle du CPU selon le point\n" | ||
389 | " de vue du coeur du système de cpufreq *\n" | ||
390 | |||
391 | #: utils/cpufreq-info.c:477 | ||
392 | #, c-format | ||
393 | msgid "" | ||
394 | " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
395 | " it from hardware (only available to root) *\n" | ||
396 | msgstr "" | ||
397 | " -w, --hwfreq Obtenir la fréquence actuelle du CPU directement par\n" | ||
398 | " le matériel (doit être root) *\n" | ||
399 | |||
400 | #: utils/cpufreq-info.c:479 | ||
401 | #, c-format | ||
402 | msgid "" | ||
403 | " -l, --hwlimits Determine the minimum and maximum CPU frequency " | ||
404 | "allowed *\n" | ||
405 | msgstr "" | ||
406 | " -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " | ||
407 | "*\n" | ||
408 | |||
409 | #: utils/cpufreq-info.c:480 | ||
410 | #, c-format | ||
411 | msgid " -d, --driver Determines the used cpufreq kernel driver *\n" | ||
412 | msgstr " -d, --driver Affiche le pilote cpufreq utilisé *\n" | ||
413 | |||
414 | #: utils/cpufreq-info.c:481 | ||
415 | #, c-format | ||
416 | msgid " -p, --policy Gets the currently used cpufreq policy *\n" | ||
417 | msgstr " -p, --policy Affiche la tactique actuelle de cpufreq *\n" | ||
418 | |||
419 | #: utils/cpufreq-info.c:482 | ||
420 | #, c-format | ||
421 | msgid " -g, --governors Determines available cpufreq governors *\n" | ||
422 | msgstr "" | ||
423 | " -g, --governors Affiche les régulateurs disponibles de cpufreq *\n" | ||
424 | |||
425 | #: utils/cpufreq-info.c:483 | ||
426 | #, fuzzy, c-format | ||
427 | msgid "" | ||
428 | " -r, --related-cpus Determines which CPUs run at the same hardware " | ||
429 | "frequency *\n" | ||
430 | msgstr "" | ||
431 | " -a, --affected-cpus Affiche quels sont les CPUs qui doivent changer de\n" | ||
432 | " fréquences en même temps *\n" | ||
433 | |||
434 | #: utils/cpufreq-info.c:484 | ||
435 | #, fuzzy, c-format | ||
436 | msgid "" | ||
437 | " -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
438 | " coordinated by software *\n" | ||
439 | msgstr "" | ||
440 | " -a, --affected-cpus Affiche quels sont les CPUs qui doivent changer de\n" | ||
441 | " fréquences en même temps *\n" | ||
442 | |||
443 | #: utils/cpufreq-info.c:486 | ||
444 | #, c-format | ||
445 | msgid " -s, --stats Shows cpufreq statistics if available\n" | ||
446 | msgstr "" | ||
447 | " -s, --stats Indique des statistiques concernant cpufreq, si\n" | ||
448 | " disponibles\n" | ||
449 | |||
450 | #: utils/cpufreq-info.c:487 | ||
451 | #, fuzzy, c-format | ||
452 | msgid "" | ||
453 | " -y, --latency Determines the maximum latency on CPU frequency " | ||
454 | "changes *\n" | ||
455 | msgstr "" | ||
456 | " -l, --hwlimits Affiche les fréquences minimales et maximales du CPU " | ||
457 | "*\n" | ||
458 | |||
459 | #: utils/cpufreq-info.c:488 | ||
460 | #, c-format | ||
461 | msgid " -b, --boost Checks for turbo or boost modes *\n" | ||
462 | msgstr "" | ||
463 | |||
464 | #: utils/cpufreq-info.c:489 | ||
465 | #, c-format | ||
466 | msgid "" | ||
467 | " -o, --proc Prints out information like provided by the /proc/" | ||
468 | "cpufreq\n" | ||
469 | " interface in 2.4. and early 2.6. kernels\n" | ||
470 | msgstr "" | ||
471 | " -o, --proc Affiche les informations en utilisant l'interface\n" | ||
472 | " fournie par /proc/cpufreq, présente dans les " | ||
473 | "versions\n" | ||
474 | " 2.4 et les anciennes versions 2.6 du noyau\n" | ||
475 | |||
476 | #: utils/cpufreq-info.c:491 | ||
477 | #, fuzzy, c-format | ||
478 | msgid "" | ||
479 | " -m, --human human-readable output for the -f, -w, -s and -y " | ||
480 | "parameters\n" | ||
481 | msgstr "" | ||
482 | " -m, --human affiche dans un format lisible pour un humain\n" | ||
483 | " pour les options -f, -w et -s (MHz, GHz)\n" | ||
484 | |||
485 | #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 | ||
486 | #, c-format | ||
487 | msgid " -h, --help Prints out this screen\n" | ||
488 | msgstr " -h, --help affiche l'aide-mémoire\n" | ||
489 | |||
490 | #: utils/cpufreq-info.c:495 | ||
491 | #, c-format | ||
492 | msgid "" | ||
493 | "If no argument or only the -c, --cpu parameter is given, debug output about\n" | ||
494 | "cpufreq is printed which is useful e.g. for reporting bugs.\n" | ||
495 | msgstr "" | ||
496 | "Par défaut, les informations de déboguage seront affichées si aucun\n" | ||
497 | "argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n" | ||
498 | "faciliter les rapports de bogues par exemple\n" | ||
499 | |||
500 | #: utils/cpufreq-info.c:497 | ||
501 | #, c-format | ||
502 | msgid "" | ||
503 | "For the arguments marked with *, omitting the -c or --cpu argument is\n" | ||
504 | "equivalent to setting it to zero\n" | ||
505 | msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n" | ||
506 | |||
507 | #: utils/cpufreq-info.c:580 | ||
508 | #, c-format | ||
509 | msgid "" | ||
510 | "The argument passed to this tool can't be combined with passing a --cpu " | ||
511 | "argument\n" | ||
512 | msgstr "Cette option est incompatible avec --cpu\n" | ||
513 | |||
514 | #: utils/cpufreq-info.c:596 | ||
515 | #, c-format | ||
516 | msgid "" | ||
517 | "You can't specify more than one --cpu parameter and/or\n" | ||
518 | "more than one output-specific argument\n" | ||
519 | msgstr "" | ||
520 | "On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" | ||
521 | "spécifier plus d'un argument de formatage\n" | ||
522 | |||
523 | #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 | ||
524 | #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 | ||
525 | #, c-format | ||
526 | msgid "invalid or unknown argument\n" | ||
527 | msgstr "option invalide\n" | ||
528 | |||
529 | #: utils/cpufreq-info.c:617 | ||
530 | #, c-format | ||
531 | msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" | ||
532 | msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n" | ||
533 | |||
534 | #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 | ||
535 | #, c-format | ||
536 | msgid "analyzing CPU %d:\n" | ||
537 | msgstr "analyse du CPU %d :\n" | ||
538 | |||
539 | #: utils/cpufreq-set.c:25 | ||
540 | #, fuzzy, c-format | ||
541 | msgid "Usage: cpupower frequency-set [options]\n" | ||
542 | msgstr "Usage : cpufreq-set [options]\n" | ||
543 | |||
544 | #: utils/cpufreq-set.c:27 | ||
545 | #, c-format | ||
546 | msgid "" | ||
547 | " -d FREQ, --min FREQ new minimum CPU frequency the governor may " | ||
548 | "select\n" | ||
549 | msgstr "" | ||
550 | " -d FREQ, --min FREQ nouvelle fréquence minimale du CPU à utiliser\n" | ||
551 | " par le régulateur\n" | ||
552 | |||
553 | #: utils/cpufreq-set.c:28 | ||
554 | #, c-format | ||
555 | msgid "" | ||
556 | " -u FREQ, --max FREQ new maximum CPU frequency the governor may " | ||
557 | "select\n" | ||
558 | msgstr "" | ||
559 | " -u FREQ, --max FREQ nouvelle fréquence maximale du CPU à utiliser\n" | ||
560 | " par le régulateur\n" | ||
561 | |||
562 | #: utils/cpufreq-set.c:29 | ||
563 | #, c-format | ||
564 | msgid " -g GOV, --governor GOV new cpufreq governor\n" | ||
565 | msgstr " -g GOV, --governor GOV active le régulateur GOV\n" | ||
566 | |||
567 | #: utils/cpufreq-set.c:30 | ||
568 | #, c-format | ||
569 | msgid "" | ||
570 | " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
571 | " governor to be available and loaded\n" | ||
572 | msgstr "" | ||
573 | " -f FREQ, --freq FREQ fixe la fréquence du processeur à FREQ. Il faut\n" | ||
574 | " que le régulateur « userspace » soit disponible \n" | ||
575 | " et activé.\n" | ||
576 | |||
577 | #: utils/cpufreq-set.c:32 | ||
578 | #, c-format | ||
579 | msgid " -r, --related Switches all hardware-related CPUs\n" | ||
580 | msgstr "" | ||
581 | |||
582 | #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 | ||
583 | #, fuzzy, c-format | ||
584 | msgid " -h, --help Prints out this screen\n" | ||
585 | msgstr " -h, --help affiche l'aide-mémoire\n" | ||
586 | |||
587 | #: utils/cpufreq-set.c:35 | ||
588 | #, fuzzy, c-format | ||
589 | msgid "" | ||
590 | "Notes:\n" | ||
591 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" | ||
592 | msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n" | ||
593 | |||
594 | #: utils/cpufreq-set.c:37 | ||
595 | #, fuzzy, c-format | ||
596 | msgid "" | ||
597 | "2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " | ||
598 | "parameter\n" | ||
599 | " except the -c CPU, --cpu CPU parameter\n" | ||
600 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
601 | " by postfixing the value with the wanted unit name, without any space\n" | ||
602 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
603 | msgstr "" | ||
604 | "Remarque :\n" | ||
605 | "1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n" | ||
606 | "2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n" | ||
607 | "3. on pourra préciser l'unité des fréquences en postfixant sans aucune " | ||
608 | "espace\n" | ||
609 | " les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n" | ||
610 | " (kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
611 | |||
612 | #: utils/cpufreq-set.c:57 | ||
613 | #, c-format | ||
614 | msgid "" | ||
615 | "Error setting new values. Common errors:\n" | ||
616 | "- Do you have proper administration rights? (super-user?)\n" | ||
617 | "- Is the governor you requested available and modprobed?\n" | ||
618 | "- Trying to set an invalid policy?\n" | ||
619 | "- Trying to set a specific frequency, but userspace governor is not " | ||
620 | "available,\n" | ||
621 | " for example because of hardware which cannot be set to a specific " | ||
622 | "frequency\n" | ||
623 | " or because the userspace governor isn't loaded?\n" | ||
624 | msgstr "" | ||
625 | "En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n" | ||
626 | "d'erreur typique sont :\n" | ||
627 | "- droit d'administration insuffisant (êtes-vous root ?) ;\n" | ||
628 | "- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible " | ||
629 | "en\n" | ||
630 | " tant que module noyau ;\n" | ||
631 | "- la tactique n'est pas disponible ;\n" | ||
632 | "- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n" | ||
633 | " n'est pas disponible, par exemple parce que le matériel ne le supporte\n" | ||
634 | " pas, ou bien n'est tout simplement pas chargé.\n" | ||
635 | |||
636 | #: utils/cpufreq-set.c:170 | ||
637 | #, c-format | ||
638 | msgid "wrong, unknown or unhandled CPU?\n" | ||
639 | msgstr "CPU inconnu ou non supporté ?\n" | ||
640 | |||
641 | #: utils/cpufreq-set.c:302 | ||
642 | #, c-format | ||
643 | msgid "" | ||
644 | "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
645 | "-g/--governor parameters\n" | ||
646 | msgstr "" | ||
647 | "l'option -f/--freq est incompatible avec les options -d/--min, -u/--max et\n" | ||
648 | "-g/--governor\n" | ||
649 | |||
650 | #: utils/cpufreq-set.c:308 | ||
651 | #, c-format | ||
652 | msgid "" | ||
653 | "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
654 | "-g/--governor must be passed\n" | ||
655 | msgstr "" | ||
656 | "L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n" | ||
657 | "-g/--governor\n" | ||
658 | |||
659 | #: utils/cpufreq-set.c:347 | ||
660 | #, c-format | ||
661 | msgid "Setting cpu: %d\n" | ||
662 | msgstr "" | ||
663 | |||
664 | #: utils/cpupower-set.c:22 | ||
665 | #, c-format | ||
666 | msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" | ||
667 | msgstr "" | ||
668 | |||
669 | #: utils/cpupower-set.c:24 | ||
670 | #, c-format | ||
671 | msgid "" | ||
672 | " -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
673 | " Intel models [0-15], see manpage for details\n" | ||
674 | msgstr "" | ||
675 | |||
676 | #: utils/cpupower-set.c:26 | ||
677 | #, c-format | ||
678 | msgid "" | ||
679 | " -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n" | ||
680 | msgstr "" | ||
681 | |||
682 | #: utils/cpupower-set.c:27 | ||
683 | #, c-format | ||
684 | msgid "" | ||
685 | " -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler " | ||
686 | "policy.\n" | ||
687 | msgstr "" | ||
688 | |||
689 | #: utils/cpupower-set.c:80 | ||
690 | #, c-format | ||
691 | msgid "--perf-bias param out of range [0-%d]\n" | ||
692 | msgstr "" | ||
693 | |||
694 | #: utils/cpupower-set.c:91 | ||
695 | #, c-format | ||
696 | msgid "--sched-mc param out of range [0-%d]\n" | ||
697 | msgstr "" | ||
698 | |||
699 | #: utils/cpupower-set.c:102 | ||
700 | #, c-format | ||
701 | msgid "--sched-smt param out of range [0-%d]\n" | ||
702 | msgstr "" | ||
703 | |||
704 | #: utils/cpupower-set.c:121 | ||
705 | #, c-format | ||
706 | msgid "Error setting sched-mc %s\n" | ||
707 | msgstr "" | ||
708 | |||
709 | #: utils/cpupower-set.c:127 | ||
710 | #, c-format | ||
711 | msgid "Error setting sched-smt %s\n" | ||
712 | msgstr "" | ||
713 | |||
714 | #: utils/cpupower-set.c:146 | ||
715 | #, c-format | ||
716 | msgid "Error setting perf-bias value on CPU %d\n" | ||
717 | msgstr "" | ||
718 | |||
719 | #: utils/cpupower-info.c:21 | ||
720 | #, c-format | ||
721 | msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" | ||
722 | msgstr "" | ||
723 | |||
724 | #: utils/cpupower-info.c:23 | ||
725 | #, c-format | ||
726 | msgid "" | ||
727 | " -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
728 | " Intel models [0-15], see manpage for details\n" | ||
729 | msgstr "" | ||
730 | |||
731 | #: utils/cpupower-info.c:25 | ||
732 | #, fuzzy, c-format | ||
733 | msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n" | ||
734 | msgstr " -p, --policy Affiche la tactique actuelle de cpufreq *\n" | ||
735 | |||
736 | #: utils/cpupower-info.c:26 | ||
737 | #, c-format | ||
738 | msgid "" | ||
739 | " -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n" | ||
740 | msgstr "" | ||
741 | |||
742 | #: utils/cpupower-info.c:28 | ||
743 | #, c-format | ||
744 | msgid "" | ||
745 | "\n" | ||
746 | "Passing no option will show all info, by default only on core 0\n" | ||
747 | msgstr "" | ||
748 | |||
749 | #: utils/cpupower-info.c:102 | ||
750 | #, c-format | ||
751 | msgid "System's multi core scheduler setting: " | ||
752 | msgstr "" | ||
753 | |||
754 | #. if sysfs file is missing it's: errno == ENOENT | ||
755 | #: utils/cpupower-info.c:105 utils/cpupower-info.c:114 | ||
756 | #, c-format | ||
757 | msgid "not supported\n" | ||
758 | msgstr "" | ||
759 | |||
760 | #: utils/cpupower-info.c:111 | ||
761 | #, c-format | ||
762 | msgid "System's thread sibling scheduler setting: " | ||
763 | msgstr "" | ||
764 | |||
765 | #: utils/cpupower-info.c:126 | ||
766 | #, c-format | ||
767 | msgid "Intel's performance bias setting needs root privileges\n" | ||
768 | msgstr "" | ||
769 | |||
770 | #: utils/cpupower-info.c:128 | ||
771 | #, c-format | ||
772 | msgid "System does not support Intel's performance bias setting\n" | ||
773 | msgstr "" | ||
774 | |||
775 | #: utils/cpupower-info.c:147 | ||
776 | #, c-format | ||
777 | msgid "Could not read perf-bias value\n" | ||
778 | msgstr "" | ||
779 | |||
780 | #: utils/cpupower-info.c:150 | ||
781 | #, c-format | ||
782 | msgid "perf-bias: %d\n" | ||
783 | msgstr "" | ||
784 | |||
785 | #: utils/cpuidle-info.c:28 | ||
786 | #, fuzzy, c-format | ||
787 | msgid "Analyzing CPU %d:\n" | ||
788 | msgstr "analyse du CPU %d :\n" | ||
789 | |||
790 | #: utils/cpuidle-info.c:32 | ||
791 | #, c-format | ||
792 | msgid "CPU %u: No idle states\n" | ||
793 | msgstr "" | ||
794 | |||
795 | #: utils/cpuidle-info.c:36 | ||
796 | #, c-format | ||
797 | msgid "CPU %u: Can't read idle state info\n" | ||
798 | msgstr "" | ||
799 | |||
800 | #: utils/cpuidle-info.c:41 | ||
801 | #, c-format | ||
802 | msgid "Could not determine max idle state %u\n" | ||
803 | msgstr "" | ||
804 | |||
805 | #: utils/cpuidle-info.c:46 | ||
806 | #, c-format | ||
807 | msgid "Number of idle states: %d\n" | ||
808 | msgstr "" | ||
809 | |||
810 | #: utils/cpuidle-info.c:48 | ||
811 | #, fuzzy, c-format | ||
812 | msgid "Available idle states:" | ||
813 | msgstr " plage de fréquence : " | ||
814 | |||
815 | #: utils/cpuidle-info.c:71 | ||
816 | #, c-format | ||
817 | msgid "Flags/Description: %s\n" | ||
818 | msgstr "" | ||
819 | |||
820 | #: utils/cpuidle-info.c:74 | ||
821 | #, c-format | ||
822 | msgid "Latency: %lu\n" | ||
823 | msgstr "" | ||
824 | |||
825 | #: utils/cpuidle-info.c:76 | ||
826 | #, c-format | ||
827 | msgid "Usage: %lu\n" | ||
828 | msgstr "" | ||
829 | |||
830 | #: utils/cpuidle-info.c:78 | ||
831 | #, c-format | ||
832 | msgid "Duration: %llu\n" | ||
833 | msgstr "" | ||
834 | |||
835 | #: utils/cpuidle-info.c:90 | ||
836 | #, c-format | ||
837 | msgid "Could not determine cpuidle driver\n" | ||
838 | msgstr "" | ||
839 | |||
840 | #: utils/cpuidle-info.c:94 | ||
841 | #, fuzzy, c-format | ||
842 | msgid "CPUidle driver: %s\n" | ||
843 | msgstr " pilote : %s\n" | ||
844 | |||
845 | #: utils/cpuidle-info.c:99 | ||
846 | #, c-format | ||
847 | msgid "Could not determine cpuidle governor\n" | ||
848 | msgstr "" | ||
849 | |||
850 | #: utils/cpuidle-info.c:103 | ||
851 | #, c-format | ||
852 | msgid "CPUidle governor: %s\n" | ||
853 | msgstr "" | ||
854 | |||
855 | #: utils/cpuidle-info.c:122 | ||
856 | #, c-format | ||
857 | msgid "CPU %u: Can't read C-state info\n" | ||
858 | msgstr "" | ||
859 | |||
860 | #. printf("Cstates: %d\n", cstates); | ||
861 | #: utils/cpuidle-info.c:127 | ||
862 | #, c-format | ||
863 | msgid "active state: C0\n" | ||
864 | msgstr "" | ||
865 | |||
866 | #: utils/cpuidle-info.c:128 | ||
867 | #, c-format | ||
868 | msgid "max_cstate: C%u\n" | ||
869 | msgstr "" | ||
870 | |||
871 | #: utils/cpuidle-info.c:129 | ||
872 | #, c-format | ||
873 | msgid "maximum allowed latency: %lu usec\n" | ||
874 | msgstr "" | ||
875 | |||
876 | #: utils/cpuidle-info.c:130 | ||
877 | #, c-format | ||
878 | msgid "states:\t\n" | ||
879 | msgstr "" | ||
880 | |||
881 | #: utils/cpuidle-info.c:132 | ||
882 | #, c-format | ||
883 | msgid " C%d: type[C%d] " | ||
884 | msgstr "" | ||
885 | |||
886 | #: utils/cpuidle-info.c:134 | ||
887 | #, c-format | ||
888 | msgid "promotion[--] demotion[--] " | ||
889 | msgstr "" | ||
890 | |||
891 | #: utils/cpuidle-info.c:135 | ||
892 | #, c-format | ||
893 | msgid "latency[%03lu] " | ||
894 | msgstr "" | ||
895 | |||
896 | #: utils/cpuidle-info.c:137 | ||
897 | #, c-format | ||
898 | msgid "usage[%08lu] " | ||
899 | msgstr "" | ||
900 | |||
901 | #: utils/cpuidle-info.c:139 | ||
902 | #, c-format | ||
903 | msgid "duration[%020Lu] \n" | ||
904 | msgstr "" | ||
905 | |||
906 | #: utils/cpuidle-info.c:147 | ||
907 | #, fuzzy, c-format | ||
908 | msgid "Usage: cpupower idleinfo [options]\n" | ||
909 | msgstr "Usage : cpufreq-info [options]\n" | ||
910 | |||
911 | #: utils/cpuidle-info.c:149 | ||
912 | #, fuzzy, c-format | ||
913 | msgid " -s, --silent Only show general C-state information\n" | ||
914 | msgstr " -e, --debug Afficher les informations de déboguage\n" | ||
915 | |||
916 | #: utils/cpuidle-info.c:150 | ||
917 | #, fuzzy, c-format | ||
918 | msgid "" | ||
919 | " -o, --proc Prints out information like provided by the /proc/" | ||
920 | "acpi/processor/*/power\n" | ||
921 | " interface in older kernels\n" | ||
922 | msgstr "" | ||
923 | " -o, --proc Affiche les informations en utilisant l'interface\n" | ||
924 | " fournie par /proc/cpufreq, présente dans les " | ||
925 | "versions\n" | ||
926 | " 2.4 et les anciennes versions 2.6 du noyau\n" | ||
927 | |||
928 | #: utils/cpuidle-info.c:209 | ||
929 | #, fuzzy, c-format | ||
930 | msgid "You can't specify more than one output-specific argument\n" | ||
931 | msgstr "" | ||
932 | "On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" | ||
933 | "spécifier plus d'un argument de formatage\n" | ||
934 | |||
935 | #~ msgid "" | ||
936 | #~ " -c CPU, --cpu CPU CPU number which information shall be determined " | ||
937 | #~ "about\n" | ||
938 | #~ msgstr "" | ||
939 | #~ " -c CPU, --cpu CPU Numéro du CPU pour lequel l'information sera " | ||
940 | #~ "affichée\n" | ||
941 | |||
942 | #~ msgid "" | ||
943 | #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " | ||
944 | #~ "modified\n" | ||
945 | #~ msgstr "" | ||
946 | #~ " -c CPU, --cpu CPU numéro du CPU à prendre en compte pour les\n" | ||
947 | #~ " changements\n" | ||
diff --git a/tools/power/cpupower/po/it.po b/tools/power/cpupower/po/it.po new file mode 100644 index 000000000000..f80c4ddb9bda --- /dev/null +++ b/tools/power/cpupower/po/it.po | |||
@@ -0,0 +1,961 @@ | |||
1 | # Italian translations for cpufrequtils package | ||
2 | # Copyright (C) 2004-2009 | ||
3 | # This file is distributed under the same license as the cpufrequtils package. | ||
4 | # Mattia Dongili <malattia@gmail.com>. | ||
5 | # | ||
6 | # | ||
7 | msgid "" | ||
8 | msgstr "" | ||
9 | "Project-Id-Version: cpufrequtils 0.3\n" | ||
10 | "Report-Msgid-Bugs-To: \n" | ||
11 | "POT-Creation-Date: 2011-03-08 17:03+0100\n" | ||
12 | "PO-Revision-Date: 2009-08-15 12:00+0900\n" | ||
13 | "Last-Translator: Mattia Dongili <malattia@gmail.com>\n" | ||
14 | "Language-Team: NONE\n" | ||
15 | "Language: \n" | ||
16 | "MIME-Version: 1.0\n" | ||
17 | "Content-Type: text/plain; charset=UTF-8\n" | ||
18 | "Content-Transfer-Encoding: 8bit\n" | ||
19 | |||
20 | #: utils/idle_monitor/nhm_idle.c:36 | ||
21 | msgid "Processor Core C3" | ||
22 | msgstr "" | ||
23 | |||
24 | #: utils/idle_monitor/nhm_idle.c:43 | ||
25 | msgid "Processor Core C6" | ||
26 | msgstr "" | ||
27 | |||
28 | #: utils/idle_monitor/nhm_idle.c:51 | ||
29 | msgid "Processor Package C3" | ||
30 | msgstr "" | ||
31 | |||
32 | #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 | ||
33 | msgid "Processor Package C6" | ||
34 | msgstr "" | ||
35 | |||
36 | #: utils/idle_monitor/snb_idle.c:33 | ||
37 | msgid "Processor Core C7" | ||
38 | msgstr "" | ||
39 | |||
40 | #: utils/idle_monitor/snb_idle.c:40 | ||
41 | msgid "Processor Package C2" | ||
42 | msgstr "" | ||
43 | |||
44 | #: utils/idle_monitor/snb_idle.c:47 | ||
45 | msgid "Processor Package C7" | ||
46 | msgstr "" | ||
47 | |||
48 | #: utils/idle_monitor/amd_fam14h_idle.c:56 | ||
49 | msgid "Package in sleep state (PC1 or deeper)" | ||
50 | msgstr "" | ||
51 | |||
52 | #: utils/idle_monitor/amd_fam14h_idle.c:63 | ||
53 | msgid "Processor Package C1" | ||
54 | msgstr "" | ||
55 | |||
56 | #: utils/idle_monitor/amd_fam14h_idle.c:77 | ||
57 | msgid "North Bridge P1 boolean counter (returns 0 or 1)" | ||
58 | msgstr "" | ||
59 | |||
60 | #: utils/idle_monitor/mperf_monitor.c:35 | ||
61 | msgid "Processor Core not idle" | ||
62 | msgstr "" | ||
63 | |||
64 | #: utils/idle_monitor/mperf_monitor.c:42 | ||
65 | msgid "Processor Core in an idle state" | ||
66 | msgstr "" | ||
67 | |||
68 | #: utils/idle_monitor/mperf_monitor.c:50 | ||
69 | msgid "Average Frequency (including boost) in MHz" | ||
70 | msgstr "" | ||
71 | |||
72 | #: utils/idle_monitor/cpupower-monitor.c:66 | ||
73 | #, c-format | ||
74 | msgid "" | ||
75 | "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
76 | "interval_sec | -c command ...]\n" | ||
77 | msgstr "" | ||
78 | |||
79 | #: utils/idle_monitor/cpupower-monitor.c:69 | ||
80 | #, c-format | ||
81 | msgid "" | ||
82 | "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
83 | "interval_sec | -c command ...]\n" | ||
84 | msgstr "" | ||
85 | |||
86 | #: utils/idle_monitor/cpupower-monitor.c:71 | ||
87 | #, c-format | ||
88 | msgid "\t -v: be more verbose\n" | ||
89 | msgstr "" | ||
90 | |||
91 | #: utils/idle_monitor/cpupower-monitor.c:73 | ||
92 | #, c-format | ||
93 | msgid "\t -h: print this help\n" | ||
94 | msgstr "" | ||
95 | |||
96 | #: utils/idle_monitor/cpupower-monitor.c:74 | ||
97 | #, c-format | ||
98 | msgid "\t -i: time intervall to measure for in seconds (default 1)\n" | ||
99 | msgstr "" | ||
100 | |||
101 | #: utils/idle_monitor/cpupower-monitor.c:75 | ||
102 | #, c-format | ||
103 | msgid "\t -t: show CPU topology/hierarchy\n" | ||
104 | msgstr "" | ||
105 | |||
106 | #: utils/idle_monitor/cpupower-monitor.c:76 | ||
107 | #, c-format | ||
108 | msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" | ||
109 | msgstr "" | ||
110 | |||
111 | #: utils/idle_monitor/cpupower-monitor.c:77 | ||
112 | #, c-format | ||
113 | msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" | ||
114 | msgstr "" | ||
115 | |||
116 | #: utils/idle_monitor/cpupower-monitor.c:79 | ||
117 | #, c-format | ||
118 | msgid "" | ||
119 | "only one of: -t, -l, -m are allowed\n" | ||
120 | "If none of them is passed," | ||
121 | msgstr "" | ||
122 | |||
123 | #: utils/idle_monitor/cpupower-monitor.c:80 | ||
124 | #, c-format | ||
125 | msgid " all supported monitors are shown\n" | ||
126 | msgstr "" | ||
127 | |||
128 | #: utils/idle_monitor/cpupower-monitor.c:197 | ||
129 | #, c-format | ||
130 | msgid "Monitor %s, Counter %s has no count function. Implementation error\n" | ||
131 | msgstr "" | ||
132 | |||
133 | #: utils/idle_monitor/cpupower-monitor.c:207 | ||
134 | #, c-format | ||
135 | msgid " *is offline\n" | ||
136 | msgstr "" | ||
137 | |||
138 | #: utils/idle_monitor/cpupower-monitor.c:236 | ||
139 | #, c-format | ||
140 | msgid "%s: max monitor name length (%d) exceeded\n" | ||
141 | msgstr "" | ||
142 | |||
143 | #: utils/idle_monitor/cpupower-monitor.c:250 | ||
144 | #, c-format | ||
145 | msgid "No matching monitor found in %s, try -l option\n" | ||
146 | msgstr "" | ||
147 | |||
148 | #: utils/idle_monitor/cpupower-monitor.c:266 | ||
149 | #, c-format | ||
150 | msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" | ||
151 | msgstr "" | ||
152 | |||
153 | #: utils/idle_monitor/cpupower-monitor.c:319 | ||
154 | #, c-format | ||
155 | msgid "%s took %.5f seconds and exited with status %d\n" | ||
156 | msgstr "" | ||
157 | |||
158 | #: utils/idle_monitor/cpupower-monitor.c:406 | ||
159 | #, c-format | ||
160 | msgid "Cannot read number of available processors\n" | ||
161 | msgstr "" | ||
162 | |||
163 | #: utils/idle_monitor/cpupower-monitor.c:417 | ||
164 | #, c-format | ||
165 | msgid "Available monitor %s needs root access\n" | ||
166 | msgstr "" | ||
167 | |||
168 | #: utils/idle_monitor/cpupower-monitor.c:428 | ||
169 | #, c-format | ||
170 | msgid "No HW Cstate monitors found\n" | ||
171 | msgstr "" | ||
172 | |||
173 | #: utils/cpupower.c:78 | ||
174 | #, c-format | ||
175 | msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" | ||
176 | msgstr "" | ||
177 | |||
178 | #: utils/cpupower.c:79 | ||
179 | #, c-format | ||
180 | msgid "cpupower --version\n" | ||
181 | msgstr "" | ||
182 | |||
183 | #: utils/cpupower.c:80 | ||
184 | #, c-format | ||
185 | msgid "Supported subcommands are:\n" | ||
186 | msgstr "" | ||
187 | |||
188 | #: utils/cpupower.c:83 | ||
189 | #, c-format | ||
190 | msgid "" | ||
191 | "\n" | ||
192 | "Some subcommands can make use of the -c cpulist option.\n" | ||
193 | msgstr "" | ||
194 | |||
195 | #: utils/cpupower.c:84 | ||
196 | #, c-format | ||
197 | msgid "Look at the general cpupower manpage how to use it\n" | ||
198 | msgstr "" | ||
199 | |||
200 | #: utils/cpupower.c:85 | ||
201 | #, c-format | ||
202 | msgid "and read up the subcommand's manpage whether it is supported.\n" | ||
203 | msgstr "" | ||
204 | |||
205 | #: utils/cpupower.c:86 | ||
206 | #, c-format | ||
207 | msgid "" | ||
208 | "\n" | ||
209 | "Use cpupower help subcommand for getting help for above subcommands.\n" | ||
210 | msgstr "" | ||
211 | |||
212 | #: utils/cpupower.c:91 | ||
213 | #, c-format | ||
214 | msgid "Report errors and bugs to %s, please.\n" | ||
215 | msgstr "Per favore, comunicare errori e malfunzionamenti a %s.\n" | ||
216 | |||
217 | #: utils/cpupower.c:114 | ||
218 | #, c-format | ||
219 | msgid "Error parsing cpu list\n" | ||
220 | msgstr "" | ||
221 | |||
222 | #: utils/cpupower.c:172 | ||
223 | #, c-format | ||
224 | msgid "Subcommand %s needs root privileges\n" | ||
225 | msgstr "" | ||
226 | |||
227 | #: utils/cpufreq-info.c:31 | ||
228 | #, c-format | ||
229 | msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" | ||
230 | msgstr "Impossibile determinare il numero di CPU (%s: %s), assumo sia 1\n" | ||
231 | |||
232 | #: utils/cpufreq-info.c:63 | ||
233 | #, c-format | ||
234 | msgid "" | ||
235 | " minimum CPU frequency - maximum CPU frequency - governor\n" | ||
236 | msgstr "" | ||
237 | " frequenza minima CPU - frequenza massima CPU - gestore\n" | ||
238 | |||
239 | #: utils/cpufreq-info.c:151 | ||
240 | #, c-format | ||
241 | msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" | ||
242 | msgstr "" | ||
243 | |||
244 | #. P state changes via MSR are identified via cpuid 80000007 | ||
245 | #. on Intel and AMD, but we assume boost capable machines can do that | ||
246 | #. if (cpuid_eax(0x80000000) >= 0x80000007 | ||
247 | #. && (cpuid_edx(0x80000007) & (1 << 7))) | ||
248 | #. | ||
249 | #: utils/cpufreq-info.c:161 | ||
250 | #, c-format | ||
251 | msgid " boost state support: \n" | ||
252 | msgstr "" | ||
253 | |||
254 | #: utils/cpufreq-info.c:163 | ||
255 | #, c-format | ||
256 | msgid " Supported: %s\n" | ||
257 | msgstr "" | ||
258 | |||
259 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
260 | msgid "yes" | ||
261 | msgstr "" | ||
262 | |||
263 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
264 | msgid "no" | ||
265 | msgstr "" | ||
266 | |||
267 | #: utils/cpufreq-info.c:164 | ||
268 | #, fuzzy, c-format | ||
269 | msgid " Active: %s\n" | ||
270 | msgstr " modulo %s\n" | ||
271 | |||
272 | #: utils/cpufreq-info.c:177 | ||
273 | #, c-format | ||
274 | msgid " Boost States: %d\n" | ||
275 | msgstr "" | ||
276 | |||
277 | #: utils/cpufreq-info.c:178 | ||
278 | #, c-format | ||
279 | msgid " Total States: %d\n" | ||
280 | msgstr "" | ||
281 | |||
282 | #: utils/cpufreq-info.c:181 | ||
283 | #, c-format | ||
284 | msgid " Pstate-Pb%d: %luMHz (boost state)\n" | ||
285 | msgstr "" | ||
286 | |||
287 | #: utils/cpufreq-info.c:184 | ||
288 | #, c-format | ||
289 | msgid " Pstate-P%d: %luMHz\n" | ||
290 | msgstr "" | ||
291 | |||
292 | #: utils/cpufreq-info.c:211 | ||
293 | #, c-format | ||
294 | msgid " no or unknown cpufreq driver is active on this CPU\n" | ||
295 | msgstr " nessun modulo o modulo cpufreq sconosciuto per questa CPU\n" | ||
296 | |||
297 | #: utils/cpufreq-info.c:213 | ||
298 | #, c-format | ||
299 | msgid " driver: %s\n" | ||
300 | msgstr " modulo %s\n" | ||
301 | |||
302 | #: utils/cpufreq-info.c:219 | ||
303 | #, c-format | ||
304 | msgid " CPUs which run at the same hardware frequency: " | ||
305 | msgstr " CPU che operano alla stessa frequenza hardware: " | ||
306 | |||
307 | #: utils/cpufreq-info.c:230 | ||
308 | #, c-format | ||
309 | msgid " CPUs which need to have their frequency coordinated by software: " | ||
310 | msgstr " CPU che è necessario siano coordinate dal software: " | ||
311 | |||
312 | #: utils/cpufreq-info.c:241 | ||
313 | #, c-format | ||
314 | msgid " maximum transition latency: " | ||
315 | msgstr " latenza massima durante la transizione: " | ||
316 | |||
317 | #: utils/cpufreq-info.c:247 | ||
318 | #, c-format | ||
319 | msgid " hardware limits: " | ||
320 | msgstr " limiti hardware: " | ||
321 | |||
322 | #: utils/cpufreq-info.c:256 | ||
323 | #, c-format | ||
324 | msgid " available frequency steps: " | ||
325 | msgstr " frequenze disponibili: " | ||
326 | |||
327 | #: utils/cpufreq-info.c:269 | ||
328 | #, c-format | ||
329 | msgid " available cpufreq governors: " | ||
330 | msgstr " gestori disponibili: " | ||
331 | |||
332 | #: utils/cpufreq-info.c:280 | ||
333 | #, c-format | ||
334 | msgid " current policy: frequency should be within " | ||
335 | msgstr " gestore attuale: la frequenza deve mantenersi tra " | ||
336 | |||
337 | #: utils/cpufreq-info.c:282 | ||
338 | #, c-format | ||
339 | msgid " and " | ||
340 | msgstr " e " | ||
341 | |||
342 | #: utils/cpufreq-info.c:286 | ||
343 | #, c-format | ||
344 | msgid "" | ||
345 | "The governor \"%s\" may decide which speed to use\n" | ||
346 | " within this range.\n" | ||
347 | msgstr "" | ||
348 | " Il gestore \"%s\" può decidere quale velocità usare\n" | ||
349 | " in questo intervallo.\n" | ||
350 | |||
351 | #: utils/cpufreq-info.c:293 | ||
352 | #, c-format | ||
353 | msgid " current CPU frequency is " | ||
354 | msgstr " la frequenza attuale della CPU è " | ||
355 | |||
356 | #: utils/cpufreq-info.c:296 | ||
357 | #, c-format | ||
358 | msgid " (asserted by call to hardware)" | ||
359 | msgstr " (ottenuta da una chiamata diretta all'hardware)" | ||
360 | |||
361 | #: utils/cpufreq-info.c:304 | ||
362 | #, c-format | ||
363 | msgid " cpufreq stats: " | ||
364 | msgstr " statistiche cpufreq:" | ||
365 | |||
366 | #: utils/cpufreq-info.c:472 | ||
367 | #, fuzzy, c-format | ||
368 | msgid "Usage: cpupower freqinfo [options]\n" | ||
369 | msgstr "Uso: cpufreq-info [opzioni]\n" | ||
370 | |||
371 | #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 | ||
372 | #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 | ||
373 | #, c-format | ||
374 | msgid "Options:\n" | ||
375 | msgstr "Opzioni:\n" | ||
376 | |||
377 | #: utils/cpufreq-info.c:474 | ||
378 | #, fuzzy, c-format | ||
379 | msgid " -e, --debug Prints out debug information [default]\n" | ||
380 | msgstr " -e, --debug Mostra informazioni di debug\n" | ||
381 | |||
382 | #: utils/cpufreq-info.c:475 | ||
383 | #, c-format | ||
384 | msgid "" | ||
385 | " -f, --freq Get frequency the CPU currently runs at, according\n" | ||
386 | " to the cpufreq core *\n" | ||
387 | msgstr "" | ||
388 | " -f, --freq Mostra la frequenza attuale della CPU secondo\n" | ||
389 | " il modulo cpufreq *\n" | ||
390 | |||
391 | #: utils/cpufreq-info.c:477 | ||
392 | #, c-format | ||
393 | msgid "" | ||
394 | " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
395 | " it from hardware (only available to root) *\n" | ||
396 | msgstr "" | ||
397 | " -w, --hwfreq Mostra la frequenza attuale della CPU leggendola\n" | ||
398 | " dall'hardware (disponibile solo per l'utente root) *\n" | ||
399 | |||
400 | #: utils/cpufreq-info.c:479 | ||
401 | #, c-format | ||
402 | msgid "" | ||
403 | " -l, --hwlimits Determine the minimum and maximum CPU frequency " | ||
404 | "allowed *\n" | ||
405 | msgstr "" | ||
406 | " -l, --hwlimits Determina le frequenze minima e massima possibili per " | ||
407 | "la CPU *\n" | ||
408 | |||
409 | #: utils/cpufreq-info.c:480 | ||
410 | #, c-format | ||
411 | msgid " -d, --driver Determines the used cpufreq kernel driver *\n" | ||
412 | msgstr "" | ||
413 | " -d, --driver Determina il modulo cpufreq del kernel in uso *\n" | ||
414 | |||
415 | #: utils/cpufreq-info.c:481 | ||
416 | #, c-format | ||
417 | msgid " -p, --policy Gets the currently used cpufreq policy *\n" | ||
418 | msgstr "" | ||
419 | " -p, --policy Mostra il gestore cpufreq attualmente in uso *\n" | ||
420 | |||
421 | #: utils/cpufreq-info.c:482 | ||
422 | #, c-format | ||
423 | msgid " -g, --governors Determines available cpufreq governors *\n" | ||
424 | msgstr " -g, --governors Determina i gestori cpufreq disponibili *\n" | ||
425 | |||
426 | #: utils/cpufreq-info.c:483 | ||
427 | #, c-format | ||
428 | msgid "" | ||
429 | " -r, --related-cpus Determines which CPUs run at the same hardware " | ||
430 | "frequency *\n" | ||
431 | msgstr "" | ||
432 | " -r, --related-cpus Determina quali CPU operano alla stessa frequenza *\n" | ||
433 | |||
434 | #: utils/cpufreq-info.c:484 | ||
435 | #, c-format | ||
436 | msgid "" | ||
437 | " -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
438 | " coordinated by software *\n" | ||
439 | msgstr "" | ||
440 | " -a, --affected-cpus Determina quali CPU devono avere la frequenza\n" | ||
441 | " coordinata dal software *\n" | ||
442 | |||
443 | #: utils/cpufreq-info.c:486 | ||
444 | #, c-format | ||
445 | msgid " -s, --stats Shows cpufreq statistics if available\n" | ||
446 | msgstr " -s, --stats Mostra le statistiche se disponibili\n" | ||
447 | |||
448 | #: utils/cpufreq-info.c:487 | ||
449 | #, c-format | ||
450 | msgid "" | ||
451 | " -y, --latency Determines the maximum latency on CPU frequency " | ||
452 | "changes *\n" | ||
453 | msgstr "" | ||
454 | " -y, --latency Determina la latenza massima durante i cambi di " | ||
455 | "frequenza *\n" | ||
456 | |||
457 | #: utils/cpufreq-info.c:488 | ||
458 | #, c-format | ||
459 | msgid " -b, --boost Checks for turbo or boost modes *\n" | ||
460 | msgstr "" | ||
461 | |||
462 | #: utils/cpufreq-info.c:489 | ||
463 | #, c-format | ||
464 | msgid "" | ||
465 | " -o, --proc Prints out information like provided by the /proc/" | ||
466 | "cpufreq\n" | ||
467 | " interface in 2.4. and early 2.6. kernels\n" | ||
468 | msgstr "" | ||
469 | " -o, --proc Stampa le informazioni come se provenissero dalla\n" | ||
470 | " interfaccia cpufreq /proc/ presente nei kernel\n" | ||
471 | " 2.4 ed i primi 2.6\n" | ||
472 | |||
473 | #: utils/cpufreq-info.c:491 | ||
474 | #, c-format | ||
475 | msgid "" | ||
476 | " -m, --human human-readable output for the -f, -w, -s and -y " | ||
477 | "parameters\n" | ||
478 | msgstr "" | ||
479 | " -m, --human formatta l'output delle opzioni -f, -w, -s e -y in " | ||
480 | "maniera\n" | ||
481 | " leggibile da un essere umano\n" | ||
482 | |||
483 | #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 | ||
484 | #, c-format | ||
485 | msgid " -h, --help Prints out this screen\n" | ||
486 | msgstr " -h, --help Stampa questa schermata\n" | ||
487 | |||
488 | #: utils/cpufreq-info.c:495 | ||
489 | #, c-format | ||
490 | msgid "" | ||
491 | "If no argument or only the -c, --cpu parameter is given, debug output about\n" | ||
492 | "cpufreq is printed which is useful e.g. for reporting bugs.\n" | ||
493 | msgstr "" | ||
494 | "Se non viene specificata nessuna opzione o viene specificata solo l'opzione -" | ||
495 | "c, --cpu,\n" | ||
496 | "le informazioni di debug per cpufreq saranno utili ad esempio a riportare i " | ||
497 | "bug.\n" | ||
498 | |||
499 | #: utils/cpufreq-info.c:497 | ||
500 | #, c-format | ||
501 | msgid "" | ||
502 | "For the arguments marked with *, omitting the -c or --cpu argument is\n" | ||
503 | "equivalent to setting it to zero\n" | ||
504 | msgstr "" | ||
505 | "Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come " | ||
506 | "specificarla\n" | ||
507 | "con il valore 0\n" | ||
508 | |||
509 | #: utils/cpufreq-info.c:580 | ||
510 | #, c-format | ||
511 | msgid "" | ||
512 | "The argument passed to this tool can't be combined with passing a --cpu " | ||
513 | "argument\n" | ||
514 | msgstr "" | ||
515 | "L'opzione specificata a questo programma non può essere combinata con --cpu\n" | ||
516 | |||
517 | #: utils/cpufreq-info.c:596 | ||
518 | #, c-format | ||
519 | msgid "" | ||
520 | "You can't specify more than one --cpu parameter and/or\n" | ||
521 | "more than one output-specific argument\n" | ||
522 | msgstr "" | ||
523 | "Non è possibile specificare più di una volta l'opzione --cpu e/o\n" | ||
524 | "specificare più di un parametro di output specifico\n" | ||
525 | |||
526 | #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 | ||
527 | #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 | ||
528 | #, c-format | ||
529 | msgid "invalid or unknown argument\n" | ||
530 | msgstr "opzione sconosciuta o non valida\n" | ||
531 | |||
532 | #: utils/cpufreq-info.c:617 | ||
533 | #, c-format | ||
534 | msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" | ||
535 | msgstr "impossibile analizzare la CPU %d poiché non sembra essere presente\n" | ||
536 | |||
537 | #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 | ||
538 | #, c-format | ||
539 | msgid "analyzing CPU %d:\n" | ||
540 | msgstr "analisi della CPU %d:\n" | ||
541 | |||
542 | #: utils/cpufreq-set.c:25 | ||
543 | #, fuzzy, c-format | ||
544 | msgid "Usage: cpupower frequency-set [options]\n" | ||
545 | msgstr "Uso: cpufreq-set [opzioni]\n" | ||
546 | |||
547 | #: utils/cpufreq-set.c:27 | ||
548 | #, c-format | ||
549 | msgid "" | ||
550 | " -d FREQ, --min FREQ new minimum CPU frequency the governor may " | ||
551 | "select\n" | ||
552 | msgstr "" | ||
553 | " -d FREQ, --min FREQ la nuova frequenza minima che il gestore cpufreq " | ||
554 | "può scegliere\n" | ||
555 | |||
556 | #: utils/cpufreq-set.c:28 | ||
557 | #, c-format | ||
558 | msgid "" | ||
559 | " -u FREQ, --max FREQ new maximum CPU frequency the governor may " | ||
560 | "select\n" | ||
561 | msgstr "" | ||
562 | " -u FREQ, --max FREQ la nuova frequenza massima che il gestore cpufreq " | ||
563 | "può scegliere\n" | ||
564 | |||
565 | #: utils/cpufreq-set.c:29 | ||
566 | #, c-format | ||
567 | msgid " -g GOV, --governor GOV new cpufreq governor\n" | ||
568 | msgstr " -g GOV, --governor GOV nuovo gestore cpufreq\n" | ||
569 | |||
570 | #: utils/cpufreq-set.c:30 | ||
571 | #, c-format | ||
572 | msgid "" | ||
573 | " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
574 | " governor to be available and loaded\n" | ||
575 | msgstr "" | ||
576 | " -f FREQ, --freq FREQ specifica la frequenza a cui impostare la CPU.\n" | ||
577 | " È necessario che il gestore userspace sia " | ||
578 | "disponibile e caricato\n" | ||
579 | |||
580 | #: utils/cpufreq-set.c:32 | ||
581 | #, c-format | ||
582 | msgid " -r, --related Switches all hardware-related CPUs\n" | ||
583 | msgstr "" | ||
584 | " -r, --related Modifica tutte le CPU coordinate dall'hardware\n" | ||
585 | |||
586 | #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 | ||
587 | #, c-format | ||
588 | msgid " -h, --help Prints out this screen\n" | ||
589 | msgstr " -h, --help Stampa questa schermata\n" | ||
590 | |||
591 | #: utils/cpufreq-set.c:35 | ||
592 | #, fuzzy, c-format | ||
593 | msgid "" | ||
594 | "Notes:\n" | ||
595 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" | ||
596 | msgstr "" | ||
597 | "Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come " | ||
598 | "specificarla\n" | ||
599 | "con il valore 0\n" | ||
600 | |||
601 | #: utils/cpufreq-set.c:37 | ||
602 | #, fuzzy, c-format | ||
603 | msgid "" | ||
604 | "2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " | ||
605 | "parameter\n" | ||
606 | " except the -c CPU, --cpu CPU parameter\n" | ||
607 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
608 | " by postfixing the value with the wanted unit name, without any space\n" | ||
609 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
610 | msgstr "" | ||
611 | "Note:\n" | ||
612 | "1. Omettere l'opzione -c o --cpu è equivalente a impostarlo a 0\n" | ||
613 | "2. l'opzione -f FREQ, --freq FREQ non può essere specificata con altre " | ||
614 | "opzioni\n" | ||
615 | " ad eccezione dell'opzione -c CPU o --cpu CPU\n" | ||
616 | "3. le FREQuenze possono essere specuficate in Hz, kHz (default), MHz, GHz, " | ||
617 | "or THz\n" | ||
618 | " postponendo l'unità di misura al valore senza nessuno spazio fra loro\n" | ||
619 | " (FREQuenza in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
620 | |||
621 | #: utils/cpufreq-set.c:57 | ||
622 | #, c-format | ||
623 | msgid "" | ||
624 | "Error setting new values. Common errors:\n" | ||
625 | "- Do you have proper administration rights? (super-user?)\n" | ||
626 | "- Is the governor you requested available and modprobed?\n" | ||
627 | "- Trying to set an invalid policy?\n" | ||
628 | "- Trying to set a specific frequency, but userspace governor is not " | ||
629 | "available,\n" | ||
630 | " for example because of hardware which cannot be set to a specific " | ||
631 | "frequency\n" | ||
632 | " or because the userspace governor isn't loaded?\n" | ||
633 | msgstr "" | ||
634 | "Si sono verificati degli errori impostando i nuovi valori.\n" | ||
635 | "Alcuni errori comuni possono essere:\n" | ||
636 | "- Hai i necessari diritti di amministrazione? (super-user?)\n" | ||
637 | "- Il gestore che hai richiesto è disponibile e caricato?\n" | ||
638 | "- Stai provando ad impostare una politica di gestione non valida?\n" | ||
639 | "- Stai provando a impostare una specifica frequenza ma il gestore\n" | ||
640 | " userspace non è disponibile, per esempio a causa dell'hardware\n" | ||
641 | " che non supporta frequenze fisse o a causa del fatto che\n" | ||
642 | " il gestore userspace non è caricato?\n" | ||
643 | |||
644 | #: utils/cpufreq-set.c:170 | ||
645 | #, c-format | ||
646 | msgid "wrong, unknown or unhandled CPU?\n" | ||
647 | msgstr "CPU errata, sconosciuta o non gestita?\n" | ||
648 | |||
649 | #: utils/cpufreq-set.c:302 | ||
650 | #, c-format | ||
651 | msgid "" | ||
652 | "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
653 | "-g/--governor parameters\n" | ||
654 | msgstr "" | ||
655 | "l'opzione -f/--freq non può venire combinata con i parametri\n" | ||
656 | " -d/--min, -u/--max o -g/--governor\n" | ||
657 | |||
658 | #: utils/cpufreq-set.c:308 | ||
659 | #, c-format | ||
660 | msgid "" | ||
661 | "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
662 | "-g/--governor must be passed\n" | ||
663 | msgstr "" | ||
664 | "Almeno una delle opzioni -f/--freq, -d/--min, -u/--max, e -g/--governor\n" | ||
665 | "deve essere specificata\n" | ||
666 | |||
667 | #: utils/cpufreq-set.c:347 | ||
668 | #, c-format | ||
669 | msgid "Setting cpu: %d\n" | ||
670 | msgstr "" | ||
671 | |||
672 | #: utils/cpupower-set.c:22 | ||
673 | #, c-format | ||
674 | msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" | ||
675 | msgstr "" | ||
676 | |||
677 | #: utils/cpupower-set.c:24 | ||
678 | #, c-format | ||
679 | msgid "" | ||
680 | " -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
681 | " Intel models [0-15], see manpage for details\n" | ||
682 | msgstr "" | ||
683 | |||
684 | #: utils/cpupower-set.c:26 | ||
685 | #, c-format | ||
686 | msgid "" | ||
687 | " -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n" | ||
688 | msgstr "" | ||
689 | |||
690 | #: utils/cpupower-set.c:27 | ||
691 | #, c-format | ||
692 | msgid "" | ||
693 | " -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler " | ||
694 | "policy.\n" | ||
695 | msgstr "" | ||
696 | |||
697 | #: utils/cpupower-set.c:80 | ||
698 | #, c-format | ||
699 | msgid "--perf-bias param out of range [0-%d]\n" | ||
700 | msgstr "" | ||
701 | |||
702 | #: utils/cpupower-set.c:91 | ||
703 | #, c-format | ||
704 | msgid "--sched-mc param out of range [0-%d]\n" | ||
705 | msgstr "" | ||
706 | |||
707 | #: utils/cpupower-set.c:102 | ||
708 | #, c-format | ||
709 | msgid "--sched-smt param out of range [0-%d]\n" | ||
710 | msgstr "" | ||
711 | |||
712 | #: utils/cpupower-set.c:121 | ||
713 | #, c-format | ||
714 | msgid "Error setting sched-mc %s\n" | ||
715 | msgstr "" | ||
716 | |||
717 | #: utils/cpupower-set.c:127 | ||
718 | #, c-format | ||
719 | msgid "Error setting sched-smt %s\n" | ||
720 | msgstr "" | ||
721 | |||
722 | #: utils/cpupower-set.c:146 | ||
723 | #, c-format | ||
724 | msgid "Error setting perf-bias value on CPU %d\n" | ||
725 | msgstr "" | ||
726 | |||
727 | #: utils/cpupower-info.c:21 | ||
728 | #, c-format | ||
729 | msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" | ||
730 | msgstr "" | ||
731 | |||
732 | #: utils/cpupower-info.c:23 | ||
733 | #, c-format | ||
734 | msgid "" | ||
735 | " -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
736 | " Intel models [0-15], see manpage for details\n" | ||
737 | msgstr "" | ||
738 | |||
739 | #: utils/cpupower-info.c:25 | ||
740 | #, fuzzy, c-format | ||
741 | msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n" | ||
742 | msgstr "" | ||
743 | " -p, --policy Mostra il gestore cpufreq attualmente in uso *\n" | ||
744 | |||
745 | #: utils/cpupower-info.c:26 | ||
746 | #, c-format | ||
747 | msgid "" | ||
748 | " -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n" | ||
749 | msgstr "" | ||
750 | |||
751 | #: utils/cpupower-info.c:28 | ||
752 | #, c-format | ||
753 | msgid "" | ||
754 | "\n" | ||
755 | "Passing no option will show all info, by default only on core 0\n" | ||
756 | msgstr "" | ||
757 | |||
758 | #: utils/cpupower-info.c:102 | ||
759 | #, c-format | ||
760 | msgid "System's multi core scheduler setting: " | ||
761 | msgstr "" | ||
762 | |||
763 | #. if sysfs file is missing it's: errno == ENOENT | ||
764 | #: utils/cpupower-info.c:105 utils/cpupower-info.c:114 | ||
765 | #, c-format | ||
766 | msgid "not supported\n" | ||
767 | msgstr "" | ||
768 | |||
769 | #: utils/cpupower-info.c:111 | ||
770 | #, c-format | ||
771 | msgid "System's thread sibling scheduler setting: " | ||
772 | msgstr "" | ||
773 | |||
774 | #: utils/cpupower-info.c:126 | ||
775 | #, c-format | ||
776 | msgid "Intel's performance bias setting needs root privileges\n" | ||
777 | msgstr "" | ||
778 | |||
779 | #: utils/cpupower-info.c:128 | ||
780 | #, c-format | ||
781 | msgid "System does not support Intel's performance bias setting\n" | ||
782 | msgstr "" | ||
783 | |||
784 | #: utils/cpupower-info.c:147 | ||
785 | #, c-format | ||
786 | msgid "Could not read perf-bias value\n" | ||
787 | msgstr "" | ||
788 | |||
789 | #: utils/cpupower-info.c:150 | ||
790 | #, c-format | ||
791 | msgid "perf-bias: %d\n" | ||
792 | msgstr "" | ||
793 | |||
794 | #: utils/cpuidle-info.c:28 | ||
795 | #, fuzzy, c-format | ||
796 | msgid "Analyzing CPU %d:\n" | ||
797 | msgstr "analisi della CPU %d:\n" | ||
798 | |||
799 | #: utils/cpuidle-info.c:32 | ||
800 | #, c-format | ||
801 | msgid "CPU %u: No idle states\n" | ||
802 | msgstr "" | ||
803 | |||
804 | #: utils/cpuidle-info.c:36 | ||
805 | #, c-format | ||
806 | msgid "CPU %u: Can't read idle state info\n" | ||
807 | msgstr "" | ||
808 | |||
809 | #: utils/cpuidle-info.c:41 | ||
810 | #, c-format | ||
811 | msgid "Could not determine max idle state %u\n" | ||
812 | msgstr "" | ||
813 | |||
814 | #: utils/cpuidle-info.c:46 | ||
815 | #, c-format | ||
816 | msgid "Number of idle states: %d\n" | ||
817 | msgstr "" | ||
818 | |||
819 | #: utils/cpuidle-info.c:48 | ||
820 | #, fuzzy, c-format | ||
821 | msgid "Available idle states:" | ||
822 | msgstr " frequenze disponibili: " | ||
823 | |||
824 | #: utils/cpuidle-info.c:71 | ||
825 | #, c-format | ||
826 | msgid "Flags/Description: %s\n" | ||
827 | msgstr "" | ||
828 | |||
829 | #: utils/cpuidle-info.c:74 | ||
830 | #, c-format | ||
831 | msgid "Latency: %lu\n" | ||
832 | msgstr "" | ||
833 | |||
834 | #: utils/cpuidle-info.c:76 | ||
835 | #, c-format | ||
836 | msgid "Usage: %lu\n" | ||
837 | msgstr "" | ||
838 | |||
839 | #: utils/cpuidle-info.c:78 | ||
840 | #, c-format | ||
841 | msgid "Duration: %llu\n" | ||
842 | msgstr "" | ||
843 | |||
844 | #: utils/cpuidle-info.c:90 | ||
845 | #, c-format | ||
846 | msgid "Could not determine cpuidle driver\n" | ||
847 | msgstr "" | ||
848 | |||
849 | #: utils/cpuidle-info.c:94 | ||
850 | #, fuzzy, c-format | ||
851 | msgid "CPUidle driver: %s\n" | ||
852 | msgstr " modulo %s\n" | ||
853 | |||
854 | #: utils/cpuidle-info.c:99 | ||
855 | #, c-format | ||
856 | msgid "Could not determine cpuidle governor\n" | ||
857 | msgstr "" | ||
858 | |||
859 | #: utils/cpuidle-info.c:103 | ||
860 | #, c-format | ||
861 | msgid "CPUidle governor: %s\n" | ||
862 | msgstr "" | ||
863 | |||
864 | #: utils/cpuidle-info.c:122 | ||
865 | #, c-format | ||
866 | msgid "CPU %u: Can't read C-state info\n" | ||
867 | msgstr "" | ||
868 | |||
869 | #. printf("Cstates: %d\n", cstates); | ||
870 | #: utils/cpuidle-info.c:127 | ||
871 | #, c-format | ||
872 | msgid "active state: C0\n" | ||
873 | msgstr "" | ||
874 | |||
875 | #: utils/cpuidle-info.c:128 | ||
876 | #, c-format | ||
877 | msgid "max_cstate: C%u\n" | ||
878 | msgstr "" | ||
879 | |||
880 | #: utils/cpuidle-info.c:129 | ||
881 | #, fuzzy, c-format | ||
882 | msgid "maximum allowed latency: %lu usec\n" | ||
883 | msgstr " latenza massima durante la transizione: " | ||
884 | |||
885 | #: utils/cpuidle-info.c:130 | ||
886 | #, c-format | ||
887 | msgid "states:\t\n" | ||
888 | msgstr "" | ||
889 | |||
890 | #: utils/cpuidle-info.c:132 | ||
891 | #, c-format | ||
892 | msgid " C%d: type[C%d] " | ||
893 | msgstr "" | ||
894 | |||
895 | #: utils/cpuidle-info.c:134 | ||
896 | #, c-format | ||
897 | msgid "promotion[--] demotion[--] " | ||
898 | msgstr "" | ||
899 | |||
900 | #: utils/cpuidle-info.c:135 | ||
901 | #, c-format | ||
902 | msgid "latency[%03lu] " | ||
903 | msgstr "" | ||
904 | |||
905 | #: utils/cpuidle-info.c:137 | ||
906 | #, c-format | ||
907 | msgid "usage[%08lu] " | ||
908 | msgstr "" | ||
909 | |||
910 | #: utils/cpuidle-info.c:139 | ||
911 | #, c-format | ||
912 | msgid "duration[%020Lu] \n" | ||
913 | msgstr "" | ||
914 | |||
915 | #: utils/cpuidle-info.c:147 | ||
916 | #, fuzzy, c-format | ||
917 | msgid "Usage: cpupower idleinfo [options]\n" | ||
918 | msgstr "Uso: cpufreq-info [opzioni]\n" | ||
919 | |||
920 | #: utils/cpuidle-info.c:149 | ||
921 | #, fuzzy, c-format | ||
922 | msgid " -s, --silent Only show general C-state information\n" | ||
923 | msgstr " -e, --debug Mostra informazioni di debug\n" | ||
924 | |||
925 | #: utils/cpuidle-info.c:150 | ||
926 | #, fuzzy, c-format | ||
927 | msgid "" | ||
928 | " -o, --proc Prints out information like provided by the /proc/" | ||
929 | "acpi/processor/*/power\n" | ||
930 | " interface in older kernels\n" | ||
931 | msgstr "" | ||
932 | " -o, --proc Stampa le informazioni come se provenissero dalla\n" | ||
933 | " interfaccia cpufreq /proc/ presente nei kernel\n" | ||
934 | " 2.4 ed i primi 2.6\n" | ||
935 | |||
936 | #: utils/cpuidle-info.c:209 | ||
937 | #, fuzzy, c-format | ||
938 | msgid "You can't specify more than one output-specific argument\n" | ||
939 | msgstr "" | ||
940 | "Non è possibile specificare più di una volta l'opzione --cpu e/o\n" | ||
941 | "specificare più di un parametro di output specifico\n" | ||
942 | |||
943 | #~ msgid "" | ||
944 | #~ " -c CPU, --cpu CPU CPU number which information shall be determined " | ||
945 | #~ "about\n" | ||
946 | #~ msgstr "" | ||
947 | #~ " -c CPU, --cpu CPU Numero di CPU per la quale ottenere le " | ||
948 | #~ "informazioni\n" | ||
949 | |||
950 | #~ msgid "" | ||
951 | #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " | ||
952 | #~ "modified\n" | ||
953 | #~ msgstr "" | ||
954 | #~ " -c CPU, --cpu CPU numero di CPU per la quale modificare le " | ||
955 | #~ "impostazioni\n" | ||
956 | |||
957 | #, fuzzy | ||
958 | #~ msgid " CPUs which coordinate software frequency requirements: " | ||
959 | #~ msgstr "" | ||
960 | #~ " CPU per le quali e` necessario cambiare la frequenza " | ||
961 | #~ "contemporaneamente: " | ||
diff --git a/tools/power/cpupower/po/pt.po b/tools/power/cpupower/po/pt.po new file mode 100644 index 000000000000..990f5267ffe8 --- /dev/null +++ b/tools/power/cpupower/po/pt.po | |||
@@ -0,0 +1,957 @@ | |||
1 | # Brazilian Portuguese translations for cpufrequtils package | ||
2 | # Copyright (C) 2008 THE cpufrequtils'S COPYRIGHT HOLDER | ||
3 | # This file is distributed under the same license as the cpufrequtils package. | ||
4 | # Claudio Eduardo <claudioeddy@gmail.com>, 2009. | ||
5 | # | ||
6 | # | ||
7 | msgid "" | ||
8 | msgstr "" | ||
9 | "Project-Id-Version: cpufrequtils 004\n" | ||
10 | "Report-Msgid-Bugs-To: \n" | ||
11 | "POT-Creation-Date: 2011-03-08 17:03+0100\n" | ||
12 | "PO-Revision-Date: 2008-06-14 22:16-0400\n" | ||
13 | "Last-Translator: Claudio Eduardo <claudioeddy@gmail.com>\n" | ||
14 | "MIME-Version: 1.0\n" | ||
15 | "Content-Type: text/plain; charset=UTF-8\n" | ||
16 | "Content-Transfer-Encoding: 8bit\n" | ||
17 | |||
18 | #: utils/idle_monitor/nhm_idle.c:36 | ||
19 | msgid "Processor Core C3" | ||
20 | msgstr "" | ||
21 | |||
22 | #: utils/idle_monitor/nhm_idle.c:43 | ||
23 | msgid "Processor Core C6" | ||
24 | msgstr "" | ||
25 | |||
26 | #: utils/idle_monitor/nhm_idle.c:51 | ||
27 | msgid "Processor Package C3" | ||
28 | msgstr "" | ||
29 | |||
30 | #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 | ||
31 | msgid "Processor Package C6" | ||
32 | msgstr "" | ||
33 | |||
34 | #: utils/idle_monitor/snb_idle.c:33 | ||
35 | msgid "Processor Core C7" | ||
36 | msgstr "" | ||
37 | |||
38 | #: utils/idle_monitor/snb_idle.c:40 | ||
39 | msgid "Processor Package C2" | ||
40 | msgstr "" | ||
41 | |||
42 | #: utils/idle_monitor/snb_idle.c:47 | ||
43 | msgid "Processor Package C7" | ||
44 | msgstr "" | ||
45 | |||
46 | #: utils/idle_monitor/amd_fam14h_idle.c:56 | ||
47 | msgid "Package in sleep state (PC1 or deeper)" | ||
48 | msgstr "" | ||
49 | |||
50 | #: utils/idle_monitor/amd_fam14h_idle.c:63 | ||
51 | msgid "Processor Package C1" | ||
52 | msgstr "" | ||
53 | |||
54 | #: utils/idle_monitor/amd_fam14h_idle.c:77 | ||
55 | msgid "North Bridge P1 boolean counter (returns 0 or 1)" | ||
56 | msgstr "" | ||
57 | |||
58 | #: utils/idle_monitor/mperf_monitor.c:35 | ||
59 | msgid "Processor Core not idle" | ||
60 | msgstr "" | ||
61 | |||
62 | #: utils/idle_monitor/mperf_monitor.c:42 | ||
63 | msgid "Processor Core in an idle state" | ||
64 | msgstr "" | ||
65 | |||
66 | #: utils/idle_monitor/mperf_monitor.c:50 | ||
67 | msgid "Average Frequency (including boost) in MHz" | ||
68 | msgstr "" | ||
69 | |||
70 | #: utils/idle_monitor/cpupower-monitor.c:66 | ||
71 | #, c-format | ||
72 | msgid "" | ||
73 | "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
74 | "interval_sec | -c command ...]\n" | ||
75 | msgstr "" | ||
76 | |||
77 | #: utils/idle_monitor/cpupower-monitor.c:69 | ||
78 | #, c-format | ||
79 | msgid "" | ||
80 | "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " | ||
81 | "interval_sec | -c command ...]\n" | ||
82 | msgstr "" | ||
83 | |||
84 | #: utils/idle_monitor/cpupower-monitor.c:71 | ||
85 | #, c-format | ||
86 | msgid "\t -v: be more verbose\n" | ||
87 | msgstr "" | ||
88 | |||
89 | #: utils/idle_monitor/cpupower-monitor.c:73 | ||
90 | #, c-format | ||
91 | msgid "\t -h: print this help\n" | ||
92 | msgstr "" | ||
93 | |||
94 | #: utils/idle_monitor/cpupower-monitor.c:74 | ||
95 | #, c-format | ||
96 | msgid "\t -i: time intervall to measure for in seconds (default 1)\n" | ||
97 | msgstr "" | ||
98 | |||
99 | #: utils/idle_monitor/cpupower-monitor.c:75 | ||
100 | #, c-format | ||
101 | msgid "\t -t: show CPU topology/hierarchy\n" | ||
102 | msgstr "" | ||
103 | |||
104 | #: utils/idle_monitor/cpupower-monitor.c:76 | ||
105 | #, c-format | ||
106 | msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" | ||
107 | msgstr "" | ||
108 | |||
109 | #: utils/idle_monitor/cpupower-monitor.c:77 | ||
110 | #, c-format | ||
111 | msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" | ||
112 | msgstr "" | ||
113 | |||
114 | #: utils/idle_monitor/cpupower-monitor.c:79 | ||
115 | #, c-format | ||
116 | msgid "" | ||
117 | "only one of: -t, -l, -m are allowed\n" | ||
118 | "If none of them is passed," | ||
119 | msgstr "" | ||
120 | |||
121 | #: utils/idle_monitor/cpupower-monitor.c:80 | ||
122 | #, c-format | ||
123 | msgid " all supported monitors are shown\n" | ||
124 | msgstr "" | ||
125 | |||
126 | #: utils/idle_monitor/cpupower-monitor.c:197 | ||
127 | #, c-format | ||
128 | msgid "Monitor %s, Counter %s has no count function. Implementation error\n" | ||
129 | msgstr "" | ||
130 | |||
131 | #: utils/idle_monitor/cpupower-monitor.c:207 | ||
132 | #, c-format | ||
133 | msgid " *is offline\n" | ||
134 | msgstr "" | ||
135 | |||
136 | #: utils/idle_monitor/cpupower-monitor.c:236 | ||
137 | #, c-format | ||
138 | msgid "%s: max monitor name length (%d) exceeded\n" | ||
139 | msgstr "" | ||
140 | |||
141 | #: utils/idle_monitor/cpupower-monitor.c:250 | ||
142 | #, c-format | ||
143 | msgid "No matching monitor found in %s, try -l option\n" | ||
144 | msgstr "" | ||
145 | |||
146 | #: utils/idle_monitor/cpupower-monitor.c:266 | ||
147 | #, c-format | ||
148 | msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" | ||
149 | msgstr "" | ||
150 | |||
151 | #: utils/idle_monitor/cpupower-monitor.c:319 | ||
152 | #, c-format | ||
153 | msgid "%s took %.5f seconds and exited with status %d\n" | ||
154 | msgstr "" | ||
155 | |||
156 | #: utils/idle_monitor/cpupower-monitor.c:406 | ||
157 | #, c-format | ||
158 | msgid "Cannot read number of available processors\n" | ||
159 | msgstr "" | ||
160 | |||
161 | #: utils/idle_monitor/cpupower-monitor.c:417 | ||
162 | #, c-format | ||
163 | msgid "Available monitor %s needs root access\n" | ||
164 | msgstr "" | ||
165 | |||
166 | #: utils/idle_monitor/cpupower-monitor.c:428 | ||
167 | #, c-format | ||
168 | msgid "No HW Cstate monitors found\n" | ||
169 | msgstr "" | ||
170 | |||
171 | #: utils/cpupower.c:78 | ||
172 | #, c-format | ||
173 | msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" | ||
174 | msgstr "" | ||
175 | |||
176 | #: utils/cpupower.c:79 | ||
177 | #, c-format | ||
178 | msgid "cpupower --version\n" | ||
179 | msgstr "" | ||
180 | |||
181 | #: utils/cpupower.c:80 | ||
182 | #, c-format | ||
183 | msgid "Supported subcommands are:\n" | ||
184 | msgstr "" | ||
185 | |||
186 | #: utils/cpupower.c:83 | ||
187 | #, c-format | ||
188 | msgid "" | ||
189 | "\n" | ||
190 | "Some subcommands can make use of the -c cpulist option.\n" | ||
191 | msgstr "" | ||
192 | |||
193 | #: utils/cpupower.c:84 | ||
194 | #, c-format | ||
195 | msgid "Look at the general cpupower manpage how to use it\n" | ||
196 | msgstr "" | ||
197 | |||
198 | #: utils/cpupower.c:85 | ||
199 | #, c-format | ||
200 | msgid "and read up the subcommand's manpage whether it is supported.\n" | ||
201 | msgstr "" | ||
202 | |||
203 | #: utils/cpupower.c:86 | ||
204 | #, c-format | ||
205 | msgid "" | ||
206 | "\n" | ||
207 | "Use cpupower help subcommand for getting help for above subcommands.\n" | ||
208 | msgstr "" | ||
209 | |||
210 | #: utils/cpupower.c:91 | ||
211 | #, c-format | ||
212 | msgid "Report errors and bugs to %s, please.\n" | ||
213 | msgstr "Reporte erros e bugs para %s, por favor.\n" | ||
214 | |||
215 | #: utils/cpupower.c:114 | ||
216 | #, c-format | ||
217 | msgid "Error parsing cpu list\n" | ||
218 | msgstr "" | ||
219 | |||
220 | #: utils/cpupower.c:172 | ||
221 | #, c-format | ||
222 | msgid "Subcommand %s needs root privileges\n" | ||
223 | msgstr "" | ||
224 | |||
225 | #: utils/cpufreq-info.c:31 | ||
226 | #, c-format | ||
227 | msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" | ||
228 | msgstr "Não foi possÃvel contar o número de CPUs (%s: %s), assumindo 1\n" | ||
229 | |||
230 | #: utils/cpufreq-info.c:63 | ||
231 | #, c-format | ||
232 | msgid "" | ||
233 | " minimum CPU frequency - maximum CPU frequency - governor\n" | ||
234 | msgstr "" | ||
235 | " frequência mÃnina do CPU - frequência máxima do CPU - " | ||
236 | "regulador\n" | ||
237 | |||
238 | #: utils/cpufreq-info.c:151 | ||
239 | #, c-format | ||
240 | msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" | ||
241 | msgstr "" | ||
242 | |||
243 | #. P state changes via MSR are identified via cpuid 80000007 | ||
244 | #. on Intel and AMD, but we assume boost capable machines can do that | ||
245 | #. if (cpuid_eax(0x80000000) >= 0x80000007 | ||
246 | #. && (cpuid_edx(0x80000007) & (1 << 7))) | ||
247 | #. | ||
248 | #: utils/cpufreq-info.c:161 | ||
249 | #, c-format | ||
250 | msgid " boost state support: \n" | ||
251 | msgstr "" | ||
252 | |||
253 | #: utils/cpufreq-info.c:163 | ||
254 | #, c-format | ||
255 | msgid " Supported: %s\n" | ||
256 | msgstr "" | ||
257 | |||
258 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
259 | msgid "yes" | ||
260 | msgstr "" | ||
261 | |||
262 | #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 | ||
263 | msgid "no" | ||
264 | msgstr "" | ||
265 | |||
266 | #: utils/cpufreq-info.c:164 | ||
267 | #, fuzzy, c-format | ||
268 | msgid " Active: %s\n" | ||
269 | msgstr " driver: %s\n" | ||
270 | |||
271 | #: utils/cpufreq-info.c:177 | ||
272 | #, c-format | ||
273 | msgid " Boost States: %d\n" | ||
274 | msgstr "" | ||
275 | |||
276 | #: utils/cpufreq-info.c:178 | ||
277 | #, c-format | ||
278 | msgid " Total States: %d\n" | ||
279 | msgstr "" | ||
280 | |||
281 | #: utils/cpufreq-info.c:181 | ||
282 | #, c-format | ||
283 | msgid " Pstate-Pb%d: %luMHz (boost state)\n" | ||
284 | msgstr "" | ||
285 | |||
286 | #: utils/cpufreq-info.c:184 | ||
287 | #, c-format | ||
288 | msgid " Pstate-P%d: %luMHz\n" | ||
289 | msgstr "" | ||
290 | |||
291 | #: utils/cpufreq-info.c:211 | ||
292 | #, c-format | ||
293 | msgid " no or unknown cpufreq driver is active on this CPU\n" | ||
294 | msgstr " nenhum ou driver do cpufreq deconhecido está ativo nesse CPU\n" | ||
295 | |||
296 | #: utils/cpufreq-info.c:213 | ||
297 | #, c-format | ||
298 | msgid " driver: %s\n" | ||
299 | msgstr " driver: %s\n" | ||
300 | |||
301 | #: utils/cpufreq-info.c:219 | ||
302 | #, c-format | ||
303 | msgid " CPUs which run at the same hardware frequency: " | ||
304 | msgstr " CPUs que rodam na mesma frequência de hardware: " | ||
305 | |||
306 | #: utils/cpufreq-info.c:230 | ||
307 | #, c-format | ||
308 | msgid " CPUs which need to have their frequency coordinated by software: " | ||
309 | msgstr " CPUs que precisam ter suas frequências coordenadas por software: " | ||
310 | |||
311 | #: utils/cpufreq-info.c:241 | ||
312 | #, c-format | ||
313 | msgid " maximum transition latency: " | ||
314 | msgstr " maior latência de transição: " | ||
315 | |||
316 | #: utils/cpufreq-info.c:247 | ||
317 | #, c-format | ||
318 | msgid " hardware limits: " | ||
319 | msgstr " limites do hardware: " | ||
320 | |||
321 | #: utils/cpufreq-info.c:256 | ||
322 | #, c-format | ||
323 | msgid " available frequency steps: " | ||
324 | msgstr " nÃveis de frequência disponÃveis: " | ||
325 | |||
326 | #: utils/cpufreq-info.c:269 | ||
327 | #, c-format | ||
328 | msgid " available cpufreq governors: " | ||
329 | msgstr " reguladores do cpufreq disponÃveis: " | ||
330 | |||
331 | #: utils/cpufreq-info.c:280 | ||
332 | #, c-format | ||
333 | msgid " current policy: frequency should be within " | ||
334 | msgstr " polÃtica de frequência atual deve estar entre " | ||
335 | |||
336 | #: utils/cpufreq-info.c:282 | ||
337 | #, c-format | ||
338 | msgid " and " | ||
339 | msgstr " e " | ||
340 | |||
341 | #: utils/cpufreq-info.c:286 | ||
342 | #, c-format | ||
343 | msgid "" | ||
344 | "The governor \"%s\" may decide which speed to use\n" | ||
345 | " within this range.\n" | ||
346 | msgstr "" | ||
347 | "O regulador \"%s\" deve decidir qual velocidade usar\n" | ||
348 | " dentro desse limite.\n" | ||
349 | |||
350 | #: utils/cpufreq-info.c:293 | ||
351 | #, c-format | ||
352 | msgid " current CPU frequency is " | ||
353 | msgstr " frequência atual do CPU é " | ||
354 | |||
355 | #: utils/cpufreq-info.c:296 | ||
356 | #, c-format | ||
357 | msgid " (asserted by call to hardware)" | ||
358 | msgstr " (declarado por chamada ao hardware)" | ||
359 | |||
360 | #: utils/cpufreq-info.c:304 | ||
361 | #, c-format | ||
362 | msgid " cpufreq stats: " | ||
363 | msgstr " status do cpufreq: " | ||
364 | |||
365 | #: utils/cpufreq-info.c:472 | ||
366 | #, fuzzy, c-format | ||
367 | msgid "Usage: cpupower freqinfo [options]\n" | ||
368 | msgstr "Uso: cpufreq-info [opções]\n" | ||
369 | |||
370 | #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 | ||
371 | #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 | ||
372 | #, c-format | ||
373 | msgid "Options:\n" | ||
374 | msgstr "Opções:\n" | ||
375 | |||
376 | #: utils/cpufreq-info.c:474 | ||
377 | #, fuzzy, c-format | ||
378 | msgid " -e, --debug Prints out debug information [default]\n" | ||
379 | msgstr " -e, --debug Mostra informação de debug\n" | ||
380 | |||
381 | #: utils/cpufreq-info.c:475 | ||
382 | #, c-format | ||
383 | msgid "" | ||
384 | " -f, --freq Get frequency the CPU currently runs at, according\n" | ||
385 | " to the cpufreq core *\n" | ||
386 | msgstr "" | ||
387 | " -f, --freq Obtem a frequência na qual o CPU roda no momento, de " | ||
388 | "acordo\n" | ||
389 | " com o núcleo do cpufreq *\n" | ||
390 | |||
391 | #: utils/cpufreq-info.c:477 | ||
392 | #, c-format | ||
393 | msgid "" | ||
394 | " -w, --hwfreq Get frequency the CPU currently runs at, by reading\n" | ||
395 | " it from hardware (only available to root) *\n" | ||
396 | msgstr "" | ||
397 | " -w, --hwfreq Obtem a frequência na qual o CPU está operando no " | ||
398 | "momento,\n" | ||
399 | " através de leitura no hardware (disponÃvel somente " | ||
400 | "para root) *\n" | ||
401 | |||
402 | #: utils/cpufreq-info.c:479 | ||
403 | #, c-format | ||
404 | msgid "" | ||
405 | " -l, --hwlimits Determine the minimum and maximum CPU frequency " | ||
406 | "allowed *\n" | ||
407 | msgstr "" | ||
408 | " -l, --hwlimits Determina a frequência mÃnima e máxima do CPU " | ||
409 | "permitida *\n" | ||
410 | |||
411 | #: utils/cpufreq-info.c:480 | ||
412 | #, c-format | ||
413 | msgid " -d, --driver Determines the used cpufreq kernel driver *\n" | ||
414 | msgstr "" | ||
415 | " -d, --driver Determina o driver do kernel do cpufreq usado *\n" | ||
416 | |||
417 | #: utils/cpufreq-info.c:481 | ||
418 | #, c-format | ||
419 | msgid " -p, --policy Gets the currently used cpufreq policy *\n" | ||
420 | msgstr "" | ||
421 | "--p, --policy Obtem a polÃtica do cpufreq em uso no momento *\n" | ||
422 | |||
423 | #: utils/cpufreq-info.c:482 | ||
424 | #, c-format | ||
425 | msgid " -g, --governors Determines available cpufreq governors *\n" | ||
426 | msgstr "" | ||
427 | " -g, --governors Determina reguladores do cpufreq disponÃveis *\n" | ||
428 | |||
429 | #: utils/cpufreq-info.c:483 | ||
430 | #, c-format | ||
431 | msgid "" | ||
432 | " -r, --related-cpus Determines which CPUs run at the same hardware " | ||
433 | "frequency *\n" | ||
434 | msgstr "" | ||
435 | " -r, --related-cpus Determina quais CPUs rodam na mesma frequência de " | ||
436 | "hardware *\n" | ||
437 | |||
438 | #: utils/cpufreq-info.c:484 | ||
439 | #, c-format | ||
440 | msgid "" | ||
441 | " -a, --affected-cpus Determines which CPUs need to have their frequency\n" | ||
442 | " coordinated by software *\n" | ||
443 | msgstr "" | ||
444 | " -a, --affected-cpus Determina quais CPUs precisam ter suas frequências\n" | ||
445 | " coordenadas por software *\n" | ||
446 | |||
447 | #: utils/cpufreq-info.c:486 | ||
448 | #, c-format | ||
449 | msgid " -s, --stats Shows cpufreq statistics if available\n" | ||
450 | msgstr " -s, --stats Mostra estatÃsticas do cpufreq se disponÃveis\n" | ||
451 | |||
452 | #: utils/cpufreq-info.c:487 | ||
453 | #, c-format | ||
454 | msgid "" | ||
455 | " -y, --latency Determines the maximum latency on CPU frequency " | ||
456 | "changes *\n" | ||
457 | msgstr "" | ||
458 | " -y, --latency Determina a latência máxima nas trocas de frequência " | ||
459 | "do CPU *\n" | ||
460 | |||
461 | #: utils/cpufreq-info.c:488 | ||
462 | #, c-format | ||
463 | msgid " -b, --boost Checks for turbo or boost modes *\n" | ||
464 | msgstr "" | ||
465 | |||
466 | #: utils/cpufreq-info.c:489 | ||
467 | #, c-format | ||
468 | msgid "" | ||
469 | " -o, --proc Prints out information like provided by the /proc/" | ||
470 | "cpufreq\n" | ||
471 | " interface in 2.4. and early 2.6. kernels\n" | ||
472 | msgstr "" | ||
473 | " -o, --proc Mostra informação do tipo provida pela interface /" | ||
474 | "proc/cpufreq\n" | ||
475 | " em kernels 2.4. e mais recentes 2.6\n" | ||
476 | |||
477 | #: utils/cpufreq-info.c:491 | ||
478 | #, c-format | ||
479 | msgid "" | ||
480 | " -m, --human human-readable output for the -f, -w, -s and -y " | ||
481 | "parameters\n" | ||
482 | msgstr "" | ||
483 | " -m, --human saÃda legÃvel para humanos para os parâmetros -f, -w, " | ||
484 | "-s e -y\n" | ||
485 | |||
486 | #: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 | ||
487 | #, c-format | ||
488 | msgid " -h, --help Prints out this screen\n" | ||
489 | msgstr " -h, --help Imprime essa tela\n" | ||
490 | |||
491 | #: utils/cpufreq-info.c:495 | ||
492 | #, c-format | ||
493 | msgid "" | ||
494 | "If no argument or only the -c, --cpu parameter is given, debug output about\n" | ||
495 | "cpufreq is printed which is useful e.g. for reporting bugs.\n" | ||
496 | msgstr "" | ||
497 | "Se nenhum argumento ou somente o parâmetro -c, --cpu é dado, informação de " | ||
498 | "debug sobre\n" | ||
499 | "o cpufreq é mostrada, o que é útil por exemplo para reportar bugs.\n" | ||
500 | |||
501 | #: utils/cpufreq-info.c:497 | ||
502 | #, c-format | ||
503 | msgid "" | ||
504 | "For the arguments marked with *, omitting the -c or --cpu argument is\n" | ||
505 | "equivalent to setting it to zero\n" | ||
506 | msgstr "" | ||
507 | "Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n" | ||
508 | "equivalente a setá-lo como zero\n" | ||
509 | |||
510 | #: utils/cpufreq-info.c:580 | ||
511 | #, c-format | ||
512 | msgid "" | ||
513 | "The argument passed to this tool can't be combined with passing a --cpu " | ||
514 | "argument\n" | ||
515 | msgstr "" | ||
516 | "O argumento usado pra essa ferramenta não pode ser combinado com um " | ||
517 | "argumento --cpu\n" | ||
518 | |||
519 | #: utils/cpufreq-info.c:596 | ||
520 | #, c-format | ||
521 | msgid "" | ||
522 | "You can't specify more than one --cpu parameter and/or\n" | ||
523 | "more than one output-specific argument\n" | ||
524 | msgstr "" | ||
525 | "Você não pode especificar mais do que um parâmetro --cpu e/ou\n" | ||
526 | "mais do que um argumento de saÃda especÃfico\n" | ||
527 | |||
528 | #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 | ||
529 | #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 | ||
530 | #, c-format | ||
531 | msgid "invalid or unknown argument\n" | ||
532 | msgstr "argumento inválido ou desconhecido\n" | ||
533 | |||
534 | #: utils/cpufreq-info.c:617 | ||
535 | #, c-format | ||
536 | msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" | ||
537 | msgstr "" | ||
538 | "não foi possÃvel analisar o CPU % já que o mesmo parece não estar presente\n" | ||
539 | |||
540 | #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 | ||
541 | #, c-format | ||
542 | msgid "analyzing CPU %d:\n" | ||
543 | msgstr "analisando o CPU %d:\n" | ||
544 | |||
545 | #: utils/cpufreq-set.c:25 | ||
546 | #, fuzzy, c-format | ||
547 | msgid "Usage: cpupower frequency-set [options]\n" | ||
548 | msgstr "Uso: cpufreq-set [opções]\n" | ||
549 | |||
550 | #: utils/cpufreq-set.c:27 | ||
551 | #, c-format | ||
552 | msgid "" | ||
553 | " -d FREQ, --min FREQ new minimum CPU frequency the governor may " | ||
554 | "select\n" | ||
555 | msgstr "" | ||
556 | " -d FREQ, --min FREQ nova frequência mÃnima do CPU que o regulador " | ||
557 | "deve selecionar\n" | ||
558 | |||
559 | #: utils/cpufreq-set.c:28 | ||
560 | #, c-format | ||
561 | msgid "" | ||
562 | " -u FREQ, --max FREQ new maximum CPU frequency the governor may " | ||
563 | "select\n" | ||
564 | msgstr "" | ||
565 | " -u FREQ, --max FREQ nova frequência máxima do CPU que o regulador " | ||
566 | "deve escolher\n" | ||
567 | |||
568 | #: utils/cpufreq-set.c:29 | ||
569 | #, c-format | ||
570 | msgid " -g GOV, --governor GOV new cpufreq governor\n" | ||
571 | msgstr " -g GOV, --governor GOV novo regulador do cpufreq\n" | ||
572 | |||
573 | #: utils/cpufreq-set.c:30 | ||
574 | #, c-format | ||
575 | msgid "" | ||
576 | " -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n" | ||
577 | " governor to be available and loaded\n" | ||
578 | msgstr "" | ||
579 | " -f FREQ, --freq FREQ frequência especÃfica para ser setada. Necessita " | ||
580 | "que o regulador em\n" | ||
581 | " nÃvel de usuário esteja disponÃvel e carregado\n" | ||
582 | |||
583 | #: utils/cpufreq-set.c:32 | ||
584 | #, c-format | ||
585 | msgid " -r, --related Switches all hardware-related CPUs\n" | ||
586 | msgstr "" | ||
587 | " -r, --related Modifica todos os CPUs relacionados ao hardware\n" | ||
588 | |||
589 | #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 | ||
590 | #, c-format | ||
591 | msgid " -h, --help Prints out this screen\n" | ||
592 | msgstr " -h, --help Mostra essa tela\n" | ||
593 | |||
594 | #: utils/cpufreq-set.c:35 | ||
595 | #, fuzzy, c-format | ||
596 | msgid "" | ||
597 | "Notes:\n" | ||
598 | "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" | ||
599 | msgstr "" | ||
600 | "Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n" | ||
601 | "equivalente a setá-lo como zero\n" | ||
602 | |||
603 | #: utils/cpufreq-set.c:37 | ||
604 | #, fuzzy, c-format | ||
605 | msgid "" | ||
606 | "2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " | ||
607 | "parameter\n" | ||
608 | " except the -c CPU, --cpu CPU parameter\n" | ||
609 | "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" | ||
610 | " by postfixing the value with the wanted unit name, without any space\n" | ||
611 | " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
612 | msgstr "" | ||
613 | "Notas:\n" | ||
614 | "1. Omitir o argumento -c or --cpu é equivalente a setá-lo como zero\n" | ||
615 | "2. O parâmetro -f FREQ, --freq FREQ não pode ser combinado com qualquer " | ||
616 | "outro parâmetro\n" | ||
617 | " exceto com o parâmetro -c CPU, --cpu CPU\n" | ||
618 | "3. FREQuências podem ser usadas em Hz, kHz (padrão), MHz, GHz, o THz\n" | ||
619 | " colocando o nome desejado da unidade após o valor, sem qualquer espaço\n" | ||
620 | " (FREQuência em kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" | ||
621 | |||
622 | #: utils/cpufreq-set.c:57 | ||
623 | #, c-format | ||
624 | msgid "" | ||
625 | "Error setting new values. Common errors:\n" | ||
626 | "- Do you have proper administration rights? (super-user?)\n" | ||
627 | "- Is the governor you requested available and modprobed?\n" | ||
628 | "- Trying to set an invalid policy?\n" | ||
629 | "- Trying to set a specific frequency, but userspace governor is not " | ||
630 | "available,\n" | ||
631 | " for example because of hardware which cannot be set to a specific " | ||
632 | "frequency\n" | ||
633 | " or because the userspace governor isn't loaded?\n" | ||
634 | msgstr "" | ||
635 | "Erro ao setar novos valores. Erros comuns:\n" | ||
636 | "- Você tem direitos administrativos necessários? (super-usuário?)\n" | ||
637 | "- O regulador que você requesitou está disponÃvel e foi \"modprobed\"?\n" | ||
638 | "- Tentando setar uma polÃtica inválida?\n" | ||
639 | "- Tentando setar uma frequência especÃfica, mas o regulador em nÃvel de " | ||
640 | "usuário não está disponÃvel,\n" | ||
641 | " por exemplo devido ao hardware que não pode ser setado pra uma frequência " | ||
642 | "especÃfica\n" | ||
643 | " ou porque o regulador em nÃvel de usuário não foi carregado?\n" | ||
644 | |||
645 | #: utils/cpufreq-set.c:170 | ||
646 | #, c-format | ||
647 | msgid "wrong, unknown or unhandled CPU?\n" | ||
648 | msgstr "CPU errado, desconhecido ou inesperado?\n" | ||
649 | |||
650 | #: utils/cpufreq-set.c:302 | ||
651 | #, c-format | ||
652 | msgid "" | ||
653 | "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
654 | "-g/--governor parameters\n" | ||
655 | msgstr "" | ||
656 | "o parâmetro -f/--freq não pode ser combinado com os parâmetros -d/--min, -" | ||
657 | "u/--max ou\n" | ||
658 | "-g/--governor\n" | ||
659 | |||
660 | #: utils/cpufreq-set.c:308 | ||
661 | #, c-format | ||
662 | msgid "" | ||
663 | "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
664 | "-g/--governor must be passed\n" | ||
665 | msgstr "" | ||
666 | "Pelo menos um parâmetro entre -f/--freq, -d/--min, -u/--max, e\n" | ||
667 | "-g/--governor deve ser usado\n" | ||
668 | |||
669 | #: utils/cpufreq-set.c:347 | ||
670 | #, c-format | ||
671 | msgid "Setting cpu: %d\n" | ||
672 | msgstr "" | ||
673 | |||
674 | #: utils/cpupower-set.c:22 | ||
675 | #, c-format | ||
676 | msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" | ||
677 | msgstr "" | ||
678 | |||
679 | #: utils/cpupower-set.c:24 | ||
680 | #, c-format | ||
681 | msgid "" | ||
682 | " -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n" | ||
683 | " Intel models [0-15], see manpage for details\n" | ||
684 | msgstr "" | ||
685 | |||
686 | #: utils/cpupower-set.c:26 | ||
687 | #, c-format | ||
688 | msgid "" | ||
689 | " -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n" | ||
690 | msgstr "" | ||
691 | |||
692 | #: utils/cpupower-set.c:27 | ||
693 | #, c-format | ||
694 | msgid "" | ||
695 | " -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler " | ||
696 | "policy.\n" | ||
697 | msgstr "" | ||
698 | |||
699 | #: utils/cpupower-set.c:80 | ||
700 | #, c-format | ||
701 | msgid "--perf-bias param out of range [0-%d]\n" | ||
702 | msgstr "" | ||
703 | |||
704 | #: utils/cpupower-set.c:91 | ||
705 | #, c-format | ||
706 | msgid "--sched-mc param out of range [0-%d]\n" | ||
707 | msgstr "" | ||
708 | |||
709 | #: utils/cpupower-set.c:102 | ||
710 | #, c-format | ||
711 | msgid "--sched-smt param out of range [0-%d]\n" | ||
712 | msgstr "" | ||
713 | |||
714 | #: utils/cpupower-set.c:121 | ||
715 | #, c-format | ||
716 | msgid "Error setting sched-mc %s\n" | ||
717 | msgstr "" | ||
718 | |||
719 | #: utils/cpupower-set.c:127 | ||
720 | #, c-format | ||
721 | msgid "Error setting sched-smt %s\n" | ||
722 | msgstr "" | ||
723 | |||
724 | #: utils/cpupower-set.c:146 | ||
725 | #, c-format | ||
726 | msgid "Error setting perf-bias value on CPU %d\n" | ||
727 | msgstr "" | ||
728 | |||
729 | #: utils/cpupower-info.c:21 | ||
730 | #, c-format | ||
731 | msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" | ||
732 | msgstr "" | ||
733 | |||
734 | #: utils/cpupower-info.c:23 | ||
735 | #, c-format | ||
736 | msgid "" | ||
737 | " -b, --perf-bias Gets CPU's power vs performance policy on some\n" | ||
738 | " Intel models [0-15], see manpage for details\n" | ||
739 | msgstr "" | ||
740 | |||
741 | #: utils/cpupower-info.c:25 | ||
742 | #, fuzzy, c-format | ||
743 | msgid " -m, --sched-mc Gets the kernel's multi core scheduler policy.\n" | ||
744 | msgstr "" | ||
745 | "--p, --policy Obtem a polÃtica do cpufreq em uso no momento *\n" | ||
746 | |||
747 | #: utils/cpupower-info.c:26 | ||
748 | #, c-format | ||
749 | msgid "" | ||
750 | " -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n" | ||
751 | msgstr "" | ||
752 | |||
753 | #: utils/cpupower-info.c:28 | ||
754 | #, c-format | ||
755 | msgid "" | ||
756 | "\n" | ||
757 | "Passing no option will show all info, by default only on core 0\n" | ||
758 | msgstr "" | ||
759 | |||
760 | #: utils/cpupower-info.c:102 | ||
761 | #, c-format | ||
762 | msgid "System's multi core scheduler setting: " | ||
763 | msgstr "" | ||
764 | |||
765 | #. if sysfs file is missing it's: errno == ENOENT | ||
766 | #: utils/cpupower-info.c:105 utils/cpupower-info.c:114 | ||
767 | #, c-format | ||
768 | msgid "not supported\n" | ||
769 | msgstr "" | ||
770 | |||
771 | #: utils/cpupower-info.c:111 | ||
772 | #, c-format | ||
773 | msgid "System's thread sibling scheduler setting: " | ||
774 | msgstr "" | ||
775 | |||
776 | #: utils/cpupower-info.c:126 | ||
777 | #, c-format | ||
778 | msgid "Intel's performance bias setting needs root privileges\n" | ||
779 | msgstr "" | ||
780 | |||
781 | #: utils/cpupower-info.c:128 | ||
782 | #, c-format | ||
783 | msgid "System does not support Intel's performance bias setting\n" | ||
784 | msgstr "" | ||
785 | |||
786 | #: utils/cpupower-info.c:147 | ||
787 | #, c-format | ||
788 | msgid "Could not read perf-bias value\n" | ||
789 | msgstr "" | ||
790 | |||
791 | #: utils/cpupower-info.c:150 | ||
792 | #, c-format | ||
793 | msgid "perf-bias: %d\n" | ||
794 | msgstr "" | ||
795 | |||
796 | #: utils/cpuidle-info.c:28 | ||
797 | #, fuzzy, c-format | ||
798 | msgid "Analyzing CPU %d:\n" | ||
799 | msgstr "analisando o CPU %d:\n" | ||
800 | |||
801 | #: utils/cpuidle-info.c:32 | ||
802 | #, c-format | ||
803 | msgid "CPU %u: No idle states\n" | ||
804 | msgstr "" | ||
805 | |||
806 | #: utils/cpuidle-info.c:36 | ||
807 | #, c-format | ||
808 | msgid "CPU %u: Can't read idle state info\n" | ||
809 | msgstr "" | ||
810 | |||
811 | #: utils/cpuidle-info.c:41 | ||
812 | #, c-format | ||
813 | msgid "Could not determine max idle state %u\n" | ||
814 | msgstr "" | ||
815 | |||
816 | #: utils/cpuidle-info.c:46 | ||
817 | #, c-format | ||
818 | msgid "Number of idle states: %d\n" | ||
819 | msgstr "" | ||
820 | |||
821 | #: utils/cpuidle-info.c:48 | ||
822 | #, fuzzy, c-format | ||
823 | msgid "Available idle states:" | ||
824 | msgstr " nÃveis de frequência disponÃveis: " | ||
825 | |||
826 | #: utils/cpuidle-info.c:71 | ||
827 | #, c-format | ||
828 | msgid "Flags/Description: %s\n" | ||
829 | msgstr "" | ||
830 | |||
831 | #: utils/cpuidle-info.c:74 | ||
832 | #, c-format | ||
833 | msgid "Latency: %lu\n" | ||
834 | msgstr "" | ||
835 | |||
836 | #: utils/cpuidle-info.c:76 | ||
837 | #, c-format | ||
838 | msgid "Usage: %lu\n" | ||
839 | msgstr "" | ||
840 | |||
841 | #: utils/cpuidle-info.c:78 | ||
842 | #, c-format | ||
843 | msgid "Duration: %llu\n" | ||
844 | msgstr "" | ||
845 | |||
846 | #: utils/cpuidle-info.c:90 | ||
847 | #, c-format | ||
848 | msgid "Could not determine cpuidle driver\n" | ||
849 | msgstr "" | ||
850 | |||
851 | #: utils/cpuidle-info.c:94 | ||
852 | #, fuzzy, c-format | ||
853 | msgid "CPUidle driver: %s\n" | ||
854 | msgstr " driver: %s\n" | ||
855 | |||
856 | #: utils/cpuidle-info.c:99 | ||
857 | #, c-format | ||
858 | msgid "Could not determine cpuidle governor\n" | ||
859 | msgstr "" | ||
860 | |||
861 | #: utils/cpuidle-info.c:103 | ||
862 | #, c-format | ||
863 | msgid "CPUidle governor: %s\n" | ||
864 | msgstr "" | ||
865 | |||
866 | #: utils/cpuidle-info.c:122 | ||
867 | #, c-format | ||
868 | msgid "CPU %u: Can't read C-state info\n" | ||
869 | msgstr "" | ||
870 | |||
871 | #. printf("Cstates: %d\n", cstates); | ||
872 | #: utils/cpuidle-info.c:127 | ||
873 | #, c-format | ||
874 | msgid "active state: C0\n" | ||
875 | msgstr "" | ||
876 | |||
877 | #: utils/cpuidle-info.c:128 | ||
878 | #, c-format | ||
879 | msgid "max_cstate: C%u\n" | ||
880 | msgstr "" | ||
881 | |||
882 | #: utils/cpuidle-info.c:129 | ||
883 | #, fuzzy, c-format | ||
884 | msgid "maximum allowed latency: %lu usec\n" | ||
885 | msgstr " maior latência de transição: " | ||
886 | |||
887 | #: utils/cpuidle-info.c:130 | ||
888 | #, c-format | ||
889 | msgid "states:\t\n" | ||
890 | msgstr "" | ||
891 | |||
892 | #: utils/cpuidle-info.c:132 | ||
893 | #, c-format | ||
894 | msgid " C%d: type[C%d] " | ||
895 | msgstr "" | ||
896 | |||
897 | #: utils/cpuidle-info.c:134 | ||
898 | #, c-format | ||
899 | msgid "promotion[--] demotion[--] " | ||
900 | msgstr "" | ||
901 | |||
902 | #: utils/cpuidle-info.c:135 | ||
903 | #, c-format | ||
904 | msgid "latency[%03lu] " | ||
905 | msgstr "" | ||
906 | |||
907 | #: utils/cpuidle-info.c:137 | ||
908 | #, c-format | ||
909 | msgid "usage[%08lu] " | ||
910 | msgstr "" | ||
911 | |||
912 | #: utils/cpuidle-info.c:139 | ||
913 | #, c-format | ||
914 | msgid "duration[%020Lu] \n" | ||
915 | msgstr "" | ||
916 | |||
917 | #: utils/cpuidle-info.c:147 | ||
918 | #, fuzzy, c-format | ||
919 | msgid "Usage: cpupower idleinfo [options]\n" | ||
920 | msgstr "Uso: cpufreq-info [opções]\n" | ||
921 | |||
922 | #: utils/cpuidle-info.c:149 | ||
923 | #, fuzzy, c-format | ||
924 | msgid " -s, --silent Only show general C-state information\n" | ||
925 | msgstr " -e, --debug Mostra informação de debug\n" | ||
926 | |||
927 | #: utils/cpuidle-info.c:150 | ||
928 | #, fuzzy, c-format | ||
929 | msgid "" | ||
930 | " -o, --proc Prints out information like provided by the /proc/" | ||
931 | "acpi/processor/*/power\n" | ||
932 | " interface in older kernels\n" | ||
933 | msgstr "" | ||
934 | " -o, --proc Mostra informação do tipo provida pela interface /" | ||
935 | "proc/cpufreq\n" | ||
936 | " em kernels 2.4. e mais recentes 2.6\n" | ||
937 | |||
938 | #: utils/cpuidle-info.c:209 | ||
939 | #, fuzzy, c-format | ||
940 | msgid "You can't specify more than one output-specific argument\n" | ||
941 | msgstr "" | ||
942 | "Você não pode especificar mais do que um parâmetro --cpu e/ou\n" | ||
943 | "mais do que um argumento de saÃda especÃfico\n" | ||
944 | |||
945 | #~ msgid "" | ||
946 | #~ " -c CPU, --cpu CPU CPU number which information shall be determined " | ||
947 | #~ "about\n" | ||
948 | #~ msgstr "" | ||
949 | #~ " -c CPU, --cpu CPU número do CPU sobre o qual as inforções devem ser " | ||
950 | #~ "determinadas\n" | ||
951 | |||
952 | #~ msgid "" | ||
953 | #~ " -c CPU, --cpu CPU number of CPU where cpufreq settings shall be " | ||
954 | #~ "modified\n" | ||
955 | #~ msgstr "" | ||
956 | #~ " -c CPU, --cpu CPU número do CPU onde as configurações do cpufreq " | ||
957 | #~ "vão ser modificadas\n" | ||
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h new file mode 100644 index 000000000000..c10496fbe3c6 --- /dev/null +++ b/tools/power/cpupower/utils/builtin.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef BUILTIN_H | ||
2 | #define BUILTIN_H | ||
3 | |||
4 | extern int cmd_set(int argc, const char **argv); | ||
5 | extern int cmd_info(int argc, const char **argv); | ||
6 | extern int cmd_freq_set(int argc, const char **argv); | ||
7 | extern int cmd_freq_info(int argc, const char **argv); | ||
8 | extern int cmd_idle_info(int argc, const char **argv); | ||
9 | extern int cmd_monitor(int argc, const char **argv); | ||
10 | |||
11 | #endif | ||
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c new file mode 100644 index 000000000000..28953c9a7bd5 --- /dev/null +++ b/tools/power/cpupower/utils/cpufreq-info.c | |||
@@ -0,0 +1,668 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <unistd.h> | ||
9 | #include <stdio.h> | ||
10 | #include <errno.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | |||
14 | #include <getopt.h> | ||
15 | |||
16 | #include "cpufreq.h" | ||
17 | #include "helpers/helpers.h" | ||
18 | #include "helpers/bitmask.h" | ||
19 | |||
20 | #define LINE_LEN 10 | ||
21 | |||
22 | static unsigned int count_cpus(void) | ||
23 | { | ||
24 | FILE *fp; | ||
25 | char value[LINE_LEN]; | ||
26 | unsigned int ret = 0; | ||
27 | unsigned int cpunr = 0; | ||
28 | |||
29 | fp = fopen("/proc/stat", "r"); | ||
30 | if (!fp) { | ||
31 | printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno)); | ||
32 | return 1; | ||
33 | } | ||
34 | |||
35 | while (!feof(fp)) { | ||
36 | if (!fgets(value, LINE_LEN, fp)) | ||
37 | continue; | ||
38 | value[LINE_LEN - 1] = '\0'; | ||
39 | if (strlen(value) < (LINE_LEN - 2)) | ||
40 | continue; | ||
41 | if (strstr(value, "cpu ")) | ||
42 | continue; | ||
43 | if (sscanf(value, "cpu%d ", &cpunr) != 1) | ||
44 | continue; | ||
45 | if (cpunr > ret) | ||
46 | ret = cpunr; | ||
47 | } | ||
48 | fclose(fp); | ||
49 | |||
50 | /* cpu count starts from 0, on error return 1 (UP) */ | ||
51 | return ret + 1; | ||
52 | } | ||
53 | |||
54 | |||
55 | static void proc_cpufreq_output(void) | ||
56 | { | ||
57 | unsigned int cpu, nr_cpus; | ||
58 | struct cpufreq_policy *policy; | ||
59 | unsigned int min_pctg = 0; | ||
60 | unsigned int max_pctg = 0; | ||
61 | unsigned long min, max; | ||
62 | |||
63 | printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n")); | ||
64 | |||
65 | nr_cpus = count_cpus(); | ||
66 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
67 | policy = cpufreq_get_policy(cpu); | ||
68 | if (!policy) | ||
69 | continue; | ||
70 | |||
71 | if (cpufreq_get_hardware_limits(cpu, &min, &max)) { | ||
72 | max = 0; | ||
73 | } else { | ||
74 | min_pctg = (policy->min * 100) / max; | ||
75 | max_pctg = (policy->max * 100) / max; | ||
76 | } | ||
77 | printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n", | ||
78 | cpu , policy->min, max ? min_pctg : 0, policy->max, | ||
79 | max ? max_pctg : 0, policy->governor); | ||
80 | |||
81 | cpufreq_put_policy(policy); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static void print_speed(unsigned long speed) | ||
86 | { | ||
87 | unsigned long tmp; | ||
88 | |||
89 | if (speed > 1000000) { | ||
90 | tmp = speed % 10000; | ||
91 | if (tmp >= 5000) | ||
92 | speed += 10000; | ||
93 | printf("%u.%02u GHz", ((unsigned int) speed/1000000), | ||
94 | ((unsigned int) (speed%1000000)/10000)); | ||
95 | } else if (speed > 100000) { | ||
96 | tmp = speed % 1000; | ||
97 | if (tmp >= 500) | ||
98 | speed += 1000; | ||
99 | printf("%u MHz", ((unsigned int) speed / 1000)); | ||
100 | } else if (speed > 1000) { | ||
101 | tmp = speed % 100; | ||
102 | if (tmp >= 50) | ||
103 | speed += 100; | ||
104 | printf("%u.%01u MHz", ((unsigned int) speed/1000), | ||
105 | ((unsigned int) (speed%1000)/100)); | ||
106 | } else | ||
107 | printf("%lu kHz", speed); | ||
108 | |||
109 | return; | ||
110 | } | ||
111 | |||
112 | static void print_duration(unsigned long duration) | ||
113 | { | ||
114 | unsigned long tmp; | ||
115 | |||
116 | if (duration > 1000000) { | ||
117 | tmp = duration % 10000; | ||
118 | if (tmp >= 5000) | ||
119 | duration += 10000; | ||
120 | printf("%u.%02u ms", ((unsigned int) duration/1000000), | ||
121 | ((unsigned int) (duration%1000000)/10000)); | ||
122 | } else if (duration > 100000) { | ||
123 | tmp = duration % 1000; | ||
124 | if (tmp >= 500) | ||
125 | duration += 1000; | ||
126 | printf("%u us", ((unsigned int) duration / 1000)); | ||
127 | } else if (duration > 1000) { | ||
128 | tmp = duration % 100; | ||
129 | if (tmp >= 50) | ||
130 | duration += 100; | ||
131 | printf("%u.%01u us", ((unsigned int) duration/1000), | ||
132 | ((unsigned int) (duration%1000)/100)); | ||
133 | } else | ||
134 | printf("%lu ns", duration); | ||
135 | |||
136 | return; | ||
137 | } | ||
138 | |||
139 | /* --boost / -b */ | ||
140 | |||
141 | static int get_boost_mode(unsigned int cpu) | ||
142 | { | ||
143 | int support, active, b_states = 0, ret, pstate_no, i; | ||
144 | /* ToDo: Make this more global */ | ||
145 | unsigned long pstates[MAX_HW_PSTATES] = {0,}; | ||
146 | |||
147 | if (cpupower_cpu_info.vendor != X86_VENDOR_AMD && | ||
148 | cpupower_cpu_info.vendor != X86_VENDOR_INTEL) | ||
149 | return 0; | ||
150 | |||
151 | ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); | ||
152 | if (ret) { | ||
153 | printf(_("Error while evaluating Boost Capabilities" | ||
154 | " on CPU %d -- are you root?\n"), cpu); | ||
155 | return ret; | ||
156 | } | ||
157 | /* P state changes via MSR are identified via cpuid 80000007 | ||
158 | on Intel and AMD, but we assume boost capable machines can do that | ||
159 | if (cpuid_eax(0x80000000) >= 0x80000007 | ||
160 | && (cpuid_edx(0x80000007) & (1 << 7))) | ||
161 | */ | ||
162 | |||
163 | printf(_(" boost state support:\n")); | ||
164 | |||
165 | printf(_(" Supported: %s\n"), support ? _("yes") : _("no")); | ||
166 | printf(_(" Active: %s\n"), active ? _("yes") : _("no")); | ||
167 | |||
168 | if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && | ||
169 | cpupower_cpu_info.family >= 0x10) { | ||
170 | ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states, | ||
171 | pstates, &pstate_no); | ||
172 | if (ret) | ||
173 | return ret; | ||
174 | |||
175 | printf(_(" Boost States: %d\n"), b_states); | ||
176 | printf(_(" Total States: %d\n"), pstate_no); | ||
177 | for (i = 0; i < pstate_no; i++) { | ||
178 | if (i < b_states) | ||
179 | printf(_(" Pstate-Pb%d: %luMHz (boost state)" | ||
180 | "\n"), i, pstates[i]); | ||
181 | else | ||
182 | printf(_(" Pstate-P%d: %luMHz\n"), | ||
183 | i - b_states, pstates[i]); | ||
184 | } | ||
185 | } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) { | ||
186 | double bclk; | ||
187 | unsigned long long intel_turbo_ratio = 0; | ||
188 | unsigned int ratio; | ||
189 | |||
190 | /* Any way to autodetect this ? */ | ||
191 | if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB) | ||
192 | bclk = 100.00; | ||
193 | else | ||
194 | bclk = 133.33; | ||
195 | intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu); | ||
196 | dprint (" Ratio: 0x%llx - bclk: %f\n", | ||
197 | intel_turbo_ratio, bclk); | ||
198 | |||
199 | ratio = (intel_turbo_ratio >> 24) & 0xFF; | ||
200 | if (ratio) | ||
201 | printf(_(" %.0f MHz max turbo 4 active cores\n"), | ||
202 | ratio * bclk); | ||
203 | |||
204 | ratio = (intel_turbo_ratio >> 16) & 0xFF; | ||
205 | if (ratio) | ||
206 | printf(_(" %.0f MHz max turbo 3 active cores\n"), | ||
207 | ratio * bclk); | ||
208 | |||
209 | ratio = (intel_turbo_ratio >> 8) & 0xFF; | ||
210 | if (ratio) | ||
211 | printf(_(" %.0f MHz max turbo 2 active cores\n"), | ||
212 | ratio * bclk); | ||
213 | |||
214 | ratio = (intel_turbo_ratio >> 0) & 0xFF; | ||
215 | if (ratio) | ||
216 | printf(_(" %.0f MHz max turbo 1 active cores\n"), | ||
217 | ratio * bclk); | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static void debug_output_one(unsigned int cpu) | ||
223 | { | ||
224 | char *driver; | ||
225 | struct cpufreq_affected_cpus *cpus; | ||
226 | struct cpufreq_available_frequencies *freqs; | ||
227 | unsigned long min, max, freq_kernel, freq_hardware; | ||
228 | unsigned long total_trans, latency; | ||
229 | unsigned long long total_time; | ||
230 | struct cpufreq_policy *policy; | ||
231 | struct cpufreq_available_governors *governors; | ||
232 | struct cpufreq_stats *stats; | ||
233 | |||
234 | if (cpufreq_cpu_exists(cpu)) | ||
235 | return; | ||
236 | |||
237 | freq_kernel = cpufreq_get_freq_kernel(cpu); | ||
238 | freq_hardware = cpufreq_get_freq_hardware(cpu); | ||
239 | |||
240 | driver = cpufreq_get_driver(cpu); | ||
241 | if (!driver) { | ||
242 | printf(_(" no or unknown cpufreq driver is active on this CPU\n")); | ||
243 | } else { | ||
244 | printf(_(" driver: %s\n"), driver); | ||
245 | cpufreq_put_driver(driver); | ||
246 | } | ||
247 | |||
248 | cpus = cpufreq_get_related_cpus(cpu); | ||
249 | if (cpus) { | ||
250 | printf(_(" CPUs which run at the same hardware frequency: ")); | ||
251 | while (cpus->next) { | ||
252 | printf("%d ", cpus->cpu); | ||
253 | cpus = cpus->next; | ||
254 | } | ||
255 | printf("%d\n", cpus->cpu); | ||
256 | cpufreq_put_related_cpus(cpus); | ||
257 | } | ||
258 | |||
259 | cpus = cpufreq_get_affected_cpus(cpu); | ||
260 | if (cpus) { | ||
261 | printf(_(" CPUs which need to have their frequency coordinated by software: ")); | ||
262 | while (cpus->next) { | ||
263 | printf("%d ", cpus->cpu); | ||
264 | cpus = cpus->next; | ||
265 | } | ||
266 | printf("%d\n", cpus->cpu); | ||
267 | cpufreq_put_affected_cpus(cpus); | ||
268 | } | ||
269 | |||
270 | latency = cpufreq_get_transition_latency(cpu); | ||
271 | if (latency) { | ||
272 | printf(_(" maximum transition latency: ")); | ||
273 | print_duration(latency); | ||
274 | printf(".\n"); | ||
275 | } | ||
276 | |||
277 | if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) { | ||
278 | printf(_(" hardware limits: ")); | ||
279 | print_speed(min); | ||
280 | printf(" - "); | ||
281 | print_speed(max); | ||
282 | printf("\n"); | ||
283 | } | ||
284 | |||
285 | freqs = cpufreq_get_available_frequencies(cpu); | ||
286 | if (freqs) { | ||
287 | printf(_(" available frequency steps: ")); | ||
288 | while (freqs->next) { | ||
289 | print_speed(freqs->frequency); | ||
290 | printf(", "); | ||
291 | freqs = freqs->next; | ||
292 | } | ||
293 | print_speed(freqs->frequency); | ||
294 | printf("\n"); | ||
295 | cpufreq_put_available_frequencies(freqs); | ||
296 | } | ||
297 | |||
298 | governors = cpufreq_get_available_governors(cpu); | ||
299 | if (governors) { | ||
300 | printf(_(" available cpufreq governors: ")); | ||
301 | while (governors->next) { | ||
302 | printf("%s, ", governors->governor); | ||
303 | governors = governors->next; | ||
304 | } | ||
305 | printf("%s\n", governors->governor); | ||
306 | cpufreq_put_available_governors(governors); | ||
307 | } | ||
308 | |||
309 | policy = cpufreq_get_policy(cpu); | ||
310 | if (policy) { | ||
311 | printf(_(" current policy: frequency should be within ")); | ||
312 | print_speed(policy->min); | ||
313 | printf(_(" and ")); | ||
314 | print_speed(policy->max); | ||
315 | |||
316 | printf(".\n "); | ||
317 | printf(_("The governor \"%s\" may" | ||
318 | " decide which speed to use\n within this range.\n"), | ||
319 | policy->governor); | ||
320 | cpufreq_put_policy(policy); | ||
321 | } | ||
322 | |||
323 | if (freq_kernel || freq_hardware) { | ||
324 | printf(_(" current CPU frequency is ")); | ||
325 | if (freq_hardware) { | ||
326 | print_speed(freq_hardware); | ||
327 | printf(_(" (asserted by call to hardware)")); | ||
328 | } else | ||
329 | print_speed(freq_kernel); | ||
330 | printf(".\n"); | ||
331 | } | ||
332 | stats = cpufreq_get_stats(cpu, &total_time); | ||
333 | if (stats) { | ||
334 | printf(_(" cpufreq stats: ")); | ||
335 | while (stats) { | ||
336 | print_speed(stats->frequency); | ||
337 | printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time); | ||
338 | stats = stats->next; | ||
339 | if (stats) | ||
340 | printf(", "); | ||
341 | } | ||
342 | cpufreq_put_stats(stats); | ||
343 | total_trans = cpufreq_get_transitions(cpu); | ||
344 | if (total_trans) | ||
345 | printf(" (%lu)\n", total_trans); | ||
346 | else | ||
347 | printf("\n"); | ||
348 | } | ||
349 | get_boost_mode(cpu); | ||
350 | |||
351 | } | ||
352 | |||
353 | /* --freq / -f */ | ||
354 | |||
355 | static int get_freq_kernel(unsigned int cpu, unsigned int human) | ||
356 | { | ||
357 | unsigned long freq = cpufreq_get_freq_kernel(cpu); | ||
358 | if (!freq) | ||
359 | return -EINVAL; | ||
360 | if (human) { | ||
361 | print_speed(freq); | ||
362 | printf("\n"); | ||
363 | } else | ||
364 | printf("%lu\n", freq); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | |||
369 | /* --hwfreq / -w */ | ||
370 | |||
371 | static int get_freq_hardware(unsigned int cpu, unsigned int human) | ||
372 | { | ||
373 | unsigned long freq = cpufreq_get_freq_hardware(cpu); | ||
374 | if (!freq) | ||
375 | return -EINVAL; | ||
376 | if (human) { | ||
377 | print_speed(freq); | ||
378 | printf("\n"); | ||
379 | } else | ||
380 | printf("%lu\n", freq); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* --hwlimits / -l */ | ||
385 | |||
386 | static int get_hardware_limits(unsigned int cpu) | ||
387 | { | ||
388 | unsigned long min, max; | ||
389 | if (cpufreq_get_hardware_limits(cpu, &min, &max)) | ||
390 | return -EINVAL; | ||
391 | printf("%lu %lu\n", min, max); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | /* --driver / -d */ | ||
396 | |||
397 | static int get_driver(unsigned int cpu) | ||
398 | { | ||
399 | char *driver = cpufreq_get_driver(cpu); | ||
400 | if (!driver) | ||
401 | return -EINVAL; | ||
402 | printf("%s\n", driver); | ||
403 | cpufreq_put_driver(driver); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* --policy / -p */ | ||
408 | |||
409 | static int get_policy(unsigned int cpu) | ||
410 | { | ||
411 | struct cpufreq_policy *policy = cpufreq_get_policy(cpu); | ||
412 | if (!policy) | ||
413 | return -EINVAL; | ||
414 | printf("%lu %lu %s\n", policy->min, policy->max, policy->governor); | ||
415 | cpufreq_put_policy(policy); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* --governors / -g */ | ||
420 | |||
421 | static int get_available_governors(unsigned int cpu) | ||
422 | { | ||
423 | struct cpufreq_available_governors *governors = | ||
424 | cpufreq_get_available_governors(cpu); | ||
425 | if (!governors) | ||
426 | return -EINVAL; | ||
427 | |||
428 | while (governors->next) { | ||
429 | printf("%s ", governors->governor); | ||
430 | governors = governors->next; | ||
431 | } | ||
432 | printf("%s\n", governors->governor); | ||
433 | cpufreq_put_available_governors(governors); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | |||
438 | /* --affected-cpus / -a */ | ||
439 | |||
440 | static int get_affected_cpus(unsigned int cpu) | ||
441 | { | ||
442 | struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); | ||
443 | if (!cpus) | ||
444 | return -EINVAL; | ||
445 | |||
446 | while (cpus->next) { | ||
447 | printf("%d ", cpus->cpu); | ||
448 | cpus = cpus->next; | ||
449 | } | ||
450 | printf("%d\n", cpus->cpu); | ||
451 | cpufreq_put_affected_cpus(cpus); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /* --related-cpus / -r */ | ||
456 | |||
457 | static int get_related_cpus(unsigned int cpu) | ||
458 | { | ||
459 | struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); | ||
460 | if (!cpus) | ||
461 | return -EINVAL; | ||
462 | |||
463 | while (cpus->next) { | ||
464 | printf("%d ", cpus->cpu); | ||
465 | cpus = cpus->next; | ||
466 | } | ||
467 | printf("%d\n", cpus->cpu); | ||
468 | cpufreq_put_related_cpus(cpus); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | /* --stats / -s */ | ||
473 | |||
474 | static int get_freq_stats(unsigned int cpu, unsigned int human) | ||
475 | { | ||
476 | unsigned long total_trans = cpufreq_get_transitions(cpu); | ||
477 | unsigned long long total_time; | ||
478 | struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); | ||
479 | while (stats) { | ||
480 | if (human) { | ||
481 | print_speed(stats->frequency); | ||
482 | printf(":%.2f%%", | ||
483 | (100.0 * stats->time_in_state) / total_time); | ||
484 | } else | ||
485 | printf("%lu:%llu", | ||
486 | stats->frequency, stats->time_in_state); | ||
487 | stats = stats->next; | ||
488 | if (stats) | ||
489 | printf(", "); | ||
490 | } | ||
491 | cpufreq_put_stats(stats); | ||
492 | if (total_trans) | ||
493 | printf(" (%lu)\n", total_trans); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /* --latency / -y */ | ||
498 | |||
499 | static int get_latency(unsigned int cpu, unsigned int human) | ||
500 | { | ||
501 | unsigned long latency = cpufreq_get_transition_latency(cpu); | ||
502 | if (!latency) | ||
503 | return -EINVAL; | ||
504 | |||
505 | if (human) { | ||
506 | print_duration(latency); | ||
507 | printf("\n"); | ||
508 | } else | ||
509 | printf("%lu\n", latency); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static struct option info_opts[] = { | ||
514 | { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, | ||
515 | { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, | ||
516 | { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'}, | ||
517 | { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'}, | ||
518 | { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'}, | ||
519 | { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'}, | ||
520 | { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'}, | ||
521 | { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'}, | ||
522 | { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'}, | ||
523 | { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'}, | ||
524 | { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'}, | ||
525 | { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, | ||
526 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | ||
527 | { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, | ||
528 | { }, | ||
529 | }; | ||
530 | |||
531 | int cmd_freq_info(int argc, char **argv) | ||
532 | { | ||
533 | extern char *optarg; | ||
534 | extern int optind, opterr, optopt; | ||
535 | int ret = 0, cont = 1; | ||
536 | unsigned int cpu = 0; | ||
537 | unsigned int human = 0; | ||
538 | int output_param = 0; | ||
539 | |||
540 | do { | ||
541 | ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); | ||
542 | switch (ret) { | ||
543 | case '?': | ||
544 | output_param = '?'; | ||
545 | cont = 0; | ||
546 | break; | ||
547 | case -1: | ||
548 | cont = 0; | ||
549 | break; | ||
550 | case 'b': | ||
551 | case 'o': | ||
552 | case 'a': | ||
553 | case 'r': | ||
554 | case 'g': | ||
555 | case 'p': | ||
556 | case 'd': | ||
557 | case 'l': | ||
558 | case 'w': | ||
559 | case 'f': | ||
560 | case 'e': | ||
561 | case 's': | ||
562 | case 'y': | ||
563 | if (output_param) { | ||
564 | output_param = -1; | ||
565 | cont = 0; | ||
566 | break; | ||
567 | } | ||
568 | output_param = ret; | ||
569 | break; | ||
570 | case 'm': | ||
571 | if (human) { | ||
572 | output_param = -1; | ||
573 | cont = 0; | ||
574 | break; | ||
575 | } | ||
576 | human = 1; | ||
577 | break; | ||
578 | default: | ||
579 | fprintf(stderr, "invalid or unknown argument\n"); | ||
580 | return EXIT_FAILURE; | ||
581 | } | ||
582 | } while (cont); | ||
583 | |||
584 | switch (output_param) { | ||
585 | case 'o': | ||
586 | if (!bitmask_isallclear(cpus_chosen)) { | ||
587 | printf(_("The argument passed to this tool can't be " | ||
588 | "combined with passing a --cpu argument\n")); | ||
589 | return -EINVAL; | ||
590 | } | ||
591 | break; | ||
592 | case 0: | ||
593 | output_param = 'e'; | ||
594 | } | ||
595 | |||
596 | ret = 0; | ||
597 | |||
598 | /* Default is: show output of CPU 0 only */ | ||
599 | if (bitmask_isallclear(cpus_chosen)) | ||
600 | bitmask_setbit(cpus_chosen, 0); | ||
601 | |||
602 | switch (output_param) { | ||
603 | case -1: | ||
604 | printf(_("You can't specify more than one --cpu parameter and/or\n" | ||
605 | "more than one output-specific argument\n")); | ||
606 | return -EINVAL; | ||
607 | case '?': | ||
608 | printf(_("invalid or unknown argument\n")); | ||
609 | return -EINVAL; | ||
610 | case 'o': | ||
611 | proc_cpufreq_output(); | ||
612 | return EXIT_SUCCESS; | ||
613 | } | ||
614 | |||
615 | for (cpu = bitmask_first(cpus_chosen); | ||
616 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
617 | |||
618 | if (!bitmask_isbitset(cpus_chosen, cpu)) | ||
619 | continue; | ||
620 | if (cpufreq_cpu_exists(cpu)) { | ||
621 | printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); | ||
622 | continue; | ||
623 | } | ||
624 | printf(_("analyzing CPU %d:\n"), cpu); | ||
625 | |||
626 | switch (output_param) { | ||
627 | case 'b': | ||
628 | get_boost_mode(cpu); | ||
629 | break; | ||
630 | case 'e': | ||
631 | debug_output_one(cpu); | ||
632 | break; | ||
633 | case 'a': | ||
634 | ret = get_affected_cpus(cpu); | ||
635 | break; | ||
636 | case 'r': | ||
637 | ret = get_related_cpus(cpu); | ||
638 | break; | ||
639 | case 'g': | ||
640 | ret = get_available_governors(cpu); | ||
641 | break; | ||
642 | case 'p': | ||
643 | ret = get_policy(cpu); | ||
644 | break; | ||
645 | case 'd': | ||
646 | ret = get_driver(cpu); | ||
647 | break; | ||
648 | case 'l': | ||
649 | ret = get_hardware_limits(cpu); | ||
650 | break; | ||
651 | case 'w': | ||
652 | ret = get_freq_hardware(cpu, human); | ||
653 | break; | ||
654 | case 'f': | ||
655 | ret = get_freq_kernel(cpu, human); | ||
656 | break; | ||
657 | case 's': | ||
658 | ret = get_freq_stats(cpu, human); | ||
659 | break; | ||
660 | case 'y': | ||
661 | ret = get_latency(cpu, human); | ||
662 | break; | ||
663 | } | ||
664 | if (ret) | ||
665 | return ret; | ||
666 | } | ||
667 | return ret; | ||
668 | } | ||
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c new file mode 100644 index 000000000000..dd1539eb8c63 --- /dev/null +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <unistd.h> | ||
9 | #include <stdio.h> | ||
10 | #include <errno.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <limits.h> | ||
13 | #include <string.h> | ||
14 | #include <ctype.h> | ||
15 | |||
16 | #include <getopt.h> | ||
17 | |||
18 | #include "cpufreq.h" | ||
19 | #include "helpers/helpers.h" | ||
20 | |||
21 | #define NORM_FREQ_LEN 32 | ||
22 | |||
23 | static struct option set_opts[] = { | ||
24 | { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, | ||
25 | { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, | ||
26 | { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, | ||
27 | { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, | ||
28 | { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, | ||
29 | { }, | ||
30 | }; | ||
31 | |||
32 | static void print_error(void) | ||
33 | { | ||
34 | printf(_("Error setting new values. Common errors:\n" | ||
35 | "- Do you have proper administration rights? (super-user?)\n" | ||
36 | "- Is the governor you requested available and modprobed?\n" | ||
37 | "- Trying to set an invalid policy?\n" | ||
38 | "- Trying to set a specific frequency, but userspace governor is not available,\n" | ||
39 | " for example because of hardware which cannot be set to a specific frequency\n" | ||
40 | " or because the userspace governor isn't loaded?\n")); | ||
41 | }; | ||
42 | |||
43 | struct freq_units { | ||
44 | char *str_unit; | ||
45 | int power_of_ten; | ||
46 | }; | ||
47 | |||
48 | const struct freq_units def_units[] = { | ||
49 | {"hz", -3}, | ||
50 | {"khz", 0}, /* default */ | ||
51 | {"mhz", 3}, | ||
52 | {"ghz", 6}, | ||
53 | {"thz", 9}, | ||
54 | {NULL, 0} | ||
55 | }; | ||
56 | |||
57 | static void print_unknown_arg(void) | ||
58 | { | ||
59 | printf(_("invalid or unknown argument\n")); | ||
60 | } | ||
61 | |||
62 | static unsigned long string_to_frequency(const char *str) | ||
63 | { | ||
64 | char normalized[NORM_FREQ_LEN]; | ||
65 | const struct freq_units *unit; | ||
66 | const char *scan; | ||
67 | char *end; | ||
68 | unsigned long freq; | ||
69 | int power = 0, match_count = 0, i, cp, pad; | ||
70 | |||
71 | while (*str == '0') | ||
72 | str++; | ||
73 | |||
74 | for (scan = str; isdigit(*scan) || *scan == '.'; scan++) { | ||
75 | if (*scan == '.' && match_count == 0) | ||
76 | match_count = 1; | ||
77 | else if (*scan == '.' && match_count == 1) | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | if (*scan) { | ||
82 | match_count = 0; | ||
83 | for (unit = def_units; unit->str_unit; unit++) { | ||
84 | for (i = 0; | ||
85 | scan[i] && tolower(scan[i]) == unit->str_unit[i]; | ||
86 | ++i) | ||
87 | continue; | ||
88 | if (scan[i]) | ||
89 | continue; | ||
90 | match_count++; | ||
91 | power = unit->power_of_ten; | ||
92 | } | ||
93 | if (match_count != 1) | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* count the number of digits to be copied */ | ||
98 | for (cp = 0; isdigit(str[cp]); cp++) | ||
99 | continue; | ||
100 | |||
101 | if (str[cp] == '.') { | ||
102 | while (power > -1 && isdigit(str[cp+1])) | ||
103 | cp++, power--; | ||
104 | } | ||
105 | if (power >= -1) /* not enough => pad */ | ||
106 | pad = power + 1; | ||
107 | else /* to much => strip */ | ||
108 | pad = 0, cp += power + 1; | ||
109 | /* check bounds */ | ||
110 | if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1) | ||
111 | return 0; | ||
112 | |||
113 | /* copy digits */ | ||
114 | for (i = 0; i < cp; i++, str++) { | ||
115 | if (*str == '.') | ||
116 | str++; | ||
117 | normalized[i] = *str; | ||
118 | } | ||
119 | /* and pad */ | ||
120 | for (; i < cp + pad; i++) | ||
121 | normalized[i] = '0'; | ||
122 | |||
123 | /* round up, down ? */ | ||
124 | match_count = (normalized[i-1] >= '5'); | ||
125 | /* and drop the decimal part */ | ||
126 | normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */ | ||
127 | |||
128 | /* final conversion (and applying rounding) */ | ||
129 | errno = 0; | ||
130 | freq = strtoul(normalized, &end, 10); | ||
131 | if (errno) | ||
132 | return 0; | ||
133 | else { | ||
134 | if (match_count && freq != ULONG_MAX) | ||
135 | freq++; | ||
136 | return freq; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol) | ||
141 | { | ||
142 | struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu); | ||
143 | int ret; | ||
144 | |||
145 | if (!cur_pol) { | ||
146 | printf(_("wrong, unknown or unhandled CPU?\n")); | ||
147 | return -EINVAL; | ||
148 | } | ||
149 | |||
150 | if (!new_pol->min) | ||
151 | new_pol->min = cur_pol->min; | ||
152 | |||
153 | if (!new_pol->max) | ||
154 | new_pol->max = cur_pol->max; | ||
155 | |||
156 | if (!new_pol->governor) | ||
157 | new_pol->governor = cur_pol->governor; | ||
158 | |||
159 | ret = cpufreq_set_policy(cpu, new_pol); | ||
160 | |||
161 | cpufreq_put_policy(cur_pol); | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | |||
167 | static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol, | ||
168 | unsigned long freq, unsigned int pc) | ||
169 | { | ||
170 | switch (pc) { | ||
171 | case 0: | ||
172 | return cpufreq_set_frequency(cpu, freq); | ||
173 | |||
174 | case 1: | ||
175 | /* if only one value of a policy is to be changed, we can | ||
176 | * use a "fast path". | ||
177 | */ | ||
178 | if (new_pol->min) | ||
179 | return cpufreq_modify_policy_min(cpu, new_pol->min); | ||
180 | else if (new_pol->max) | ||
181 | return cpufreq_modify_policy_max(cpu, new_pol->max); | ||
182 | else if (new_pol->governor) | ||
183 | return cpufreq_modify_policy_governor(cpu, | ||
184 | new_pol->governor); | ||
185 | |||
186 | default: | ||
187 | /* slow path */ | ||
188 | return do_new_policy(cpu, new_pol); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | int cmd_freq_set(int argc, char **argv) | ||
193 | { | ||
194 | extern char *optarg; | ||
195 | extern int optind, opterr, optopt; | ||
196 | int ret = 0, cont = 1; | ||
197 | int double_parm = 0, related = 0, policychange = 0; | ||
198 | unsigned long freq = 0; | ||
199 | char gov[20]; | ||
200 | unsigned int cpu; | ||
201 | |||
202 | struct cpufreq_policy new_pol = { | ||
203 | .min = 0, | ||
204 | .max = 0, | ||
205 | .governor = NULL, | ||
206 | }; | ||
207 | |||
208 | /* parameter parsing */ | ||
209 | do { | ||
210 | ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL); | ||
211 | switch (ret) { | ||
212 | case '?': | ||
213 | print_unknown_arg(); | ||
214 | return -EINVAL; | ||
215 | case -1: | ||
216 | cont = 0; | ||
217 | break; | ||
218 | case 'r': | ||
219 | if (related) | ||
220 | double_parm++; | ||
221 | related++; | ||
222 | break; | ||
223 | case 'd': | ||
224 | if (new_pol.min) | ||
225 | double_parm++; | ||
226 | policychange++; | ||
227 | new_pol.min = string_to_frequency(optarg); | ||
228 | if (new_pol.min == 0) { | ||
229 | print_unknown_arg(); | ||
230 | return -EINVAL; | ||
231 | } | ||
232 | break; | ||
233 | case 'u': | ||
234 | if (new_pol.max) | ||
235 | double_parm++; | ||
236 | policychange++; | ||
237 | new_pol.max = string_to_frequency(optarg); | ||
238 | if (new_pol.max == 0) { | ||
239 | print_unknown_arg(); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | break; | ||
243 | case 'f': | ||
244 | if (freq) | ||
245 | double_parm++; | ||
246 | freq = string_to_frequency(optarg); | ||
247 | if (freq == 0) { | ||
248 | print_unknown_arg(); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | break; | ||
252 | case 'g': | ||
253 | if (new_pol.governor) | ||
254 | double_parm++; | ||
255 | policychange++; | ||
256 | if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) { | ||
257 | print_unknown_arg(); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | if ((sscanf(optarg, "%s", gov)) != 1) { | ||
261 | print_unknown_arg(); | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | new_pol.governor = gov; | ||
265 | break; | ||
266 | } | ||
267 | } while (cont); | ||
268 | |||
269 | /* parameter checking */ | ||
270 | if (double_parm) { | ||
271 | printf("the same parameter was passed more than once\n"); | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
275 | if (freq && policychange) { | ||
276 | printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" | ||
277 | "-g/--governor parameters\n")); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | if (!freq && !policychange) { | ||
282 | printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" | ||
283 | "-g/--governor must be passed\n")); | ||
284 | return -EINVAL; | ||
285 | } | ||
286 | |||
287 | /* Default is: set all CPUs */ | ||
288 | if (bitmask_isallclear(cpus_chosen)) | ||
289 | bitmask_setall(cpus_chosen); | ||
290 | |||
291 | /* Also set frequency settings for related CPUs if -r is passed */ | ||
292 | if (related) { | ||
293 | for (cpu = bitmask_first(cpus_chosen); | ||
294 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
295 | struct cpufreq_affected_cpus *cpus; | ||
296 | |||
297 | if (!bitmask_isbitset(cpus_chosen, cpu) || | ||
298 | cpufreq_cpu_exists(cpu)) | ||
299 | continue; | ||
300 | |||
301 | cpus = cpufreq_get_related_cpus(cpu); | ||
302 | if (!cpus) | ||
303 | break; | ||
304 | while (cpus->next) { | ||
305 | bitmask_setbit(cpus_chosen, cpus->cpu); | ||
306 | cpus = cpus->next; | ||
307 | } | ||
308 | cpufreq_put_related_cpus(cpus); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | |||
313 | /* loop over CPUs */ | ||
314 | for (cpu = bitmask_first(cpus_chosen); | ||
315 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
316 | |||
317 | if (!bitmask_isbitset(cpus_chosen, cpu) || | ||
318 | cpufreq_cpu_exists(cpu)) | ||
319 | continue; | ||
320 | |||
321 | printf(_("Setting cpu: %d\n"), cpu); | ||
322 | ret = do_one_cpu(cpu, &new_pol, freq, policychange); | ||
323 | if (ret) | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | if (ret) | ||
328 | print_error(); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c new file mode 100644 index 000000000000..b028267c1376 --- /dev/null +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * (C) 2010 Thomas Renninger <trenn@suse.de> | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | */ | ||
7 | |||
8 | |||
9 | #include <unistd.h> | ||
10 | #include <stdio.h> | ||
11 | #include <errno.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | #include <getopt.h> | ||
15 | #include <cpufreq.h> | ||
16 | |||
17 | #include "helpers/helpers.h" | ||
18 | #include "helpers/sysfs.h" | ||
19 | #include "helpers/bitmask.h" | ||
20 | |||
21 | #define LINE_LEN 10 | ||
22 | |||
23 | static void cpuidle_cpu_output(unsigned int cpu, int verbose) | ||
24 | { | ||
25 | int idlestates, idlestate; | ||
26 | char *tmp; | ||
27 | |||
28 | printf(_ ("Analyzing CPU %d:\n"), cpu); | ||
29 | |||
30 | idlestates = sysfs_get_idlestate_count(cpu); | ||
31 | if (idlestates == 0) { | ||
32 | printf(_("CPU %u: No idle states\n"), cpu); | ||
33 | return; | ||
34 | } else if (idlestates <= 0) { | ||
35 | printf(_("CPU %u: Can't read idle state info\n"), cpu); | ||
36 | return; | ||
37 | } | ||
38 | tmp = sysfs_get_idlestate_name(cpu, idlestates - 1); | ||
39 | if (!tmp) { | ||
40 | printf(_("Could not determine max idle state %u\n"), | ||
41 | idlestates - 1); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | printf(_("Number of idle states: %d\n"), idlestates); | ||
46 | |||
47 | printf(_("Available idle states:")); | ||
48 | for (idlestate = 1; idlestate < idlestates; idlestate++) { | ||
49 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | ||
50 | if (!tmp) | ||
51 | continue; | ||
52 | printf(" %s", tmp); | ||
53 | free(tmp); | ||
54 | } | ||
55 | printf("\n"); | ||
56 | |||
57 | if (!verbose) | ||
58 | return; | ||
59 | |||
60 | for (idlestate = 1; idlestate < idlestates; idlestate++) { | ||
61 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | ||
62 | if (!tmp) | ||
63 | continue; | ||
64 | printf("%s:\n", tmp); | ||
65 | free(tmp); | ||
66 | |||
67 | tmp = sysfs_get_idlestate_desc(cpu, idlestate); | ||
68 | if (!tmp) | ||
69 | continue; | ||
70 | printf(_("Flags/Description: %s\n"), tmp); | ||
71 | free(tmp); | ||
72 | |||
73 | printf(_("Latency: %lu\n"), | ||
74 | sysfs_get_idlestate_latency(cpu, idlestate)); | ||
75 | printf(_("Usage: %lu\n"), | ||
76 | sysfs_get_idlestate_usage(cpu, idlestate)); | ||
77 | printf(_("Duration: %llu\n"), | ||
78 | sysfs_get_idlestate_time(cpu, idlestate)); | ||
79 | } | ||
80 | printf("\n"); | ||
81 | } | ||
82 | |||
83 | static void cpuidle_general_output(void) | ||
84 | { | ||
85 | char *tmp; | ||
86 | |||
87 | tmp = sysfs_get_cpuidle_driver(); | ||
88 | if (!tmp) { | ||
89 | printf(_("Could not determine cpuidle driver\n")); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | printf(_("CPUidle driver: %s\n"), tmp); | ||
94 | free(tmp); | ||
95 | |||
96 | tmp = sysfs_get_cpuidle_governor(); | ||
97 | if (!tmp) { | ||
98 | printf(_("Could not determine cpuidle governor\n")); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | printf(_("CPUidle governor: %s\n"), tmp); | ||
103 | free(tmp); | ||
104 | } | ||
105 | |||
106 | static void proc_cpuidle_cpu_output(unsigned int cpu) | ||
107 | { | ||
108 | long max_allowed_cstate = 2000000000; | ||
109 | int cstates, cstate; | ||
110 | |||
111 | cstates = sysfs_get_idlestate_count(cpu); | ||
112 | if (cstates == 0) { | ||
113 | /* | ||
114 | * Go on and print same useless info as you'd see with | ||
115 | * cat /proc/acpi/processor/../power | ||
116 | * printf(_("CPU %u: No C-states available\n"), cpu); | ||
117 | * return; | ||
118 | */ | ||
119 | } else if (cstates <= 0) { | ||
120 | printf(_("CPU %u: Can't read C-state info\n"), cpu); | ||
121 | return; | ||
122 | } | ||
123 | /* printf("Cstates: %d\n", cstates); */ | ||
124 | |||
125 | printf(_("active state: C0\n")); | ||
126 | printf(_("max_cstate: C%u\n"), cstates-1); | ||
127 | printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); | ||
128 | printf(_("states:\t\n")); | ||
129 | for (cstate = 1; cstate < cstates; cstate++) { | ||
130 | printf(_(" C%d: " | ||
131 | "type[C%d] "), cstate, cstate); | ||
132 | printf(_("promotion[--] demotion[--] ")); | ||
133 | printf(_("latency[%03lu] "), | ||
134 | sysfs_get_idlestate_latency(cpu, cstate)); | ||
135 | printf(_("usage[%08lu] "), | ||
136 | sysfs_get_idlestate_usage(cpu, cstate)); | ||
137 | printf(_("duration[%020Lu] \n"), | ||
138 | sysfs_get_idlestate_time(cpu, cstate)); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static struct option info_opts[] = { | ||
143 | { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, | ||
144 | { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, | ||
145 | { }, | ||
146 | }; | ||
147 | |||
148 | static inline void cpuidle_exit(int fail) | ||
149 | { | ||
150 | exit(EXIT_FAILURE); | ||
151 | } | ||
152 | |||
153 | int cmd_idle_info(int argc, char **argv) | ||
154 | { | ||
155 | extern char *optarg; | ||
156 | extern int optind, opterr, optopt; | ||
157 | int ret = 0, cont = 1, output_param = 0, verbose = 1; | ||
158 | unsigned int cpu = 0; | ||
159 | |||
160 | do { | ||
161 | ret = getopt_long(argc, argv, "os", info_opts, NULL); | ||
162 | if (ret == -1) | ||
163 | break; | ||
164 | switch (ret) { | ||
165 | case '?': | ||
166 | output_param = '?'; | ||
167 | cont = 0; | ||
168 | break; | ||
169 | case 's': | ||
170 | verbose = 0; | ||
171 | break; | ||
172 | case -1: | ||
173 | cont = 0; | ||
174 | break; | ||
175 | case 'o': | ||
176 | if (output_param) { | ||
177 | output_param = -1; | ||
178 | cont = 0; | ||
179 | break; | ||
180 | } | ||
181 | output_param = ret; | ||
182 | break; | ||
183 | } | ||
184 | } while (cont); | ||
185 | |||
186 | switch (output_param) { | ||
187 | case -1: | ||
188 | printf(_("You can't specify more than one " | ||
189 | "output-specific argument\n")); | ||
190 | cpuidle_exit(EXIT_FAILURE); | ||
191 | case '?': | ||
192 | printf(_("invalid or unknown argument\n")); | ||
193 | cpuidle_exit(EXIT_FAILURE); | ||
194 | } | ||
195 | |||
196 | /* Default is: show output of CPU 0 only */ | ||
197 | if (bitmask_isallclear(cpus_chosen)) | ||
198 | bitmask_setbit(cpus_chosen, 0); | ||
199 | |||
200 | if (output_param == 0) | ||
201 | cpuidle_general_output(); | ||
202 | |||
203 | for (cpu = bitmask_first(cpus_chosen); | ||
204 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
205 | |||
206 | if (!bitmask_isbitset(cpus_chosen, cpu) || | ||
207 | cpufreq_cpu_exists(cpu)) | ||
208 | continue; | ||
209 | |||
210 | switch (output_param) { | ||
211 | |||
212 | case 'o': | ||
213 | proc_cpuidle_cpu_output(cpu); | ||
214 | break; | ||
215 | case 0: | ||
216 | printf("\n"); | ||
217 | cpuidle_cpu_output(cpu, verbose); | ||
218 | break; | ||
219 | } | ||
220 | } | ||
221 | return EXIT_SUCCESS; | ||
222 | } | ||
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c new file mode 100644 index 000000000000..3f68632c28c7 --- /dev/null +++ b/tools/power/cpupower/utils/cpupower-info.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <unistd.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <errno.h> | ||
12 | #include <string.h> | ||
13 | #include <getopt.h> | ||
14 | |||
15 | #include <cpufreq.h> | ||
16 | #include "helpers/helpers.h" | ||
17 | #include "helpers/sysfs.h" | ||
18 | |||
19 | static struct option set_opts[] = { | ||
20 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | ||
21 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | ||
22 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | ||
23 | { }, | ||
24 | }; | ||
25 | |||
26 | static void print_wrong_arg_exit(void) | ||
27 | { | ||
28 | printf(_("invalid or unknown argument\n")); | ||
29 | exit(EXIT_FAILURE); | ||
30 | } | ||
31 | |||
32 | int cmd_info(int argc, char **argv) | ||
33 | { | ||
34 | extern char *optarg; | ||
35 | extern int optind, opterr, optopt; | ||
36 | unsigned int cpu; | ||
37 | |||
38 | union { | ||
39 | struct { | ||
40 | int sched_mc:1; | ||
41 | int sched_smt:1; | ||
42 | int perf_bias:1; | ||
43 | }; | ||
44 | int params; | ||
45 | } params = {}; | ||
46 | int ret = 0; | ||
47 | |||
48 | setlocale(LC_ALL, ""); | ||
49 | textdomain(PACKAGE); | ||
50 | |||
51 | /* parameter parsing */ | ||
52 | while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) { | ||
53 | switch (ret) { | ||
54 | case 'b': | ||
55 | if (params.perf_bias) | ||
56 | print_wrong_arg_exit(); | ||
57 | params.perf_bias = 1; | ||
58 | break; | ||
59 | case 'm': | ||
60 | if (params.sched_mc) | ||
61 | print_wrong_arg_exit(); | ||
62 | params.sched_mc = 1; | ||
63 | break; | ||
64 | case 's': | ||
65 | if (params.sched_smt) | ||
66 | print_wrong_arg_exit(); | ||
67 | params.sched_smt = 1; | ||
68 | break; | ||
69 | default: | ||
70 | print_wrong_arg_exit(); | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | if (!params.params) | ||
75 | params.params = 0x7; | ||
76 | |||
77 | /* Default is: show output of CPU 0 only */ | ||
78 | if (bitmask_isallclear(cpus_chosen)) | ||
79 | bitmask_setbit(cpus_chosen, 0); | ||
80 | |||
81 | if (params.sched_mc) { | ||
82 | ret = sysfs_get_sched("mc"); | ||
83 | printf(_("System's multi core scheduler setting: ")); | ||
84 | if (ret < 0) | ||
85 | /* if sysfs file is missing it's: errno == ENOENT */ | ||
86 | printf(_("not supported\n")); | ||
87 | else | ||
88 | printf("%d\n", ret); | ||
89 | } | ||
90 | if (params.sched_smt) { | ||
91 | ret = sysfs_get_sched("smt"); | ||
92 | printf(_("System's thread sibling scheduler setting: ")); | ||
93 | if (ret < 0) | ||
94 | /* if sysfs file is missing it's: errno == ENOENT */ | ||
95 | printf(_("not supported\n")); | ||
96 | else | ||
97 | printf("%d\n", ret); | ||
98 | } | ||
99 | |||
100 | /* Add more per cpu options here */ | ||
101 | if (!params.perf_bias) | ||
102 | return ret; | ||
103 | |||
104 | if (params.perf_bias) { | ||
105 | if (!run_as_root) { | ||
106 | params.perf_bias = 0; | ||
107 | printf(_("Intel's performance bias setting needs root privileges\n")); | ||
108 | } else if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) { | ||
109 | printf(_("System does not support Intel's performance" | ||
110 | " bias setting\n")); | ||
111 | params.perf_bias = 0; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* loop over CPUs */ | ||
116 | for (cpu = bitmask_first(cpus_chosen); | ||
117 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
118 | |||
119 | if (!bitmask_isbitset(cpus_chosen, cpu) || | ||
120 | cpufreq_cpu_exists(cpu)) | ||
121 | continue; | ||
122 | |||
123 | printf(_("analyzing CPU %d:\n"), cpu); | ||
124 | |||
125 | if (params.perf_bias) { | ||
126 | ret = msr_intel_get_perf_bias(cpu); | ||
127 | if (ret < 0) { | ||
128 | printf(_("Could not read perf-bias value\n")); | ||
129 | break; | ||
130 | } else | ||
131 | printf(_("perf-bias: %d\n"), ret); | ||
132 | } | ||
133 | } | ||
134 | return ret; | ||
135 | } | ||
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c new file mode 100644 index 000000000000..dc4de3762111 --- /dev/null +++ b/tools/power/cpupower/utils/cpupower-set.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <unistd.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <errno.h> | ||
12 | #include <string.h> | ||
13 | #include <getopt.h> | ||
14 | |||
15 | #include <cpufreq.h> | ||
16 | #include "helpers/helpers.h" | ||
17 | #include "helpers/sysfs.h" | ||
18 | #include "helpers/bitmask.h" | ||
19 | |||
20 | static struct option set_opts[] = { | ||
21 | { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, | ||
22 | { .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'}, | ||
23 | { .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'}, | ||
24 | { }, | ||
25 | }; | ||
26 | |||
27 | static void print_wrong_arg_exit(void) | ||
28 | { | ||
29 | printf(_("invalid or unknown argument\n")); | ||
30 | exit(EXIT_FAILURE); | ||
31 | } | ||
32 | |||
33 | int cmd_set(int argc, char **argv) | ||
34 | { | ||
35 | extern char *optarg; | ||
36 | extern int optind, opterr, optopt; | ||
37 | unsigned int cpu; | ||
38 | |||
39 | union { | ||
40 | struct { | ||
41 | int sched_mc:1; | ||
42 | int sched_smt:1; | ||
43 | int perf_bias:1; | ||
44 | }; | ||
45 | int params; | ||
46 | } params; | ||
47 | int sched_mc = 0, sched_smt = 0, perf_bias = 0; | ||
48 | int ret = 0; | ||
49 | |||
50 | setlocale(LC_ALL, ""); | ||
51 | textdomain(PACKAGE); | ||
52 | |||
53 | params.params = 0; | ||
54 | /* parameter parsing */ | ||
55 | while ((ret = getopt_long(argc, argv, "m:s:b:", | ||
56 | set_opts, NULL)) != -1) { | ||
57 | switch (ret) { | ||
58 | case 'b': | ||
59 | if (params.perf_bias) | ||
60 | print_wrong_arg_exit(); | ||
61 | perf_bias = atoi(optarg); | ||
62 | if (perf_bias < 0 || perf_bias > 15) { | ||
63 | printf(_("--perf-bias param out " | ||
64 | "of range [0-%d]\n"), 15); | ||
65 | print_wrong_arg_exit(); | ||
66 | } | ||
67 | params.perf_bias = 1; | ||
68 | break; | ||
69 | case 'm': | ||
70 | if (params.sched_mc) | ||
71 | print_wrong_arg_exit(); | ||
72 | sched_mc = atoi(optarg); | ||
73 | if (sched_mc < 0 || sched_mc > 2) { | ||
74 | printf(_("--sched-mc param out " | ||
75 | "of range [0-%d]\n"), 2); | ||
76 | print_wrong_arg_exit(); | ||
77 | } | ||
78 | params.sched_mc = 1; | ||
79 | break; | ||
80 | case 's': | ||
81 | if (params.sched_smt) | ||
82 | print_wrong_arg_exit(); | ||
83 | sched_smt = atoi(optarg); | ||
84 | if (sched_smt < 0 || sched_smt > 2) { | ||
85 | printf(_("--sched-smt param out " | ||
86 | "of range [0-%d]\n"), 2); | ||
87 | print_wrong_arg_exit(); | ||
88 | } | ||
89 | params.sched_smt = 1; | ||
90 | break; | ||
91 | default: | ||
92 | print_wrong_arg_exit(); | ||
93 | } | ||
94 | }; | ||
95 | |||
96 | if (!params.params) | ||
97 | print_wrong_arg_exit(); | ||
98 | |||
99 | if (params.sched_mc) { | ||
100 | ret = sysfs_set_sched("mc", sched_mc); | ||
101 | if (ret) | ||
102 | fprintf(stderr, _("Error setting sched-mc %s\n"), | ||
103 | (ret == -ENODEV) ? "not supported" : ""); | ||
104 | } | ||
105 | if (params.sched_smt) { | ||
106 | ret = sysfs_set_sched("smt", sched_smt); | ||
107 | if (ret) | ||
108 | fprintf(stderr, _("Error setting sched-smt %s\n"), | ||
109 | (ret == -ENODEV) ? "not supported" : ""); | ||
110 | } | ||
111 | |||
112 | /* Default is: set all CPUs */ | ||
113 | if (bitmask_isallclear(cpus_chosen)) | ||
114 | bitmask_setall(cpus_chosen); | ||
115 | |||
116 | /* loop over CPUs */ | ||
117 | for (cpu = bitmask_first(cpus_chosen); | ||
118 | cpu <= bitmask_last(cpus_chosen); cpu++) { | ||
119 | |||
120 | if (!bitmask_isbitset(cpus_chosen, cpu) || | ||
121 | cpufreq_cpu_exists(cpu)) | ||
122 | continue; | ||
123 | |||
124 | if (params.perf_bias) { | ||
125 | ret = msr_intel_set_perf_bias(cpu, perf_bias); | ||
126 | if (ret) { | ||
127 | fprintf(stderr, _("Error setting perf-bias " | ||
128 | "value on CPU %d\n"), cpu); | ||
129 | break; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | return ret; | ||
134 | } | ||
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c new file mode 100644 index 000000000000..52bee591c1c5 --- /dev/null +++ b/tools/power/cpupower/utils/cpupower.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Ideas taken over from the perf userspace tool (included in the Linus | ||
7 | * kernel git repo): subcommand builtins and param parsing. | ||
8 | */ | ||
9 | |||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | #include <unistd.h> | ||
14 | #include <errno.h> | ||
15 | |||
16 | #include "builtin.h" | ||
17 | #include "helpers/helpers.h" | ||
18 | #include "helpers/bitmask.h" | ||
19 | |||
20 | struct cmd_struct { | ||
21 | const char *cmd; | ||
22 | int (*main)(int, const char **); | ||
23 | int needs_root; | ||
24 | }; | ||
25 | |||
26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | ||
27 | |||
28 | static int cmd_help(int argc, const char **argv); | ||
29 | |||
30 | /* Global cpu_info object available for all binaries | ||
31 | * Info only retrieved from CPU 0 | ||
32 | * | ||
33 | * Values will be zero/unknown on non X86 archs | ||
34 | */ | ||
35 | struct cpupower_cpu_info cpupower_cpu_info; | ||
36 | int run_as_root; | ||
37 | /* Affected cpus chosen by -c/--cpu param */ | ||
38 | struct bitmask *cpus_chosen; | ||
39 | |||
40 | #ifdef DEBUG | ||
41 | int be_verbose; | ||
42 | #endif | ||
43 | |||
44 | static void print_help(void); | ||
45 | |||
46 | static struct cmd_struct commands[] = { | ||
47 | { "frequency-info", cmd_freq_info, 0 }, | ||
48 | { "frequency-set", cmd_freq_set, 1 }, | ||
49 | { "idle-info", cmd_idle_info, 0 }, | ||
50 | { "set", cmd_set, 1 }, | ||
51 | { "info", cmd_info, 0 }, | ||
52 | { "monitor", cmd_monitor, 0 }, | ||
53 | { "help", cmd_help, 0 }, | ||
54 | /* { "bench", cmd_bench, 1 }, */ | ||
55 | }; | ||
56 | |||
57 | static void print_help(void) | ||
58 | { | ||
59 | unsigned int i; | ||
60 | |||
61 | #ifdef DEBUG | ||
62 | printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); | ||
63 | #else | ||
64 | printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); | ||
65 | #endif | ||
66 | printf(_("Supported commands are:\n")); | ||
67 | for (i = 0; i < ARRAY_SIZE(commands); i++) | ||
68 | printf("\t%s\n", commands[i].cmd); | ||
69 | printf(_("\nNot all commands can make use of the -c cpulist option.\n")); | ||
70 | printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); | ||
71 | } | ||
72 | |||
73 | static int print_man_page(const char *subpage) | ||
74 | { | ||
75 | int len; | ||
76 | char *page; | ||
77 | |||
78 | len = 10; /* enough for "cpupower-" */ | ||
79 | if (subpage != NULL) | ||
80 | len += strlen(subpage); | ||
81 | |||
82 | page = malloc(len); | ||
83 | if (!page) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | sprintf(page, "cpupower"); | ||
87 | if ((subpage != NULL) && strcmp(subpage, "help")) { | ||
88 | strcat(page, "-"); | ||
89 | strcat(page, subpage); | ||
90 | } | ||
91 | |||
92 | execlp("man", "man", page, NULL); | ||
93 | |||
94 | /* should not be reached */ | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | |||
98 | static int cmd_help(int argc, const char **argv) | ||
99 | { | ||
100 | if (argc > 1) { | ||
101 | print_man_page(argv[1]); /* exits within execlp() */ | ||
102 | return EXIT_FAILURE; | ||
103 | } | ||
104 | |||
105 | print_help(); | ||
106 | return EXIT_SUCCESS; | ||
107 | } | ||
108 | |||
109 | static void print_version(void) | ||
110 | { | ||
111 | printf(PACKAGE " " VERSION "\n"); | ||
112 | printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT); | ||
113 | } | ||
114 | |||
115 | static void handle_options(int *argc, const char ***argv) | ||
116 | { | ||
117 | int ret, x, new_argc = 0; | ||
118 | |||
119 | if (*argc < 1) | ||
120 | return; | ||
121 | |||
122 | for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) { | ||
123 | const char *param = (*argv)[x]; | ||
124 | if (!strcmp(param, "-h") || !strcmp(param, "--help")) { | ||
125 | print_help(); | ||
126 | exit(EXIT_SUCCESS); | ||
127 | } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { | ||
128 | if (*argc < 2) { | ||
129 | print_help(); | ||
130 | exit(EXIT_FAILURE); | ||
131 | } | ||
132 | if (!strcmp((*argv)[x+1], "all")) | ||
133 | bitmask_setall(cpus_chosen); | ||
134 | else { | ||
135 | ret = bitmask_parselist( | ||
136 | (*argv)[x+1], cpus_chosen); | ||
137 | if (ret < 0) { | ||
138 | fprintf(stderr, _("Error parsing cpu " | ||
139 | "list\n")); | ||
140 | exit(EXIT_FAILURE); | ||
141 | } | ||
142 | } | ||
143 | x += 1; | ||
144 | /* Cut out param: cpupower -c 1 info -> cpupower info */ | ||
145 | new_argc += 2; | ||
146 | continue; | ||
147 | } else if (!strcmp(param, "-v") || | ||
148 | !strcmp(param, "--version")) { | ||
149 | print_version(); | ||
150 | exit(EXIT_SUCCESS); | ||
151 | #ifdef DEBUG | ||
152 | } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { | ||
153 | be_verbose = 1; | ||
154 | new_argc++; | ||
155 | continue; | ||
156 | #endif | ||
157 | } else { | ||
158 | fprintf(stderr, "Unknown option: %s\n", param); | ||
159 | print_help(); | ||
160 | exit(EXIT_FAILURE); | ||
161 | } | ||
162 | } | ||
163 | *argc -= new_argc; | ||
164 | *argv += new_argc; | ||
165 | } | ||
166 | |||
167 | int main(int argc, const char *argv[]) | ||
168 | { | ||
169 | const char *cmd; | ||
170 | unsigned int i, ret; | ||
171 | |||
172 | cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); | ||
173 | |||
174 | argc--; | ||
175 | argv += 1; | ||
176 | |||
177 | handle_options(&argc, &argv); | ||
178 | |||
179 | cmd = argv[0]; | ||
180 | |||
181 | if (argc < 1) { | ||
182 | print_help(); | ||
183 | return EXIT_FAILURE; | ||
184 | } | ||
185 | |||
186 | setlocale(LC_ALL, ""); | ||
187 | textdomain(PACKAGE); | ||
188 | |||
189 | /* Turn "perf cmd --help" into "perf help cmd" */ | ||
190 | if (argc > 1 && !strcmp(argv[1], "--help")) { | ||
191 | argv[1] = argv[0]; | ||
192 | argv[0] = cmd = "help"; | ||
193 | } | ||
194 | |||
195 | get_cpu_info(0, &cpupower_cpu_info); | ||
196 | run_as_root = !getuid(); | ||
197 | |||
198 | for (i = 0; i < ARRAY_SIZE(commands); i++) { | ||
199 | struct cmd_struct *p = commands + i; | ||
200 | if (strcmp(p->cmd, cmd)) | ||
201 | continue; | ||
202 | if (!run_as_root && p->needs_root) { | ||
203 | fprintf(stderr, _("Subcommand %s needs root " | ||
204 | "privileges\n"), cmd); | ||
205 | return EXIT_FAILURE; | ||
206 | } | ||
207 | ret = p->main(argc, argv); | ||
208 | if (cpus_chosen) | ||
209 | bitmask_free(cpus_chosen); | ||
210 | return ret; | ||
211 | } | ||
212 | print_help(); | ||
213 | return EXIT_FAILURE; | ||
214 | } | ||
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c new file mode 100644 index 000000000000..87d5605bdda8 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/amd.c | |||
@@ -0,0 +1,137 @@ | |||
1 | #if defined(__i386__) || defined(__x86_64__) | ||
2 | #include <unistd.h> | ||
3 | #include <errno.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdint.h> | ||
6 | |||
7 | #include <pci/pci.h> | ||
8 | |||
9 | #include "helpers/helpers.h" | ||
10 | |||
11 | #define MSR_AMD_PSTATE_STATUS 0xc0010063 | ||
12 | #define MSR_AMD_PSTATE 0xc0010064 | ||
13 | #define MSR_AMD_PSTATE_LIMIT 0xc0010061 | ||
14 | |||
15 | union msr_pstate { | ||
16 | struct { | ||
17 | unsigned fid:6; | ||
18 | unsigned did:3; | ||
19 | unsigned vid:7; | ||
20 | unsigned res1:6; | ||
21 | unsigned nbdid:1; | ||
22 | unsigned res2:2; | ||
23 | unsigned nbvid:7; | ||
24 | unsigned iddval:8; | ||
25 | unsigned idddiv:2; | ||
26 | unsigned res3:21; | ||
27 | unsigned en:1; | ||
28 | } bits; | ||
29 | unsigned long long val; | ||
30 | }; | ||
31 | |||
32 | static int get_did(int family, union msr_pstate pstate) | ||
33 | { | ||
34 | int t; | ||
35 | |||
36 | if (family == 0x12) | ||
37 | t = pstate.val & 0xf; | ||
38 | else | ||
39 | t = pstate.bits.did; | ||
40 | |||
41 | return t; | ||
42 | } | ||
43 | |||
44 | static int get_cof(int family, union msr_pstate pstate) | ||
45 | { | ||
46 | int t; | ||
47 | int fid, did; | ||
48 | |||
49 | did = get_did(family, pstate); | ||
50 | |||
51 | t = 0x10; | ||
52 | fid = pstate.bits.fid; | ||
53 | if (family == 0x11) | ||
54 | t = 0x8; | ||
55 | |||
56 | return (100 * (fid + t)) >> did; | ||
57 | } | ||
58 | |||
59 | /* Needs: | ||
60 | * cpu -> the cpu that gets evaluated | ||
61 | * cpu_family -> The cpu's family (0x10, 0x12,...) | ||
62 | * boots_states -> how much boost states the machines support | ||
63 | * | ||
64 | * Fills up: | ||
65 | * pstates -> a pointer to an array of size MAX_HW_PSTATES | ||
66 | * must be initialized with zeros. | ||
67 | * All available HW pstates (including boost states) | ||
68 | * no -> amount of pstates above array got filled up with | ||
69 | * | ||
70 | * returns zero on success, -1 on failure | ||
71 | */ | ||
72 | int decode_pstates(unsigned int cpu, unsigned int cpu_family, | ||
73 | int boost_states, unsigned long *pstates, int *no) | ||
74 | { | ||
75 | int i, psmax, pscur; | ||
76 | union msr_pstate pstate; | ||
77 | unsigned long long val; | ||
78 | |||
79 | /* Only read out frequencies from HW when CPU might be boostable | ||
80 | to keep the code as short and clean as possible. | ||
81 | Otherwise frequencies are exported via ACPI tables. | ||
82 | */ | ||
83 | if (cpu_family < 0x10 || cpu_family == 0x14) | ||
84 | return -1; | ||
85 | |||
86 | if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val)) | ||
87 | return -1; | ||
88 | |||
89 | psmax = (val >> 4) & 0x7; | ||
90 | |||
91 | if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val)) | ||
92 | return -1; | ||
93 | |||
94 | pscur = val & 0x7; | ||
95 | |||
96 | pscur += boost_states; | ||
97 | psmax += boost_states; | ||
98 | for (i = 0; i <= psmax; i++) { | ||
99 | if (i >= MAX_HW_PSTATES) { | ||
100 | fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n", | ||
101 | psmax, MAX_HW_PSTATES); | ||
102 | return -1; | ||
103 | } | ||
104 | if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val)) | ||
105 | return -1; | ||
106 | pstates[i] = get_cof(cpu_family, pstate); | ||
107 | } | ||
108 | *no = i; | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | int amd_pci_get_num_boost_states(int *active, int *states) | ||
113 | { | ||
114 | struct pci_access *pci_acc; | ||
115 | int vendor_id = 0x1022; | ||
116 | int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0}; | ||
117 | struct pci_dev *device; | ||
118 | uint8_t val = 0; | ||
119 | |||
120 | *active = *states = 0; | ||
121 | |||
122 | device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids); | ||
123 | |||
124 | if (device == NULL) | ||
125 | return -ENODEV; | ||
126 | |||
127 | val = pci_read_byte(device, 0x15c); | ||
128 | if (val & 3) | ||
129 | *active = 1; | ||
130 | else | ||
131 | *active = 0; | ||
132 | *states = (val >> 2) & 7; | ||
133 | |||
134 | pci_cleanup(pci_acc); | ||
135 | return 0; | ||
136 | } | ||
137 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/helpers/bitmask.c b/tools/power/cpupower/utils/helpers/bitmask.c new file mode 100644 index 000000000000..5c074c60f904 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/bitmask.c | |||
@@ -0,0 +1,292 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | |||
5 | #include <helpers/bitmask.h> | ||
6 | |||
7 | /* How many bits in an unsigned long */ | ||
8 | #define bitsperlong (8 * sizeof(unsigned long)) | ||
9 | |||
10 | /* howmany(a,b) : how many elements of size b needed to hold all of a */ | ||
11 | #define howmany(x, y) (((x)+((y)-1))/(y)) | ||
12 | |||
13 | /* How many longs in mask of n bits */ | ||
14 | #define longsperbits(n) howmany(n, bitsperlong) | ||
15 | |||
16 | #define max(a, b) ((a) > (b) ? (a) : (b)) | ||
17 | |||
18 | /* | ||
19 | * Allocate and free `struct bitmask *` | ||
20 | */ | ||
21 | |||
22 | /* Allocate a new `struct bitmask` with a size of n bits */ | ||
23 | struct bitmask *bitmask_alloc(unsigned int n) | ||
24 | { | ||
25 | struct bitmask *bmp; | ||
26 | |||
27 | bmp = malloc(sizeof(*bmp)); | ||
28 | if (bmp == 0) | ||
29 | return 0; | ||
30 | bmp->size = n; | ||
31 | bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long)); | ||
32 | if (bmp->maskp == 0) { | ||
33 | free(bmp); | ||
34 | return 0; | ||
35 | } | ||
36 | return bmp; | ||
37 | } | ||
38 | |||
39 | /* Free `struct bitmask` */ | ||
40 | void bitmask_free(struct bitmask *bmp) | ||
41 | { | ||
42 | if (bmp == 0) | ||
43 | return; | ||
44 | free(bmp->maskp); | ||
45 | bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */ | ||
46 | free(bmp); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * The routines _getbit() and _setbit() are the only | ||
51 | * routines that actually understand the layout of bmp->maskp[]. | ||
52 | * | ||
53 | * On little endian architectures, this could simply be an array of | ||
54 | * bytes. But the kernel layout of bitmasks _is_ visible to userspace | ||
55 | * via the sched_(set/get)affinity calls in Linux 2.6, and on big | ||
56 | * endian architectures, it is painfully obvious that this is an | ||
57 | * array of unsigned longs. | ||
58 | */ | ||
59 | |||
60 | /* Return the value (0 or 1) of bit n in bitmask bmp */ | ||
61 | static unsigned int _getbit(const struct bitmask *bmp, unsigned int n) | ||
62 | { | ||
63 | if (n < bmp->size) | ||
64 | return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1; | ||
65 | else | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* Set bit n in bitmask bmp to value v (0 or 1) */ | ||
70 | static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v) | ||
71 | { | ||
72 | if (n < bmp->size) { | ||
73 | if (v) | ||
74 | bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong); | ||
75 | else | ||
76 | bmp->maskp[n/bitsperlong] &= | ||
77 | ~(1UL << (n % bitsperlong)); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * When parsing bitmask lists, only allow numbers, separated by one | ||
83 | * of the allowed next characters. | ||
84 | * | ||
85 | * The parameter 'sret' is the return from a sscanf "%u%c". It is | ||
86 | * -1 if the sscanf input string was empty. It is 0 if the first | ||
87 | * character in the sscanf input string was not a decimal number. | ||
88 | * It is 1 if the unsigned number matching the "%u" was the end of the | ||
89 | * input string. It is 2 if one or more additional characters followed | ||
90 | * the matched unsigned number. If it is 2, then 'nextc' is the first | ||
91 | * character following the number. The parameter 'ok_next_chars' | ||
92 | * is the nul-terminated list of allowed next characters. | ||
93 | * | ||
94 | * The mask term just scanned was ok if and only if either the numbers | ||
95 | * matching the %u were all of the input or if the next character in | ||
96 | * the input past the numbers was one of the allowed next characters. | ||
97 | */ | ||
98 | static int scan_was_ok(int sret, char nextc, const char *ok_next_chars) | ||
99 | { | ||
100 | return sret == 1 || | ||
101 | (sret == 2 && strchr(ok_next_chars, nextc) != NULL); | ||
102 | } | ||
103 | |||
104 | static const char *nexttoken(const char *q, int sep) | ||
105 | { | ||
106 | if (q) | ||
107 | q = strchr(q, sep); | ||
108 | if (q) | ||
109 | q++; | ||
110 | return q; | ||
111 | } | ||
112 | |||
113 | /* Set a single bit i in bitmask */ | ||
114 | struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i) | ||
115 | { | ||
116 | _setbit(bmp, i, 1); | ||
117 | return bmp; | ||
118 | } | ||
119 | |||
120 | /* Set all bits in bitmask: bmp = ~0 */ | ||
121 | struct bitmask *bitmask_setall(struct bitmask *bmp) | ||
122 | { | ||
123 | unsigned int i; | ||
124 | for (i = 0; i < bmp->size; i++) | ||
125 | _setbit(bmp, i, 1); | ||
126 | return bmp; | ||
127 | } | ||
128 | |||
129 | /* Clear all bits in bitmask: bmp = 0 */ | ||
130 | struct bitmask *bitmask_clearall(struct bitmask *bmp) | ||
131 | { | ||
132 | unsigned int i; | ||
133 | for (i = 0; i < bmp->size; i++) | ||
134 | _setbit(bmp, i, 0); | ||
135 | return bmp; | ||
136 | } | ||
137 | |||
138 | /* True if all bits are clear */ | ||
139 | int bitmask_isallclear(const struct bitmask *bmp) | ||
140 | { | ||
141 | unsigned int i; | ||
142 | for (i = 0; i < bmp->size; i++) | ||
143 | if (_getbit(bmp, i)) | ||
144 | return 0; | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | /* True if specified bit i is set */ | ||
149 | int bitmask_isbitset(const struct bitmask *bmp, unsigned int i) | ||
150 | { | ||
151 | return _getbit(bmp, i); | ||
152 | } | ||
153 | |||
154 | /* Number of lowest set bit (min) */ | ||
155 | unsigned int bitmask_first(const struct bitmask *bmp) | ||
156 | { | ||
157 | return bitmask_next(bmp, 0); | ||
158 | } | ||
159 | |||
160 | /* Number of highest set bit (max) */ | ||
161 | unsigned int bitmask_last(const struct bitmask *bmp) | ||
162 | { | ||
163 | unsigned int i; | ||
164 | unsigned int m = bmp->size; | ||
165 | for (i = 0; i < bmp->size; i++) | ||
166 | if (_getbit(bmp, i)) | ||
167 | m = i; | ||
168 | return m; | ||
169 | } | ||
170 | |||
171 | /* Number of next set bit at or above given bit i */ | ||
172 | unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i) | ||
173 | { | ||
174 | unsigned int n; | ||
175 | for (n = i; n < bmp->size; n++) | ||
176 | if (_getbit(bmp, n)) | ||
177 | break; | ||
178 | return n; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Parses a comma-separated list of numbers and ranges of numbers, | ||
183 | * with optional ':%u' strides modifying ranges, into provided bitmask. | ||
184 | * Some examples of input lists and their equivalent simple list: | ||
185 | * Input Equivalent to | ||
186 | * 0-3 0,1,2,3 | ||
187 | * 0-7:2 0,2,4,6 | ||
188 | * 1,3,5-7 1,3,5,6,7 | ||
189 | * 0-3:2,8-15:4 0,2,8,12 | ||
190 | */ | ||
191 | int bitmask_parselist(const char *buf, struct bitmask *bmp) | ||
192 | { | ||
193 | const char *p, *q; | ||
194 | |||
195 | bitmask_clearall(bmp); | ||
196 | |||
197 | q = buf; | ||
198 | while (p = q, q = nexttoken(q, ','), p) { | ||
199 | unsigned int a; /* begin of range */ | ||
200 | unsigned int b; /* end of range */ | ||
201 | unsigned int s; /* stride */ | ||
202 | const char *c1, *c2; /* next tokens after '-' or ',' */ | ||
203 | char nextc; /* char after sscanf %u match */ | ||
204 | int sret; /* sscanf return (number of matches) */ | ||
205 | |||
206 | sret = sscanf(p, "%u%c", &a, &nextc); | ||
207 | if (!scan_was_ok(sret, nextc, ",-")) | ||
208 | goto err; | ||
209 | b = a; | ||
210 | s = 1; | ||
211 | c1 = nexttoken(p, '-'); | ||
212 | c2 = nexttoken(p, ','); | ||
213 | if (c1 != NULL && (c2 == NULL || c1 < c2)) { | ||
214 | sret = sscanf(c1, "%u%c", &b, &nextc); | ||
215 | if (!scan_was_ok(sret, nextc, ",:")) | ||
216 | goto err; | ||
217 | c1 = nexttoken(c1, ':'); | ||
218 | if (c1 != NULL && (c2 == NULL || c1 < c2)) { | ||
219 | sret = sscanf(c1, "%u%c", &s, &nextc); | ||
220 | if (!scan_was_ok(sret, nextc, ",")) | ||
221 | goto err; | ||
222 | } | ||
223 | } | ||
224 | if (!(a <= b)) | ||
225 | goto err; | ||
226 | if (b >= bmp->size) | ||
227 | goto err; | ||
228 | while (a <= b) { | ||
229 | _setbit(bmp, a, 1); | ||
230 | a += s; | ||
231 | } | ||
232 | } | ||
233 | return 0; | ||
234 | err: | ||
235 | bitmask_clearall(bmp); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * emit(buf, buflen, rbot, rtop, len) | ||
241 | * | ||
242 | * Helper routine for bitmask_displaylist(). Write decimal number | ||
243 | * or range to buf+len, suppressing output past buf+buflen, with optional | ||
244 | * comma-prefix. Return len of what would be written to buf, if it | ||
245 | * all fit. | ||
246 | */ | ||
247 | |||
248 | static inline int emit(char *buf, int buflen, int rbot, int rtop, int len) | ||
249 | { | ||
250 | if (len > 0) | ||
251 | len += snprintf(buf + len, max(buflen - len, 0), ","); | ||
252 | if (rbot == rtop) | ||
253 | len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot); | ||
254 | else | ||
255 | len += snprintf(buf + len, max(buflen - len, 0), "%d-%d", | ||
256 | rbot, rtop); | ||
257 | return len; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Write decimal list representation of bmp to buf. | ||
262 | * | ||
263 | * Output format is a comma-separated list of decimal numbers and | ||
264 | * ranges. Consecutively set bits are shown as two hyphen-separated | ||
265 | * decimal numbers, the smallest and largest bit numbers set in | ||
266 | * the range. Output format is compatible with the format | ||
267 | * accepted as input by bitmap_parselist(). | ||
268 | * | ||
269 | * The return value is the number of characters which would be | ||
270 | * generated for the given input, excluding the trailing '\0', as | ||
271 | * per ISO C99. | ||
272 | */ | ||
273 | |||
274 | int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp) | ||
275 | { | ||
276 | int len = 0; | ||
277 | /* current bit is 'cur', most recently seen range is [rbot, rtop] */ | ||
278 | unsigned int cur, rbot, rtop; | ||
279 | |||
280 | if (buflen > 0) | ||
281 | *buf = 0; | ||
282 | rbot = cur = bitmask_first(bmp); | ||
283 | while (cur < bmp->size) { | ||
284 | rtop = cur; | ||
285 | cur = bitmask_next(bmp, cur+1); | ||
286 | if (cur >= bmp->size || cur > rtop + 1) { | ||
287 | len = emit(buf, buflen, rbot, rtop, len); | ||
288 | rbot = cur; | ||
289 | } | ||
290 | } | ||
291 | return len; | ||
292 | } | ||
diff --git a/tools/power/cpupower/utils/helpers/bitmask.h b/tools/power/cpupower/utils/helpers/bitmask.h new file mode 100644 index 000000000000..eb289df41053 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/bitmask.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifndef __CPUPOWER_BITMASK__ | ||
2 | #define __CPUPOWER_BITMASK__ | ||
3 | |||
4 | /* Taken over from libbitmask, a project initiated from sgi: | ||
5 | * Url: http://oss.sgi.com/projects/cpusets/ | ||
6 | * Unfortunately it's not very widespread, therefore relevant parts are | ||
7 | * pasted here. | ||
8 | */ | ||
9 | |||
10 | struct bitmask { | ||
11 | unsigned int size; | ||
12 | unsigned long *maskp; | ||
13 | }; | ||
14 | |||
15 | struct bitmask *bitmask_alloc(unsigned int n); | ||
16 | void bitmask_free(struct bitmask *bmp); | ||
17 | |||
18 | struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i); | ||
19 | struct bitmask *bitmask_setall(struct bitmask *bmp); | ||
20 | struct bitmask *bitmask_clearall(struct bitmask *bmp); | ||
21 | |||
22 | unsigned int bitmask_first(const struct bitmask *bmp); | ||
23 | unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i); | ||
24 | unsigned int bitmask_last(const struct bitmask *bmp); | ||
25 | int bitmask_isallclear(const struct bitmask *bmp); | ||
26 | int bitmask_isbitset(const struct bitmask *bmp, unsigned int i); | ||
27 | |||
28 | int bitmask_parselist(const char *buf, struct bitmask *bmp); | ||
29 | int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp); | ||
30 | |||
31 | |||
32 | |||
33 | #endif /*__CPUPOWER_BITMASK__ */ | ||
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c new file mode 100644 index 000000000000..906895d21cce --- /dev/null +++ b/tools/power/cpupower/utils/helpers/cpuid.c | |||
@@ -0,0 +1,176 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <errno.h> | ||
3 | #include <string.h> | ||
4 | #include <unistd.h> | ||
5 | #include <stdlib.h> | ||
6 | |||
7 | #include "helpers/helpers.h" | ||
8 | |||
9 | static const char *cpu_vendor_table[X86_VENDOR_MAX] = { | ||
10 | "Unknown", "GenuineIntel", "AuthenticAMD", | ||
11 | }; | ||
12 | |||
13 | #if defined(__i386__) || defined(__x86_64__) | ||
14 | |||
15 | /* from gcc */ | ||
16 | #include <cpuid.h> | ||
17 | |||
18 | /* | ||
19 | * CPUID functions returning a single datum | ||
20 | * | ||
21 | * Define unsigned int cpuid_e[abcd]x(unsigned int op) | ||
22 | */ | ||
23 | #define cpuid_func(reg) \ | ||
24 | unsigned int cpuid_##reg(unsigned int op) \ | ||
25 | { \ | ||
26 | unsigned int eax, ebx, ecx, edx; \ | ||
27 | __cpuid(op, eax, ebx, ecx, edx); \ | ||
28 | return reg; \ | ||
29 | } | ||
30 | cpuid_func(eax); | ||
31 | cpuid_func(ebx); | ||
32 | cpuid_func(ecx); | ||
33 | cpuid_func(edx); | ||
34 | |||
35 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
36 | |||
37 | /* get_cpu_info | ||
38 | * | ||
39 | * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo | ||
40 | * | ||
41 | * Returns 0 on success or a negativ error code | ||
42 | * | ||
43 | * TBD: Should there be a cpuid alternative for this if /proc is not mounted? | ||
44 | */ | ||
45 | int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info) | ||
46 | { | ||
47 | FILE *fp; | ||
48 | char value[64]; | ||
49 | unsigned int proc, x; | ||
50 | unsigned int unknown = 0xffffff; | ||
51 | unsigned int cpuid_level, ext_cpuid_level; | ||
52 | |||
53 | int ret = -EINVAL; | ||
54 | |||
55 | cpu_info->vendor = X86_VENDOR_UNKNOWN; | ||
56 | cpu_info->family = unknown; | ||
57 | cpu_info->model = unknown; | ||
58 | cpu_info->stepping = unknown; | ||
59 | cpu_info->caps = 0; | ||
60 | |||
61 | fp = fopen("/proc/cpuinfo", "r"); | ||
62 | if (!fp) | ||
63 | return -EIO; | ||
64 | |||
65 | while (!feof(fp)) { | ||
66 | if (!fgets(value, 64, fp)) | ||
67 | continue; | ||
68 | value[63 - 1] = '\0'; | ||
69 | |||
70 | if (!strncmp(value, "processor\t: ", 12)) | ||
71 | sscanf(value, "processor\t: %u", &proc); | ||
72 | |||
73 | if (proc != cpu) | ||
74 | continue; | ||
75 | |||
76 | /* Get CPU vendor */ | ||
77 | if (!strncmp(value, "vendor_id", 9)) { | ||
78 | for (x = 1; x < X86_VENDOR_MAX; x++) { | ||
79 | if (strstr(value, cpu_vendor_table[x])) | ||
80 | cpu_info->vendor = x; | ||
81 | } | ||
82 | /* Get CPU family, etc. */ | ||
83 | } else if (!strncmp(value, "cpu family\t: ", 13)) { | ||
84 | sscanf(value, "cpu family\t: %u", | ||
85 | &cpu_info->family); | ||
86 | } else if (!strncmp(value, "model\t\t: ", 9)) { | ||
87 | sscanf(value, "model\t\t: %u", | ||
88 | &cpu_info->model); | ||
89 | } else if (!strncmp(value, "stepping\t: ", 10)) { | ||
90 | sscanf(value, "stepping\t: %u", | ||
91 | &cpu_info->stepping); | ||
92 | |||
93 | /* Exit -> all values must have been set */ | ||
94 | if (cpu_info->vendor == X86_VENDOR_UNKNOWN || | ||
95 | cpu_info->family == unknown || | ||
96 | cpu_info->model == unknown || | ||
97 | cpu_info->stepping == unknown) { | ||
98 | ret = -EINVAL; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | ret = 0; | ||
103 | goto out; | ||
104 | } | ||
105 | } | ||
106 | ret = -ENODEV; | ||
107 | out: | ||
108 | fclose(fp); | ||
109 | /* Get some useful CPU capabilities from cpuid */ | ||
110 | if (cpu_info->vendor != X86_VENDOR_AMD && | ||
111 | cpu_info->vendor != X86_VENDOR_INTEL) | ||
112 | return ret; | ||
113 | |||
114 | cpuid_level = cpuid_eax(0); | ||
115 | ext_cpuid_level = cpuid_eax(0x80000000); | ||
116 | |||
117 | /* Invariant TSC */ | ||
118 | if (ext_cpuid_level >= 0x80000007 && | ||
119 | (cpuid_edx(0x80000007) & (1 << 8))) | ||
120 | cpu_info->caps |= CPUPOWER_CAP_INV_TSC; | ||
121 | |||
122 | /* Aperf/Mperf registers support */ | ||
123 | if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1)) | ||
124 | cpu_info->caps |= CPUPOWER_CAP_APERF; | ||
125 | |||
126 | /* AMD Boost state enable/disable register */ | ||
127 | if (cpu_info->vendor == X86_VENDOR_AMD) { | ||
128 | if (ext_cpuid_level >= 0x80000007 && | ||
129 | (cpuid_edx(0x80000007) & (1 << 9))) | ||
130 | cpu_info->caps |= CPUPOWER_CAP_AMD_CBP; | ||
131 | } | ||
132 | |||
133 | if (cpu_info->vendor == X86_VENDOR_INTEL) { | ||
134 | if (cpuid_level >= 6 && | ||
135 | (cpuid_eax(6) & (1 << 1))) | ||
136 | cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA; | ||
137 | } | ||
138 | |||
139 | if (cpu_info->vendor == X86_VENDOR_INTEL) { | ||
140 | /* Intel's perf-bias MSR support */ | ||
141 | if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3))) | ||
142 | cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS; | ||
143 | |||
144 | /* Intel's Turbo Ratio Limit support */ | ||
145 | if (cpu_info->family == 6) { | ||
146 | switch (cpu_info->model) { | ||
147 | case 0x1A: /* Core i7, Xeon 5500 series | ||
148 | * Bloomfield, Gainstown NHM-EP | ||
149 | */ | ||
150 | case 0x1E: /* Core i7 and i5 Processor | ||
151 | * Clarksfield, Lynnfield, Jasper Forest | ||
152 | */ | ||
153 | case 0x1F: /* Core i7 and i5 Processor - Nehalem */ | ||
154 | case 0x25: /* Westmere Client | ||
155 | * Clarkdale, Arrandale | ||
156 | */ | ||
157 | case 0x2C: /* Westmere EP - Gulftown */ | ||
158 | cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; | ||
159 | case 0x2A: /* SNB */ | ||
160 | case 0x2D: /* SNB Xeon */ | ||
161 | cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; | ||
162 | cpu_info->caps |= CPUPOWER_CAP_IS_SNB; | ||
163 | break; | ||
164 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ | ||
165 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ | ||
166 | default: | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n", | ||
173 | cpuid_level, ext_cpuid_level, cpu_info->caps); | ||
174 | */ | ||
175 | return ret; | ||
176 | } | ||
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h new file mode 100644 index 000000000000..2747e738efb0 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Miscellaneous helpers which do not fit or are worth | ||
7 | * to put into separate headers | ||
8 | */ | ||
9 | |||
10 | #ifndef __CPUPOWERUTILS_HELPERS__ | ||
11 | #define __CPUPOWERUTILS_HELPERS__ | ||
12 | |||
13 | #include <libintl.h> | ||
14 | #include <locale.h> | ||
15 | |||
16 | #include "helpers/bitmask.h" | ||
17 | |||
18 | /* Internationalization ****************************/ | ||
19 | #ifdef NLS | ||
20 | |||
21 | #define _(String) gettext(String) | ||
22 | #ifndef gettext_noop | ||
23 | #define gettext_noop(String) String | ||
24 | #endif | ||
25 | #define N_(String) gettext_noop(String) | ||
26 | |||
27 | #else /* !NLS */ | ||
28 | |||
29 | #define _(String) String | ||
30 | #define N_(String) String | ||
31 | |||
32 | #endif | ||
33 | /* Internationalization ****************************/ | ||
34 | |||
35 | extern int run_as_root; | ||
36 | extern struct bitmask *cpus_chosen; | ||
37 | |||
38 | /* Global verbose (-d) stuff *********************************/ | ||
39 | /* | ||
40 | * define DEBUG via global Makefile variable | ||
41 | * Debug output is sent to stderr, do: | ||
42 | * cpupower monitor 2>/tmp/debug | ||
43 | * to split debug output away from normal output | ||
44 | */ | ||
45 | #ifdef DEBUG | ||
46 | extern int be_verbose; | ||
47 | |||
48 | #define dprint(fmt, ...) { \ | ||
49 | if (be_verbose) { \ | ||
50 | fprintf(stderr, "%s: " fmt, \ | ||
51 | __func__, ##__VA_ARGS__); \ | ||
52 | } \ | ||
53 | } | ||
54 | #else | ||
55 | static inline void dprint(const char *fmt, ...) { } | ||
56 | #endif | ||
57 | extern int be_verbose; | ||
58 | /* Global verbose (-v) stuff *********************************/ | ||
59 | |||
60 | /* cpuid and cpuinfo helpers **************************/ | ||
61 | enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, | ||
62 | X86_VENDOR_AMD, X86_VENDOR_MAX}; | ||
63 | |||
64 | #define CPUPOWER_CAP_INV_TSC 0x00000001 | ||
65 | #define CPUPOWER_CAP_APERF 0x00000002 | ||
66 | #define CPUPOWER_CAP_AMD_CBP 0x00000004 | ||
67 | #define CPUPOWER_CAP_PERF_BIAS 0x00000008 | ||
68 | #define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010 | ||
69 | #define CPUPOWER_CAP_IS_SNB 0x00000011 | ||
70 | #define CPUPOWER_CAP_INTEL_IDA 0x00000012 | ||
71 | |||
72 | #define MAX_HW_PSTATES 10 | ||
73 | |||
74 | struct cpupower_cpu_info { | ||
75 | enum cpupower_cpu_vendor vendor; | ||
76 | unsigned int family; | ||
77 | unsigned int model; | ||
78 | unsigned int stepping; | ||
79 | /* CPU capabilities read out from cpuid */ | ||
80 | unsigned long long caps; | ||
81 | }; | ||
82 | |||
83 | /* get_cpu_info | ||
84 | * | ||
85 | * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo | ||
86 | * | ||
87 | * Returns 0 on success or a negativ error code | ||
88 | * Only used on x86, below global's struct values are zero/unknown on | ||
89 | * other archs | ||
90 | */ | ||
91 | extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); | ||
92 | extern struct cpupower_cpu_info cpupower_cpu_info; | ||
93 | /* cpuid and cpuinfo helpers **************************/ | ||
94 | |||
95 | |||
96 | /* CPU topology/hierarchy parsing ******************/ | ||
97 | struct cpupower_topology { | ||
98 | /* Amount of CPU cores, packages and threads per core in the system */ | ||
99 | unsigned int cores; | ||
100 | unsigned int pkgs; | ||
101 | unsigned int threads; /* per core */ | ||
102 | |||
103 | /* Array gets mallocated with cores entries, holding per core info */ | ||
104 | struct { | ||
105 | int pkg; | ||
106 | int core; | ||
107 | int cpu; | ||
108 | |||
109 | /* flags */ | ||
110 | unsigned int is_online:1; | ||
111 | } *core_info; | ||
112 | }; | ||
113 | |||
114 | extern int get_cpu_topology(struct cpupower_topology *cpu_top); | ||
115 | extern void cpu_topology_release(struct cpupower_topology cpu_top); | ||
116 | /* CPU topology/hierarchy parsing ******************/ | ||
117 | |||
118 | /* X86 ONLY ****************************************/ | ||
119 | #if defined(__i386__) || defined(__x86_64__) | ||
120 | |||
121 | #include <pci/pci.h> | ||
122 | |||
123 | /* Read/Write msr ****************************/ | ||
124 | extern int read_msr(int cpu, unsigned int idx, unsigned long long *val); | ||
125 | extern int write_msr(int cpu, unsigned int idx, unsigned long long val); | ||
126 | |||
127 | extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val); | ||
128 | extern int msr_intel_get_perf_bias(unsigned int cpu); | ||
129 | extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu); | ||
130 | |||
131 | /* Read/Write msr ****************************/ | ||
132 | |||
133 | /* PCI stuff ****************************/ | ||
134 | extern int amd_pci_get_num_boost_states(int *active, int *states); | ||
135 | extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id, | ||
136 | int *dev_ids); | ||
137 | |||
138 | /* PCI stuff ****************************/ | ||
139 | |||
140 | /* AMD HW pstate decoding **************************/ | ||
141 | |||
142 | extern int decode_pstates(unsigned int cpu, unsigned int cpu_family, | ||
143 | int boost_states, unsigned long *pstates, int *no); | ||
144 | |||
145 | /* AMD HW pstate decoding **************************/ | ||
146 | |||
147 | extern int cpufreq_has_boost_support(unsigned int cpu, int *support, | ||
148 | int *active, int * states); | ||
149 | /* | ||
150 | * CPUID functions returning a single datum | ||
151 | */ | ||
152 | unsigned int cpuid_eax(unsigned int op); | ||
153 | unsigned int cpuid_ebx(unsigned int op); | ||
154 | unsigned int cpuid_ecx(unsigned int op); | ||
155 | unsigned int cpuid_edx(unsigned int op); | ||
156 | |||
157 | /* cpuid and cpuinfo helpers **************************/ | ||
158 | /* X86 ONLY ********************************************/ | ||
159 | #else | ||
160 | static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family, | ||
161 | int boost_states, unsigned long *pstates, | ||
162 | int *no) | ||
163 | { return -1; }; | ||
164 | |||
165 | static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val) | ||
166 | { return -1; }; | ||
167 | static inline int write_msr(int cpu, unsigned int idx, unsigned long long val) | ||
168 | { return -1; }; | ||
169 | static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val) | ||
170 | { return -1; }; | ||
171 | static inline int msr_intel_get_perf_bias(unsigned int cpu) | ||
172 | { return -1; }; | ||
173 | static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu) | ||
174 | { return 0; }; | ||
175 | |||
176 | /* Read/Write msr ****************************/ | ||
177 | |||
178 | static inline int cpufreq_has_boost_support(unsigned int cpu, int *support, | ||
179 | int *active, int * states) | ||
180 | { return -1; } | ||
181 | |||
182 | /* cpuid and cpuinfo helpers **************************/ | ||
183 | |||
184 | static inline unsigned int cpuid_eax(unsigned int op) { return 0; }; | ||
185 | static inline unsigned int cpuid_ebx(unsigned int op) { return 0; }; | ||
186 | static inline unsigned int cpuid_ecx(unsigned int op) { return 0; }; | ||
187 | static inline unsigned int cpuid_edx(unsigned int op) { return 0; }; | ||
188 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
189 | |||
190 | #endif /* __CPUPOWERUTILS_HELPERS__ */ | ||
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c new file mode 100644 index 000000000000..1609243f5c64 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/misc.c | |||
@@ -0,0 +1,27 @@ | |||
1 | #if defined(__i386__) || defined(__x86_64__) | ||
2 | |||
3 | #include "helpers/helpers.h" | ||
4 | |||
5 | int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, | ||
6 | int *states) | ||
7 | { | ||
8 | struct cpupower_cpu_info cpu_info; | ||
9 | int ret; | ||
10 | |||
11 | *support = *active = *states = 0; | ||
12 | |||
13 | ret = get_cpu_info(0, &cpu_info); | ||
14 | if (ret) | ||
15 | return ret; | ||
16 | |||
17 | if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) { | ||
18 | *support = 1; | ||
19 | amd_pci_get_num_boost_states(active, states); | ||
20 | if (ret <= 0) | ||
21 | return ret; | ||
22 | *support = 1; | ||
23 | } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) | ||
24 | *support = *active = 1; | ||
25 | return 0; | ||
26 | } | ||
27 | #endif /* #if defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/helpers/msr.c b/tools/power/cpupower/utils/helpers/msr.c new file mode 100644 index 000000000000..31a4b24a8bc6 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/msr.c | |||
@@ -0,0 +1,115 @@ | |||
1 | #if defined(__i386__) || defined(__x86_64__) | ||
2 | |||
3 | #include <fcntl.h> | ||
4 | #include <stdio.h> | ||
5 | #include <unistd.h> | ||
6 | #include <stdint.h> | ||
7 | |||
8 | #include "helpers/helpers.h" | ||
9 | |||
10 | /* Intel specific MSRs */ | ||
11 | #define MSR_IA32_PERF_STATUS 0x198 | ||
12 | #define MSR_IA32_MISC_ENABLES 0x1a0 | ||
13 | #define MSR_IA32_ENERGY_PERF_BIAS 0x1b0 | ||
14 | #define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1ad | ||
15 | |||
16 | /* | ||
17 | * read_msr | ||
18 | * | ||
19 | * Will return 0 on success and -1 on failure. | ||
20 | * Possible errno values could be: | ||
21 | * EFAULT -If the read/write did not fully complete | ||
22 | * EIO -If the CPU does not support MSRs | ||
23 | * ENXIO -If the CPU does not exist | ||
24 | */ | ||
25 | |||
26 | int read_msr(int cpu, unsigned int idx, unsigned long long *val) | ||
27 | { | ||
28 | int fd; | ||
29 | char msr_file_name[64]; | ||
30 | |||
31 | sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); | ||
32 | fd = open(msr_file_name, O_RDONLY); | ||
33 | if (fd < 0) | ||
34 | return -1; | ||
35 | if (lseek(fd, idx, SEEK_CUR) == -1) | ||
36 | goto err; | ||
37 | if (read(fd, val, sizeof *val) != sizeof *val) | ||
38 | goto err; | ||
39 | close(fd); | ||
40 | return 0; | ||
41 | err: | ||
42 | close(fd); | ||
43 | return -1; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * write_msr | ||
48 | * | ||
49 | * Will return 0 on success and -1 on failure. | ||
50 | * Possible errno values could be: | ||
51 | * EFAULT -If the read/write did not fully complete | ||
52 | * EIO -If the CPU does not support MSRs | ||
53 | * ENXIO -If the CPU does not exist | ||
54 | */ | ||
55 | int write_msr(int cpu, unsigned int idx, unsigned long long val) | ||
56 | { | ||
57 | int fd; | ||
58 | char msr_file_name[64]; | ||
59 | |||
60 | sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); | ||
61 | fd = open(msr_file_name, O_WRONLY); | ||
62 | if (fd < 0) | ||
63 | return -1; | ||
64 | if (lseek(fd, idx, SEEK_CUR) == -1) | ||
65 | goto err; | ||
66 | if (write(fd, &val, sizeof val) != sizeof val) | ||
67 | goto err; | ||
68 | close(fd); | ||
69 | return 0; | ||
70 | err: | ||
71 | close(fd); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | int msr_intel_get_perf_bias(unsigned int cpu) | ||
76 | { | ||
77 | unsigned long long val; | ||
78 | int ret; | ||
79 | |||
80 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) | ||
81 | return -1; | ||
82 | |||
83 | ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val); | ||
84 | if (ret) | ||
85 | return ret; | ||
86 | return val; | ||
87 | } | ||
88 | |||
89 | int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val) | ||
90 | { | ||
91 | int ret; | ||
92 | |||
93 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) | ||
94 | return -1; | ||
95 | |||
96 | ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu) | ||
103 | { | ||
104 | unsigned long long val; | ||
105 | int ret; | ||
106 | |||
107 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO)) | ||
108 | return -1; | ||
109 | |||
110 | ret = read_msr(cpu, MSR_NEHALEM_TURBO_RATIO_LIMIT, &val); | ||
111 | if (ret) | ||
112 | return ret; | ||
113 | return val; | ||
114 | } | ||
115 | #endif | ||
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c new file mode 100644 index 000000000000..cd2eb6fe41c4 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/pci.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #if defined(__i386__) || defined(__x86_64__) | ||
2 | |||
3 | #include <helpers/helpers.h> | ||
4 | |||
5 | /* | ||
6 | * pci_acc_init | ||
7 | * | ||
8 | * PCI access helper function depending on libpci | ||
9 | * | ||
10 | * **pacc : if a valid pci_dev is returned | ||
11 | * *pacc must be passed to pci_acc_cleanup to free it | ||
12 | * | ||
13 | * vendor_id : the pci vendor id matching the pci device to access | ||
14 | * dev_ids : device ids matching the pci device to access | ||
15 | * | ||
16 | * Returns : | ||
17 | * struct pci_dev which can be used with pci_{read,write}_* functions | ||
18 | * to access the PCI config space of matching pci devices | ||
19 | */ | ||
20 | struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id, | ||
21 | int *dev_ids) | ||
22 | { | ||
23 | struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0}; | ||
24 | struct pci_dev *device; | ||
25 | unsigned int i; | ||
26 | |||
27 | *pacc = pci_alloc(); | ||
28 | if (*pacc == NULL) | ||
29 | return NULL; | ||
30 | |||
31 | pci_init(*pacc); | ||
32 | pci_scan_bus(*pacc); | ||
33 | |||
34 | for (i = 0; dev_ids[i] != 0; i++) { | ||
35 | filter_nb_link.device = dev_ids[i]; | ||
36 | for (device = (*pacc)->devices; device; device = device->next) { | ||
37 | if (pci_filter_match(&filter_nb_link, device)) | ||
38 | return device; | ||
39 | } | ||
40 | } | ||
41 | pci_cleanup(*pacc); | ||
42 | return NULL; | ||
43 | } | ||
44 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c new file mode 100644 index 000000000000..c6343024a611 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/sysfs.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc. | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <errno.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "helpers/sysfs.h" | ||
18 | |||
19 | unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
20 | { | ||
21 | int fd; | ||
22 | ssize_t numread; | ||
23 | |||
24 | fd = open(path, O_RDONLY); | ||
25 | if (fd == -1) | ||
26 | return 0; | ||
27 | |||
28 | numread = read(fd, buf, buflen - 1); | ||
29 | if (numread < 1) { | ||
30 | close(fd); | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | buf[numread] = '\0'; | ||
35 | close(fd); | ||
36 | |||
37 | return (unsigned int) numread; | ||
38 | } | ||
39 | |||
40 | static unsigned int sysfs_write_file(const char *path, | ||
41 | const char *value, size_t len) | ||
42 | { | ||
43 | int fd; | ||
44 | ssize_t numwrite; | ||
45 | |||
46 | fd = open(path, O_WRONLY); | ||
47 | if (fd == -1) | ||
48 | return 0; | ||
49 | |||
50 | numwrite = write(fd, value, len); | ||
51 | if (numwrite < 1) { | ||
52 | close(fd); | ||
53 | return 0; | ||
54 | } | ||
55 | close(fd); | ||
56 | return (unsigned int) numwrite; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Detect whether a CPU is online | ||
61 | * | ||
62 | * Returns: | ||
63 | * 1 -> if CPU is online | ||
64 | * 0 -> if CPU is offline | ||
65 | * negative errno values in error case | ||
66 | */ | ||
67 | int sysfs_is_cpu_online(unsigned int cpu) | ||
68 | { | ||
69 | char path[SYSFS_PATH_MAX]; | ||
70 | int fd; | ||
71 | ssize_t numread; | ||
72 | unsigned long long value; | ||
73 | char linebuf[MAX_LINE_LEN]; | ||
74 | char *endp; | ||
75 | struct stat statbuf; | ||
76 | |||
77 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); | ||
78 | |||
79 | if (stat(path, &statbuf) != 0) | ||
80 | return 0; | ||
81 | |||
82 | /* | ||
83 | * kernel without CONFIG_HOTPLUG_CPU | ||
84 | * -> cpuX directory exists, but not cpuX/online file | ||
85 | */ | ||
86 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); | ||
87 | if (stat(path, &statbuf) != 0) | ||
88 | return 1; | ||
89 | |||
90 | fd = open(path, O_RDONLY); | ||
91 | if (fd == -1) | ||
92 | return -errno; | ||
93 | |||
94 | numread = read(fd, linebuf, MAX_LINE_LEN - 1); | ||
95 | if (numread < 1) { | ||
96 | close(fd); | ||
97 | return -EIO; | ||
98 | } | ||
99 | linebuf[numread] = '\0'; | ||
100 | close(fd); | ||
101 | |||
102 | value = strtoull(linebuf, &endp, 0); | ||
103 | if (value > 1 || value < 0) | ||
104 | return -EINVAL; | ||
105 | |||
106 | return value; | ||
107 | } | ||
108 | |||
109 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | ||
110 | |||
111 | /* | ||
112 | * helper function to read file from /sys into given buffer | ||
113 | * fname is a relative path under "cpuX/cpuidle/stateX/" dir | ||
114 | * cstates starting with 0, C0 is not counted as cstate. | ||
115 | * This means if you want C1 info, pass 0 as idlestate param | ||
116 | */ | ||
117 | unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate, | ||
118 | const char *fname, char *buf, size_t buflen) | ||
119 | { | ||
120 | char path[SYSFS_PATH_MAX]; | ||
121 | int fd; | ||
122 | ssize_t numread; | ||
123 | |||
124 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
125 | cpu, idlestate, fname); | ||
126 | |||
127 | fd = open(path, O_RDONLY); | ||
128 | if (fd == -1) | ||
129 | return 0; | ||
130 | |||
131 | numread = read(fd, buf, buflen - 1); | ||
132 | if (numread < 1) { | ||
133 | close(fd); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | buf[numread] = '\0'; | ||
138 | close(fd); | ||
139 | |||
140 | return (unsigned int) numread; | ||
141 | } | ||
142 | |||
143 | /* read access to files which contain one numeric value */ | ||
144 | |||
145 | enum idlestate_value { | ||
146 | IDLESTATE_USAGE, | ||
147 | IDLESTATE_POWER, | ||
148 | IDLESTATE_LATENCY, | ||
149 | IDLESTATE_TIME, | ||
150 | MAX_IDLESTATE_VALUE_FILES | ||
151 | }; | ||
152 | |||
153 | static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { | ||
154 | [IDLESTATE_USAGE] = "usage", | ||
155 | [IDLESTATE_POWER] = "power", | ||
156 | [IDLESTATE_LATENCY] = "latency", | ||
157 | [IDLESTATE_TIME] = "time", | ||
158 | }; | ||
159 | |||
160 | static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, | ||
161 | unsigned int idlestate, | ||
162 | enum idlestate_value which) | ||
163 | { | ||
164 | unsigned long long value; | ||
165 | unsigned int len; | ||
166 | char linebuf[MAX_LINE_LEN]; | ||
167 | char *endp; | ||
168 | |||
169 | if (which >= MAX_IDLESTATE_VALUE_FILES) | ||
170 | return 0; | ||
171 | |||
172 | len = sysfs_idlestate_read_file(cpu, idlestate, | ||
173 | idlestate_value_files[which], | ||
174 | linebuf, sizeof(linebuf)); | ||
175 | if (len == 0) | ||
176 | return 0; | ||
177 | |||
178 | value = strtoull(linebuf, &endp, 0); | ||
179 | |||
180 | if (endp == linebuf || errno == ERANGE) | ||
181 | return 0; | ||
182 | |||
183 | return value; | ||
184 | } | ||
185 | |||
186 | /* read access to files which contain one string */ | ||
187 | |||
188 | enum idlestate_string { | ||
189 | IDLESTATE_DESC, | ||
190 | IDLESTATE_NAME, | ||
191 | MAX_IDLESTATE_STRING_FILES | ||
192 | }; | ||
193 | |||
194 | static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { | ||
195 | [IDLESTATE_DESC] = "desc", | ||
196 | [IDLESTATE_NAME] = "name", | ||
197 | }; | ||
198 | |||
199 | |||
200 | static char *sysfs_idlestate_get_one_string(unsigned int cpu, | ||
201 | unsigned int idlestate, | ||
202 | enum idlestate_string which) | ||
203 | { | ||
204 | char linebuf[MAX_LINE_LEN]; | ||
205 | char *result; | ||
206 | unsigned int len; | ||
207 | |||
208 | if (which >= MAX_IDLESTATE_STRING_FILES) | ||
209 | return NULL; | ||
210 | |||
211 | len = sysfs_idlestate_read_file(cpu, idlestate, | ||
212 | idlestate_string_files[which], | ||
213 | linebuf, sizeof(linebuf)); | ||
214 | if (len == 0) | ||
215 | return NULL; | ||
216 | |||
217 | result = strdup(linebuf); | ||
218 | if (result == NULL) | ||
219 | return NULL; | ||
220 | |||
221 | if (result[strlen(result) - 1] == '\n') | ||
222 | result[strlen(result) - 1] = '\0'; | ||
223 | |||
224 | return result; | ||
225 | } | ||
226 | |||
227 | unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | ||
228 | unsigned int idlestate) | ||
229 | { | ||
230 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); | ||
231 | } | ||
232 | |||
233 | unsigned long sysfs_get_idlestate_usage(unsigned int cpu, | ||
234 | unsigned int idlestate) | ||
235 | { | ||
236 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE); | ||
237 | } | ||
238 | |||
239 | unsigned long long sysfs_get_idlestate_time(unsigned int cpu, | ||
240 | unsigned int idlestate) | ||
241 | { | ||
242 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME); | ||
243 | } | ||
244 | |||
245 | char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate) | ||
246 | { | ||
247 | return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME); | ||
248 | } | ||
249 | |||
250 | char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate) | ||
251 | { | ||
252 | return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Returns number of supported C-states of CPU core cpu | ||
257 | * Negativ in error case | ||
258 | * Zero if cpuidle does not export any C-states | ||
259 | */ | ||
260 | int sysfs_get_idlestate_count(unsigned int cpu) | ||
261 | { | ||
262 | char file[SYSFS_PATH_MAX]; | ||
263 | struct stat statbuf; | ||
264 | int idlestates = 1; | ||
265 | |||
266 | |||
267 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); | ||
268 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
269 | return -ENODEV; | ||
270 | |||
271 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); | ||
272 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
273 | return 0; | ||
274 | |||
275 | while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { | ||
276 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU | ||
277 | "cpu%u/cpuidle/state%d", cpu, idlestates); | ||
278 | idlestates++; | ||
279 | } | ||
280 | idlestates--; | ||
281 | return idlestates; | ||
282 | } | ||
283 | |||
284 | /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ | ||
285 | |||
286 | /* | ||
287 | * helper function to read file from /sys into given buffer | ||
288 | * fname is a relative path under "cpu/cpuidle/" dir | ||
289 | */ | ||
290 | static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, | ||
291 | size_t buflen) | ||
292 | { | ||
293 | char path[SYSFS_PATH_MAX]; | ||
294 | |||
295 | snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); | ||
296 | |||
297 | return sysfs_read_file(path, buf, buflen); | ||
298 | } | ||
299 | |||
300 | |||
301 | |||
302 | /* read access to files which contain one string */ | ||
303 | |||
304 | enum cpuidle_string { | ||
305 | CPUIDLE_GOVERNOR, | ||
306 | CPUIDLE_GOVERNOR_RO, | ||
307 | CPUIDLE_DRIVER, | ||
308 | MAX_CPUIDLE_STRING_FILES | ||
309 | }; | ||
310 | |||
311 | static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { | ||
312 | [CPUIDLE_GOVERNOR] = "current_governor", | ||
313 | [CPUIDLE_GOVERNOR_RO] = "current_governor_ro", | ||
314 | [CPUIDLE_DRIVER] = "current_driver", | ||
315 | }; | ||
316 | |||
317 | |||
318 | static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) | ||
319 | { | ||
320 | char linebuf[MAX_LINE_LEN]; | ||
321 | char *result; | ||
322 | unsigned int len; | ||
323 | |||
324 | if (which >= MAX_CPUIDLE_STRING_FILES) | ||
325 | return NULL; | ||
326 | |||
327 | len = sysfs_cpuidle_read_file(cpuidle_string_files[which], | ||
328 | linebuf, sizeof(linebuf)); | ||
329 | if (len == 0) | ||
330 | return NULL; | ||
331 | |||
332 | result = strdup(linebuf); | ||
333 | if (result == NULL) | ||
334 | return NULL; | ||
335 | |||
336 | if (result[strlen(result) - 1] == '\n') | ||
337 | result[strlen(result) - 1] = '\0'; | ||
338 | |||
339 | return result; | ||
340 | } | ||
341 | |||
342 | char *sysfs_get_cpuidle_governor(void) | ||
343 | { | ||
344 | char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); | ||
345 | if (!tmp) | ||
346 | return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); | ||
347 | else | ||
348 | return tmp; | ||
349 | } | ||
350 | |||
351 | char *sysfs_get_cpuidle_driver(void) | ||
352 | { | ||
353 | return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); | ||
354 | } | ||
355 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | ||
356 | |||
357 | /* | ||
358 | * Get sched_mc or sched_smt settings | ||
359 | * Pass "mc" or "smt" as argument | ||
360 | * | ||
361 | * Returns negative value on failure | ||
362 | */ | ||
363 | int sysfs_get_sched(const char *smt_mc) | ||
364 | { | ||
365 | unsigned long value; | ||
366 | char linebuf[MAX_LINE_LEN]; | ||
367 | char *endp; | ||
368 | char path[SYSFS_PATH_MAX]; | ||
369 | |||
370 | if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc)) | ||
371 | return -EINVAL; | ||
372 | |||
373 | snprintf(path, sizeof(path), | ||
374 | PATH_TO_CPU "sched_%s_power_savings", smt_mc); | ||
375 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
376 | return -1; | ||
377 | value = strtoul(linebuf, &endp, 0); | ||
378 | if (endp == linebuf || errno == ERANGE) | ||
379 | return -1; | ||
380 | return value; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Get sched_mc or sched_smt settings | ||
385 | * Pass "mc" or "smt" as argument | ||
386 | * | ||
387 | * Returns negative value on failure | ||
388 | */ | ||
389 | int sysfs_set_sched(const char *smt_mc, int val) | ||
390 | { | ||
391 | char linebuf[MAX_LINE_LEN]; | ||
392 | char path[SYSFS_PATH_MAX]; | ||
393 | struct stat statbuf; | ||
394 | |||
395 | if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc)) | ||
396 | return -EINVAL; | ||
397 | |||
398 | snprintf(path, sizeof(path), | ||
399 | PATH_TO_CPU "sched_%s_power_savings", smt_mc); | ||
400 | sprintf(linebuf, "%d", val); | ||
401 | |||
402 | if (stat(path, &statbuf) != 0) | ||
403 | return -ENODEV; | ||
404 | |||
405 | if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
406 | return -1; | ||
407 | return 0; | ||
408 | } | ||
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h new file mode 100644 index 000000000000..8cb797bbceb0 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/sysfs.h | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifndef __CPUPOWER_HELPERS_SYSFS_H__ | ||
2 | #define __CPUPOWER_HELPERS_SYSFS_H__ | ||
3 | |||
4 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
5 | #define MAX_LINE_LEN 255 | ||
6 | #define SYSFS_PATH_MAX 255 | ||
7 | |||
8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | ||
9 | |||
10 | extern int sysfs_is_cpu_online(unsigned int cpu); | ||
11 | |||
12 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | ||
13 | unsigned int idlestate); | ||
14 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, | ||
15 | unsigned int idlestate); | ||
16 | extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu, | ||
17 | unsigned int idlestate); | ||
18 | extern char *sysfs_get_idlestate_name(unsigned int cpu, | ||
19 | unsigned int idlestate); | ||
20 | extern char *sysfs_get_idlestate_desc(unsigned int cpu, | ||
21 | unsigned int idlestate); | ||
22 | extern int sysfs_get_idlestate_count(unsigned int cpu); | ||
23 | |||
24 | extern char *sysfs_get_cpuidle_governor(void); | ||
25 | extern char *sysfs_get_cpuidle_driver(void); | ||
26 | |||
27 | extern int sysfs_get_sched(const char *smt_mc); | ||
28 | extern int sysfs_set_sched(const char *smt_mc, int val); | ||
29 | |||
30 | #endif /* __CPUPOWER_HELPERS_SYSFS_H__ */ | ||
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c new file mode 100644 index 000000000000..4eae2c47ba48 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * ToDo: Needs to be done more properly for AMD/Intel specifics | ||
7 | */ | ||
8 | |||
9 | /* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */ | ||
10 | /* Be careful: Need to pass unsigned to the sort, so that offlined cores are | ||
11 | in the end, but double check for -1 for offlined cpus at other places */ | ||
12 | |||
13 | #include <stdlib.h> | ||
14 | #include <stdio.h> | ||
15 | #include <unistd.h> | ||
16 | #include <errno.h> | ||
17 | #include <fcntl.h> | ||
18 | |||
19 | #include <helpers/helpers.h> | ||
20 | #include <helpers/sysfs.h> | ||
21 | |||
22 | /* returns -1 on failure, 0 on success */ | ||
23 | int sysfs_topology_read_file(unsigned int cpu, const char *fname) | ||
24 | { | ||
25 | unsigned long value; | ||
26 | char linebuf[MAX_LINE_LEN]; | ||
27 | char *endp; | ||
28 | char path[SYSFS_PATH_MAX]; | ||
29 | |||
30 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
31 | cpu, fname); | ||
32 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
33 | return -1; | ||
34 | value = strtoul(linebuf, &endp, 0); | ||
35 | if (endp == linebuf || errno == ERANGE) | ||
36 | return -1; | ||
37 | return value; | ||
38 | } | ||
39 | |||
40 | struct cpuid_core_info { | ||
41 | unsigned int pkg; | ||
42 | unsigned int thread; | ||
43 | unsigned int cpu; | ||
44 | /* flags */ | ||
45 | unsigned int is_online:1; | ||
46 | }; | ||
47 | |||
48 | static int __compare(const void *t1, const void *t2) | ||
49 | { | ||
50 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
51 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
52 | if (top1->pkg < top2->pkg) | ||
53 | return -1; | ||
54 | else if (top1->pkg > top2->pkg) | ||
55 | return 1; | ||
56 | else if (top1->thread < top2->thread) | ||
57 | return -1; | ||
58 | else if (top1->thread > top2->thread) | ||
59 | return 1; | ||
60 | else if (top1->cpu < top2->cpu) | ||
61 | return -1; | ||
62 | else if (top1->cpu > top2->cpu) | ||
63 | return 1; | ||
64 | else | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Returns amount of cpus, negative on error, cpu_top must be | ||
70 | * passed to cpu_topology_release to free resources | ||
71 | * | ||
72 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
73 | */ | ||
74 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
75 | { | ||
76 | int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
77 | |||
78 | cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus); | ||
79 | if (cpu_top->core_info == NULL) | ||
80 | return -ENOMEM; | ||
81 | cpu_top->pkgs = cpu_top->cores = 0; | ||
82 | for (cpu = 0; cpu < cpus; cpu++) { | ||
83 | cpu_top->core_info[cpu].cpu = cpu; | ||
84 | cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); | ||
85 | cpu_top->core_info[cpu].pkg = | ||
86 | sysfs_topology_read_file(cpu, "physical_package_id"); | ||
87 | if ((int)cpu_top->core_info[cpu].pkg != -1 && | ||
88 | cpu_top->core_info[cpu].pkg > cpu_top->pkgs) | ||
89 | cpu_top->pkgs = cpu_top->core_info[cpu].pkg; | ||
90 | cpu_top->core_info[cpu].core = | ||
91 | sysfs_topology_read_file(cpu, "core_id"); | ||
92 | } | ||
93 | cpu_top->pkgs++; | ||
94 | |||
95 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
96 | __compare); | ||
97 | |||
98 | /* Intel's cores count is not consecutively numbered, there may | ||
99 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
100 | * Get amount of cores by counting duplicates in a package | ||
101 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
102 | if (cpu_top->core_info[cpu].core == 0) | ||
103 | cpu_top->cores++; | ||
104 | */ | ||
105 | return cpus; | ||
106 | } | ||
107 | |||
108 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
109 | { | ||
110 | free(cpu_top.core_info); | ||
111 | } | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c new file mode 100644 index 000000000000..202e555988be --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * PCI initialization based on example code from: | ||
7 | * Andreas Herrmann <andreas.herrmann3@amd.com> | ||
8 | */ | ||
9 | |||
10 | #if defined(__i386__) || defined(__x86_64__) | ||
11 | |||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <stdint.h> | ||
15 | #include <time.h> | ||
16 | #include <string.h> | ||
17 | |||
18 | #include <pci/pci.h> | ||
19 | |||
20 | #include "idle_monitor/cpupower-monitor.h" | ||
21 | #include "helpers/helpers.h" | ||
22 | |||
23 | /******** PCI parts could go into own file and get shared ***************/ | ||
24 | |||
25 | #define PCI_NON_PC0_OFFSET 0xb0 | ||
26 | #define PCI_PC1_OFFSET 0xb4 | ||
27 | #define PCI_PC6_OFFSET 0xb8 | ||
28 | |||
29 | #define PCI_MONITOR_ENABLE_REG 0xe0 | ||
30 | |||
31 | #define PCI_NON_PC0_ENABLE_BIT 0 | ||
32 | #define PCI_PC1_ENABLE_BIT 1 | ||
33 | #define PCI_PC6_ENABLE_BIT 2 | ||
34 | |||
35 | #define PCI_NBP1_STAT_OFFSET 0x98 | ||
36 | #define PCI_NBP1_ACTIVE_BIT 2 | ||
37 | #define PCI_NBP1_ENTERED_BIT 1 | ||
38 | |||
39 | #define PCI_NBP1_CAP_OFFSET 0x90 | ||
40 | #define PCI_NBP1_CAPABLE_BIT 31 | ||
41 | |||
42 | #define OVERFLOW_MS 343597 /* 32 bit register filled at 12500 HZ | ||
43 | (1 tick per 80ns) */ | ||
44 | |||
45 | enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1, | ||
46 | AMD_FAM14H_STATE_NUM}; | ||
47 | |||
48 | static int fam14h_get_count_percent(unsigned int self_id, double *percent, | ||
49 | unsigned int cpu); | ||
50 | static int fam14h_nbp1_count(unsigned int id, unsigned long long *count, | ||
51 | unsigned int cpu); | ||
52 | |||
53 | static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = { | ||
54 | { | ||
55 | .name = "!PC0", | ||
56 | .desc = N_("Package in sleep state (PC1 or deeper)"), | ||
57 | .id = NON_PC0, | ||
58 | .range = RANGE_PACKAGE, | ||
59 | .get_count_percent = fam14h_get_count_percent, | ||
60 | }, | ||
61 | { | ||
62 | .name = "PC1", | ||
63 | .desc = N_("Processor Package C1"), | ||
64 | .id = PC1, | ||
65 | .range = RANGE_PACKAGE, | ||
66 | .get_count_percent = fam14h_get_count_percent, | ||
67 | }, | ||
68 | { | ||
69 | .name = "PC6", | ||
70 | .desc = N_("Processor Package C6"), | ||
71 | .id = PC6, | ||
72 | .range = RANGE_PACKAGE, | ||
73 | .get_count_percent = fam14h_get_count_percent, | ||
74 | }, | ||
75 | { | ||
76 | .name = "NBP1", | ||
77 | .desc = N_("North Bridge P1 boolean counter (returns 0 or 1)"), | ||
78 | .id = NBP1, | ||
79 | .range = RANGE_PACKAGE, | ||
80 | .get_count = fam14h_nbp1_count, | ||
81 | }, | ||
82 | }; | ||
83 | |||
84 | static struct pci_access *pci_acc; | ||
85 | static int pci_vendor_id = 0x1022; | ||
86 | static int pci_dev_ids[2] = {0x1716, 0}; | ||
87 | static struct pci_dev *amd_fam14h_pci_dev; | ||
88 | |||
89 | static int nbp1_entered; | ||
90 | |||
91 | struct timespec start_time; | ||
92 | static unsigned long long timediff; | ||
93 | |||
94 | #ifdef DEBUG | ||
95 | struct timespec dbg_time; | ||
96 | long dbg_timediff; | ||
97 | #endif | ||
98 | |||
99 | static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM]; | ||
100 | static unsigned long long *current_count[AMD_FAM14H_STATE_NUM]; | ||
101 | |||
102 | static int amd_fam14h_get_pci_info(struct cstate *state, | ||
103 | unsigned int *pci_offset, | ||
104 | unsigned int *enable_bit, | ||
105 | unsigned int cpu) | ||
106 | { | ||
107 | switch (state->id) { | ||
108 | case NON_PC0: | ||
109 | *enable_bit = PCI_NON_PC0_ENABLE_BIT; | ||
110 | *pci_offset = PCI_NON_PC0_OFFSET; | ||
111 | break; | ||
112 | case PC1: | ||
113 | *enable_bit = PCI_PC1_ENABLE_BIT; | ||
114 | *pci_offset = PCI_PC1_OFFSET; | ||
115 | break; | ||
116 | case PC6: | ||
117 | *enable_bit = PCI_PC6_ENABLE_BIT; | ||
118 | *pci_offset = PCI_PC6_OFFSET; | ||
119 | break; | ||
120 | case NBP1: | ||
121 | *enable_bit = PCI_NBP1_ENTERED_BIT; | ||
122 | *pci_offset = PCI_NBP1_STAT_OFFSET; | ||
123 | break; | ||
124 | default: | ||
125 | return -1; | ||
126 | }; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int amd_fam14h_init(cstate_t *state, unsigned int cpu) | ||
131 | { | ||
132 | int enable_bit, pci_offset, ret; | ||
133 | uint32_t val; | ||
134 | |||
135 | ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu); | ||
136 | if (ret) | ||
137 | return ret; | ||
138 | |||
139 | /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */ | ||
140 | if (state->id == NBP1) { | ||
141 | val = pci_read_long(amd_fam14h_pci_dev, pci_offset); | ||
142 | val |= 1 << enable_bit; | ||
143 | val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | /* Enable monitor */ | ||
148 | val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG); | ||
149 | dprint("Init %s: read at offset: 0x%x val: %u\n", state->name, | ||
150 | PCI_MONITOR_ENABLE_REG, (unsigned int) val); | ||
151 | val |= 1 << enable_bit; | ||
152 | pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val); | ||
153 | |||
154 | dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n", | ||
155 | state->name, PCI_MONITOR_ENABLE_REG, enable_bit, | ||
156 | (unsigned int) val, cpu); | ||
157 | |||
158 | /* Set counter to zero */ | ||
159 | pci_write_long(amd_fam14h_pci_dev, pci_offset, 0); | ||
160 | previous_count[state->id][cpu] = 0; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int amd_fam14h_disable(cstate_t *state, unsigned int cpu) | ||
166 | { | ||
167 | int enable_bit, pci_offset, ret; | ||
168 | uint32_t val; | ||
169 | |||
170 | ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | val = pci_read_long(amd_fam14h_pci_dev, pci_offset); | ||
175 | dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val); | ||
176 | if (state->id == NBP1) { | ||
177 | /* was the bit whether NBP1 got entered set? */ | ||
178 | nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) | | ||
179 | (val & (1 << PCI_NBP1_ENTERED_BIT)); | ||
180 | |||
181 | dprint("NBP1 was %sentered - 0x%x - enable_bit: " | ||
182 | "%d - pci_offset: 0x%x\n", | ||
183 | nbp1_entered ? "" : "not ", | ||
184 | val, enable_bit, pci_offset); | ||
185 | return ret; | ||
186 | } | ||
187 | current_count[state->id][cpu] = val; | ||
188 | |||
189 | dprint("%s: Current - %llu (%u)\n", state->name, | ||
190 | current_count[state->id][cpu], cpu); | ||
191 | dprint("%s: Previous - %llu (%u)\n", state->name, | ||
192 | previous_count[state->id][cpu], cpu); | ||
193 | |||
194 | val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG); | ||
195 | val &= ~(1 << enable_bit); | ||
196 | pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int fam14h_nbp1_count(unsigned int id, unsigned long long *count, | ||
202 | unsigned int cpu) | ||
203 | { | ||
204 | if (id == NBP1) { | ||
205 | if (nbp1_entered) | ||
206 | *count = 1; | ||
207 | else | ||
208 | *count = 0; | ||
209 | return 0; | ||
210 | } | ||
211 | return -1; | ||
212 | } | ||
213 | static int fam14h_get_count_percent(unsigned int id, double *percent, | ||
214 | unsigned int cpu) | ||
215 | { | ||
216 | unsigned long diff; | ||
217 | |||
218 | if (id >= AMD_FAM14H_STATE_NUM) | ||
219 | return -1; | ||
220 | /* residency count in 80ns -> divide through 12.5 to get us residency */ | ||
221 | diff = current_count[id][cpu] - previous_count[id][cpu]; | ||
222 | |||
223 | if (timediff == 0) | ||
224 | *percent = 0.0; | ||
225 | else | ||
226 | *percent = 100.0 * diff / timediff / 12.5; | ||
227 | |||
228 | dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n", | ||
229 | timediff, diff * 10 / 125, *percent); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int amd_fam14h_start(void) | ||
235 | { | ||
236 | int num, cpu; | ||
237 | clock_gettime(CLOCK_REALTIME, &start_time); | ||
238 | for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) { | ||
239 | for (cpu = 0; cpu < cpu_count; cpu++) | ||
240 | amd_fam14h_init(&amd_fam14h_cstates[num], cpu); | ||
241 | } | ||
242 | #ifdef DEBUG | ||
243 | clock_gettime(CLOCK_REALTIME, &dbg_time); | ||
244 | dbg_timediff = timespec_diff_us(start_time, dbg_time); | ||
245 | dprint("Enabling counters took: %lu us\n", | ||
246 | dbg_timediff); | ||
247 | #endif | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int amd_fam14h_stop(void) | ||
252 | { | ||
253 | int num, cpu; | ||
254 | struct timespec end_time; | ||
255 | |||
256 | clock_gettime(CLOCK_REALTIME, &end_time); | ||
257 | |||
258 | for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) { | ||
259 | for (cpu = 0; cpu < cpu_count; cpu++) | ||
260 | amd_fam14h_disable(&amd_fam14h_cstates[num], cpu); | ||
261 | } | ||
262 | #ifdef DEBUG | ||
263 | clock_gettime(CLOCK_REALTIME, &dbg_time); | ||
264 | dbg_timediff = timespec_diff_us(end_time, dbg_time); | ||
265 | dprint("Disabling counters took: %lu ns\n", dbg_timediff); | ||
266 | #endif | ||
267 | timediff = timespec_diff_us(start_time, end_time); | ||
268 | if (timediff / 1000 > OVERFLOW_MS) | ||
269 | print_overflow_err((unsigned int)timediff / 1000000, | ||
270 | OVERFLOW_MS / 1000); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int is_nbp1_capable(void) | ||
276 | { | ||
277 | uint32_t val; | ||
278 | val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET); | ||
279 | return val & (1 << 31); | ||
280 | } | ||
281 | |||
282 | struct cpuidle_monitor *amd_fam14h_register(void) | ||
283 | { | ||
284 | int num; | ||
285 | |||
286 | if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) | ||
287 | return NULL; | ||
288 | |||
289 | if (cpupower_cpu_info.family == 0x14) { | ||
290 | if (cpu_count <= 0 || cpu_count > 2) { | ||
291 | fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n", | ||
292 | cpu_count); | ||
293 | return NULL; | ||
294 | } | ||
295 | } else | ||
296 | return NULL; | ||
297 | |||
298 | /* We do not alloc for nbp1 machine wide counter */ | ||
299 | for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) { | ||
300 | previous_count[num] = calloc(cpu_count, | ||
301 | sizeof(unsigned long long)); | ||
302 | current_count[num] = calloc(cpu_count, | ||
303 | sizeof(unsigned long long)); | ||
304 | } | ||
305 | |||
306 | amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids); | ||
307 | if (amd_fam14h_pci_dev == NULL || pci_acc == NULL) | ||
308 | return NULL; | ||
309 | |||
310 | if (!is_nbp1_capable()) | ||
311 | amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1; | ||
312 | |||
313 | amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name); | ||
314 | return &amd_fam14h_monitor; | ||
315 | } | ||
316 | |||
317 | static void amd_fam14h_unregister(void) | ||
318 | { | ||
319 | int num; | ||
320 | for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) { | ||
321 | free(previous_count[num]); | ||
322 | free(current_count[num]); | ||
323 | } | ||
324 | pci_cleanup(pci_acc); | ||
325 | } | ||
326 | |||
327 | struct cpuidle_monitor amd_fam14h_monitor = { | ||
328 | .name = "Ontario", | ||
329 | .hw_states = amd_fam14h_cstates, | ||
330 | .hw_states_num = AMD_FAM14H_STATE_NUM, | ||
331 | .start = amd_fam14h_start, | ||
332 | .stop = amd_fam14h_stop, | ||
333 | .do_register = amd_fam14h_register, | ||
334 | .unregister = amd_fam14h_unregister, | ||
335 | .needs_root = 1, | ||
336 | .overflow_s = OVERFLOW_MS / 1000, | ||
337 | }; | ||
338 | #endif /* #if defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c new file mode 100644 index 000000000000..bcd22a1a3970 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <stdint.h> | ||
11 | #include <string.h> | ||
12 | #include <limits.h> | ||
13 | |||
14 | #include "helpers/sysfs.h" | ||
15 | #include "helpers/helpers.h" | ||
16 | #include "idle_monitor/cpupower-monitor.h" | ||
17 | |||
18 | #define CPUIDLE_STATES_MAX 10 | ||
19 | static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX]; | ||
20 | struct cpuidle_monitor cpuidle_sysfs_monitor; | ||
21 | |||
22 | static unsigned long long **previous_count; | ||
23 | static unsigned long long **current_count; | ||
24 | struct timespec start_time; | ||
25 | static unsigned long long timediff; | ||
26 | |||
27 | static int cpuidle_get_count_percent(unsigned int id, double *percent, | ||
28 | unsigned int cpu) | ||
29 | { | ||
30 | unsigned long long statediff = current_count[cpu][id] | ||
31 | - previous_count[cpu][id]; | ||
32 | dprint("%s: - diff: %llu - percent: %f (%u)\n", | ||
33 | cpuidle_cstates[id].name, timediff, *percent, cpu); | ||
34 | |||
35 | if (timediff == 0) | ||
36 | *percent = 0.0; | ||
37 | else | ||
38 | *percent = ((100.0 * statediff) / timediff); | ||
39 | |||
40 | dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n", | ||
41 | cpuidle_cstates[id].name, timediff, statediff, *percent, cpu); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int cpuidle_start(void) | ||
47 | { | ||
48 | int cpu, state; | ||
49 | clock_gettime(CLOCK_REALTIME, &start_time); | ||
50 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
51 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | ||
52 | state++) { | ||
53 | previous_count[cpu][state] = | ||
54 | sysfs_get_idlestate_time(cpu, state); | ||
55 | dprint("CPU %d - State: %d - Val: %llu\n", | ||
56 | cpu, state, previous_count[cpu][state]); | ||
57 | } | ||
58 | }; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int cpuidle_stop(void) | ||
63 | { | ||
64 | int cpu, state; | ||
65 | struct timespec end_time; | ||
66 | clock_gettime(CLOCK_REALTIME, &end_time); | ||
67 | timediff = timespec_diff_us(start_time, end_time); | ||
68 | |||
69 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
70 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | ||
71 | state++) { | ||
72 | current_count[cpu][state] = | ||
73 | sysfs_get_idlestate_time(cpu, state); | ||
74 | dprint("CPU %d - State: %d - Val: %llu\n", | ||
75 | cpu, state, previous_count[cpu][state]); | ||
76 | } | ||
77 | }; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | void fix_up_intel_idle_driver_name(char *tmp, int num) | ||
82 | { | ||
83 | /* fix up cpuidle name for intel idle driver */ | ||
84 | if (!strncmp(tmp, "NHM-", 4)) { | ||
85 | switch (num) { | ||
86 | case 1: | ||
87 | strcpy(tmp, "C1"); | ||
88 | break; | ||
89 | case 2: | ||
90 | strcpy(tmp, "C3"); | ||
91 | break; | ||
92 | case 3: | ||
93 | strcpy(tmp, "C6"); | ||
94 | break; | ||
95 | } | ||
96 | } else if (!strncmp(tmp, "SNB-", 4)) { | ||
97 | switch (num) { | ||
98 | case 1: | ||
99 | strcpy(tmp, "C1"); | ||
100 | break; | ||
101 | case 2: | ||
102 | strcpy(tmp, "C3"); | ||
103 | break; | ||
104 | case 3: | ||
105 | strcpy(tmp, "C6"); | ||
106 | break; | ||
107 | case 4: | ||
108 | strcpy(tmp, "C7"); | ||
109 | break; | ||
110 | } | ||
111 | } else if (!strncmp(tmp, "ATM-", 4)) { | ||
112 | switch (num) { | ||
113 | case 1: | ||
114 | strcpy(tmp, "C1"); | ||
115 | break; | ||
116 | case 2: | ||
117 | strcpy(tmp, "C2"); | ||
118 | break; | ||
119 | case 3: | ||
120 | strcpy(tmp, "C4"); | ||
121 | break; | ||
122 | case 4: | ||
123 | strcpy(tmp, "C6"); | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static struct cpuidle_monitor *cpuidle_register(void) | ||
130 | { | ||
131 | int num; | ||
132 | char *tmp; | ||
133 | |||
134 | /* Assume idle state count is the same for all CPUs */ | ||
135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); | ||
136 | |||
137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) | ||
138 | return NULL; | ||
139 | |||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | ||
141 | tmp = sysfs_get_idlestate_name(0, num); | ||
142 | if (tmp == NULL) | ||
143 | continue; | ||
144 | |||
145 | fix_up_intel_idle_driver_name(tmp, num); | ||
146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); | ||
147 | free(tmp); | ||
148 | |||
149 | tmp = sysfs_get_idlestate_desc(0, num); | ||
150 | if (tmp == NULL) | ||
151 | continue; | ||
152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); | ||
153 | free(tmp); | ||
154 | |||
155 | cpuidle_cstates[num].range = RANGE_THREAD; | ||
156 | cpuidle_cstates[num].id = num; | ||
157 | cpuidle_cstates[num].get_count_percent = | ||
158 | cpuidle_get_count_percent; | ||
159 | }; | ||
160 | |||
161 | /* Free this at program termination */ | ||
162 | previous_count = malloc(sizeof(long long *) * cpu_count); | ||
163 | current_count = malloc(sizeof(long long *) * cpu_count); | ||
164 | for (num = 0; num < cpu_count; num++) { | ||
165 | previous_count[num] = malloc(sizeof(long long) * | ||
166 | cpuidle_sysfs_monitor.hw_states_num); | ||
167 | current_count[num] = malloc(sizeof(long long) * | ||
168 | cpuidle_sysfs_monitor.hw_states_num); | ||
169 | } | ||
170 | |||
171 | cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name); | ||
172 | return &cpuidle_sysfs_monitor; | ||
173 | } | ||
174 | |||
175 | void cpuidle_unregister(void) | ||
176 | { | ||
177 | int num; | ||
178 | |||
179 | for (num = 0; num < cpu_count; num++) { | ||
180 | free(previous_count[num]); | ||
181 | free(current_count[num]); | ||
182 | } | ||
183 | free(previous_count); | ||
184 | free(current_count); | ||
185 | } | ||
186 | |||
187 | struct cpuidle_monitor cpuidle_sysfs_monitor = { | ||
188 | .name = "Idle_Stats", | ||
189 | .hw_states = cpuidle_cstates, | ||
190 | .start = cpuidle_start, | ||
191 | .stop = cpuidle_stop, | ||
192 | .do_register = cpuidle_register, | ||
193 | .unregister = cpuidle_unregister, | ||
194 | .needs_root = 0, | ||
195 | .overflow_s = UINT_MAX, | ||
196 | }; | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c new file mode 100644 index 000000000000..0d6571e418db --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <unistd.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <time.h> | ||
16 | #include <signal.h> | ||
17 | #include <sys/types.h> | ||
18 | #include <sys/wait.h> | ||
19 | #include <libgen.h> | ||
20 | |||
21 | #include "idle_monitor/cpupower-monitor.h" | ||
22 | #include "idle_monitor/idle_monitors.h" | ||
23 | #include "helpers/helpers.h" | ||
24 | |||
25 | /* Define pointers to all monitors. */ | ||
26 | #define DEF(x) & x ## _monitor , | ||
27 | struct cpuidle_monitor *all_monitors[] = { | ||
28 | #include "idle_monitors.def" | ||
29 | 0 | ||
30 | }; | ||
31 | |||
32 | static struct cpuidle_monitor *monitors[MONITORS_MAX]; | ||
33 | static unsigned int avail_monitors; | ||
34 | |||
35 | static char *progname; | ||
36 | |||
37 | enum operation_mode_e { list = 1, show, show_all }; | ||
38 | static int mode; | ||
39 | static int interval = 1; | ||
40 | static char *show_monitors_param; | ||
41 | static struct cpupower_topology cpu_top; | ||
42 | |||
43 | /* ToDo: Document this in the manpage */ | ||
44 | static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; | ||
45 | |||
46 | static void print_wrong_arg_exit(void) | ||
47 | { | ||
48 | printf(_("invalid or unknown argument\n")); | ||
49 | exit(EXIT_FAILURE); | ||
50 | } | ||
51 | |||
52 | long long timespec_diff_us(struct timespec start, struct timespec end) | ||
53 | { | ||
54 | struct timespec temp; | ||
55 | if ((end.tv_nsec - start.tv_nsec) < 0) { | ||
56 | temp.tv_sec = end.tv_sec - start.tv_sec - 1; | ||
57 | temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; | ||
58 | } else { | ||
59 | temp.tv_sec = end.tv_sec - start.tv_sec; | ||
60 | temp.tv_nsec = end.tv_nsec - start.tv_nsec; | ||
61 | } | ||
62 | return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); | ||
63 | } | ||
64 | |||
65 | void print_n_spaces(int n) | ||
66 | { | ||
67 | int x; | ||
68 | for (x = 0; x < n; x++) | ||
69 | printf(" "); | ||
70 | } | ||
71 | |||
72 | /* size of s must be at least n + 1 */ | ||
73 | int fill_string_with_spaces(char *s, int n) | ||
74 | { | ||
75 | int len = strlen(s); | ||
76 | if (len > n) | ||
77 | return -1; | ||
78 | for (; len < n; len++) | ||
79 | s[len] = ' '; | ||
80 | s[len] = '\0'; | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | void print_header(int topology_depth) | ||
85 | { | ||
86 | int unsigned mon; | ||
87 | int state, need_len, pr_mon_len; | ||
88 | cstate_t s; | ||
89 | char buf[128] = ""; | ||
90 | int percent_width = 4; | ||
91 | |||
92 | fill_string_with_spaces(buf, topology_depth * 5 - 1); | ||
93 | printf("%s|", buf); | ||
94 | |||
95 | for (mon = 0; mon < avail_monitors; mon++) { | ||
96 | pr_mon_len = 0; | ||
97 | need_len = monitors[mon]->hw_states_num * (percent_width + 3) | ||
98 | - 1; | ||
99 | if (mon != 0) { | ||
100 | printf("|| "); | ||
101 | need_len--; | ||
102 | } | ||
103 | sprintf(buf, "%s", monitors[mon]->name); | ||
104 | fill_string_with_spaces(buf, need_len); | ||
105 | printf("%s", buf); | ||
106 | } | ||
107 | printf("\n"); | ||
108 | |||
109 | if (topology_depth > 2) | ||
110 | printf("PKG |"); | ||
111 | if (topology_depth > 1) | ||
112 | printf("CORE|"); | ||
113 | if (topology_depth > 0) | ||
114 | printf("CPU |"); | ||
115 | |||
116 | for (mon = 0; mon < avail_monitors; mon++) { | ||
117 | if (mon != 0) | ||
118 | printf("|| "); | ||
119 | else | ||
120 | printf(" "); | ||
121 | for (state = 0; state < monitors[mon]->hw_states_num; state++) { | ||
122 | if (state != 0) | ||
123 | printf(" | "); | ||
124 | s = monitors[mon]->hw_states[state]; | ||
125 | sprintf(buf, "%s", s.name); | ||
126 | fill_string_with_spaces(buf, percent_width); | ||
127 | printf("%s", buf); | ||
128 | } | ||
129 | printf(" "); | ||
130 | } | ||
131 | printf("\n"); | ||
132 | } | ||
133 | |||
134 | |||
135 | void print_results(int topology_depth, int cpu) | ||
136 | { | ||
137 | unsigned int mon; | ||
138 | int state, ret; | ||
139 | double percent; | ||
140 | unsigned long long result; | ||
141 | cstate_t s; | ||
142 | |||
143 | /* Be careful CPUs may got resorted for pkg value do not just use cpu */ | ||
144 | if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) | ||
145 | return; | ||
146 | |||
147 | if (topology_depth > 2) | ||
148 | printf("%4d|", cpu_top.core_info[cpu].pkg); | ||
149 | if (topology_depth > 1) | ||
150 | printf("%4d|", cpu_top.core_info[cpu].core); | ||
151 | if (topology_depth > 0) | ||
152 | printf("%4d|", cpu_top.core_info[cpu].cpu); | ||
153 | |||
154 | for (mon = 0; mon < avail_monitors; mon++) { | ||
155 | if (mon != 0) | ||
156 | printf("||"); | ||
157 | |||
158 | for (state = 0; state < monitors[mon]->hw_states_num; state++) { | ||
159 | if (state != 0) | ||
160 | printf("|"); | ||
161 | |||
162 | s = monitors[mon]->hw_states[state]; | ||
163 | |||
164 | if (s.get_count_percent) { | ||
165 | ret = s.get_count_percent(s.id, &percent, | ||
166 | cpu_top.core_info[cpu].cpu); | ||
167 | if (ret) | ||
168 | printf("******"); | ||
169 | else if (percent >= 100.0) | ||
170 | printf("%6.1f", percent); | ||
171 | else | ||
172 | printf("%6.2f", percent); | ||
173 | } else if (s.get_count) { | ||
174 | ret = s.get_count(s.id, &result, | ||
175 | cpu_top.core_info[cpu].cpu); | ||
176 | if (ret) | ||
177 | printf("******"); | ||
178 | else | ||
179 | printf("%6llu", result); | ||
180 | } else { | ||
181 | printf(_("Monitor %s, Counter %s has no count " | ||
182 | "function. Implementation error\n"), | ||
183 | monitors[mon]->name, s.name); | ||
184 | exit(EXIT_FAILURE); | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | /* | ||
189 | * The monitor could still provide useful data, for example | ||
190 | * AMD HW counters partly sit in PCI config space. | ||
191 | * It's up to the monitor plug-in to check .is_online, this one | ||
192 | * is just for additional info. | ||
193 | */ | ||
194 | if (!cpu_top.core_info[cpu].is_online) { | ||
195 | printf(_(" *is offline\n")); | ||
196 | return; | ||
197 | } else | ||
198 | printf("\n"); | ||
199 | } | ||
200 | |||
201 | |||
202 | /* param: string passed by -m param (The list of monitors to show) | ||
203 | * | ||
204 | * Monitors must have been registered already, matching monitors | ||
205 | * are picked out and available monitors array is overridden | ||
206 | * with matching ones | ||
207 | * | ||
208 | * Monitors get sorted in the same order the user passes them | ||
209 | */ | ||
210 | |||
211 | static void parse_monitor_param(char *param) | ||
212 | { | ||
213 | unsigned int num; | ||
214 | int mon, hits = 0; | ||
215 | char *tmp = param, *token; | ||
216 | struct cpuidle_monitor *tmp_mons[MONITORS_MAX]; | ||
217 | |||
218 | |||
219 | for (mon = 0; mon < MONITORS_MAX; mon++, tmp = NULL) { | ||
220 | token = strtok(tmp, ","); | ||
221 | if (token == NULL) | ||
222 | break; | ||
223 | if (strlen(token) >= MONITOR_NAME_LEN) { | ||
224 | printf(_("%s: max monitor name length" | ||
225 | " (%d) exceeded\n"), token, MONITOR_NAME_LEN); | ||
226 | continue; | ||
227 | } | ||
228 | |||
229 | for (num = 0; num < avail_monitors; num++) { | ||
230 | if (!strcmp(monitors[num]->name, token)) { | ||
231 | dprint("Found requested monitor: %s\n", token); | ||
232 | tmp_mons[hits] = monitors[num]; | ||
233 | hits++; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | if (hits == 0) { | ||
238 | printf(_("No matching monitor found in %s, " | ||
239 | "try -l option\n"), param); | ||
240 | exit(EXIT_FAILURE); | ||
241 | } | ||
242 | /* Override detected/registerd monitors array with requested one */ | ||
243 | memcpy(monitors, tmp_mons, | ||
244 | sizeof(struct cpuidle_monitor *) * MONITORS_MAX); | ||
245 | avail_monitors = hits; | ||
246 | } | ||
247 | |||
248 | void list_monitors(void) | ||
249 | { | ||
250 | unsigned int mon; | ||
251 | int state; | ||
252 | cstate_t s; | ||
253 | |||
254 | for (mon = 0; mon < avail_monitors; mon++) { | ||
255 | printf(_("Monitor \"%s\" (%d states) - Might overflow after %u " | ||
256 | "s\n"), | ||
257 | monitors[mon]->name, monitors[mon]->hw_states_num, | ||
258 | monitors[mon]->overflow_s); | ||
259 | |||
260 | for (state = 0; state < monitors[mon]->hw_states_num; state++) { | ||
261 | s = monitors[mon]->hw_states[state]; | ||
262 | /* | ||
263 | * ToDo show more state capabilities: | ||
264 | * percent, time (granlarity) | ||
265 | */ | ||
266 | printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range], | ||
267 | gettext(s.desc)); | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | int fork_it(char **argv) | ||
273 | { | ||
274 | int status; | ||
275 | unsigned int num; | ||
276 | unsigned long long timediff; | ||
277 | pid_t child_pid; | ||
278 | struct timespec start, end; | ||
279 | |||
280 | child_pid = fork(); | ||
281 | clock_gettime(CLOCK_REALTIME, &start); | ||
282 | |||
283 | for (num = 0; num < avail_monitors; num++) | ||
284 | monitors[num]->start(); | ||
285 | |||
286 | if (!child_pid) { | ||
287 | /* child */ | ||
288 | execvp(argv[0], argv); | ||
289 | } else { | ||
290 | /* parent */ | ||
291 | if (child_pid == -1) { | ||
292 | perror("fork"); | ||
293 | exit(1); | ||
294 | } | ||
295 | |||
296 | signal(SIGINT, SIG_IGN); | ||
297 | signal(SIGQUIT, SIG_IGN); | ||
298 | if (waitpid(child_pid, &status, 0) == -1) { | ||
299 | perror("wait"); | ||
300 | exit(1); | ||
301 | } | ||
302 | } | ||
303 | clock_gettime(CLOCK_REALTIME, &end); | ||
304 | for (num = 0; num < avail_monitors; num++) | ||
305 | monitors[num]->stop(); | ||
306 | |||
307 | timediff = timespec_diff_us(start, end); | ||
308 | if (WIFEXITED(status)) | ||
309 | printf(_("%s took %.5f seconds and exited with status %d\n"), | ||
310 | argv[0], timediff / (1000.0 * 1000), | ||
311 | WEXITSTATUS(status)); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | int do_interval_measure(int i) | ||
316 | { | ||
317 | unsigned int num; | ||
318 | |||
319 | for (num = 0; num < avail_monitors; num++) { | ||
320 | dprint("HW C-state residency monitor: %s - States: %d\n", | ||
321 | monitors[num]->name, monitors[num]->hw_states_num); | ||
322 | monitors[num]->start(); | ||
323 | } | ||
324 | sleep(i); | ||
325 | for (num = 0; num < avail_monitors; num++) | ||
326 | monitors[num]->stop(); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static void cmdline(int argc, char *argv[]) | ||
332 | { | ||
333 | int opt; | ||
334 | progname = basename(argv[0]); | ||
335 | |||
336 | while ((opt = getopt(argc, argv, "+li:m:")) != -1) { | ||
337 | switch (opt) { | ||
338 | case 'l': | ||
339 | if (mode) | ||
340 | print_wrong_arg_exit(); | ||
341 | mode = list; | ||
342 | break; | ||
343 | case 'i': | ||
344 | /* only allow -i with -m or no option */ | ||
345 | if (mode && mode != show) | ||
346 | print_wrong_arg_exit(); | ||
347 | interval = atoi(optarg); | ||
348 | break; | ||
349 | case 'm': | ||
350 | if (mode) | ||
351 | print_wrong_arg_exit(); | ||
352 | mode = show; | ||
353 | show_monitors_param = optarg; | ||
354 | break; | ||
355 | default: | ||
356 | print_wrong_arg_exit(); | ||
357 | } | ||
358 | } | ||
359 | if (!mode) | ||
360 | mode = show_all; | ||
361 | } | ||
362 | |||
363 | int cmd_monitor(int argc, char **argv) | ||
364 | { | ||
365 | unsigned int num; | ||
366 | struct cpuidle_monitor *test_mon; | ||
367 | int cpu; | ||
368 | |||
369 | cmdline(argc, argv); | ||
370 | cpu_count = get_cpu_topology(&cpu_top); | ||
371 | if (cpu_count < 0) { | ||
372 | printf(_("Cannot read number of available processors\n")); | ||
373 | return EXIT_FAILURE; | ||
374 | } | ||
375 | |||
376 | /* Default is: monitor all CPUs */ | ||
377 | if (bitmask_isallclear(cpus_chosen)) | ||
378 | bitmask_setall(cpus_chosen); | ||
379 | |||
380 | dprint("System has up to %d CPU cores\n", cpu_count); | ||
381 | |||
382 | for (num = 0; all_monitors[num]; num++) { | ||
383 | dprint("Try to register: %s\n", all_monitors[num]->name); | ||
384 | test_mon = all_monitors[num]->do_register(); | ||
385 | if (test_mon) { | ||
386 | if (test_mon->needs_root && !run_as_root) { | ||
387 | fprintf(stderr, _("Available monitor %s needs " | ||
388 | "root access\n"), test_mon->name); | ||
389 | continue; | ||
390 | } | ||
391 | monitors[avail_monitors] = test_mon; | ||
392 | dprint("%s registered\n", all_monitors[num]->name); | ||
393 | avail_monitors++; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if (avail_monitors == 0) { | ||
398 | printf(_("No HW Cstate monitors found\n")); | ||
399 | return 1; | ||
400 | } | ||
401 | |||
402 | if (mode == list) { | ||
403 | list_monitors(); | ||
404 | exit(EXIT_SUCCESS); | ||
405 | } | ||
406 | |||
407 | if (mode == show) | ||
408 | parse_monitor_param(show_monitors_param); | ||
409 | |||
410 | dprint("Packages: %d - Cores: %d - CPUs: %d\n", | ||
411 | cpu_top.pkgs, cpu_top.cores, cpu_count); | ||
412 | |||
413 | /* | ||
414 | * if any params left, it must be a command to fork | ||
415 | */ | ||
416 | if (argc - optind) | ||
417 | fork_it(argv + optind); | ||
418 | else | ||
419 | do_interval_measure(interval); | ||
420 | |||
421 | /* ToDo: Topology parsing needs fixing first to do | ||
422 | this more generically */ | ||
423 | if (cpu_top.pkgs > 1) | ||
424 | print_header(3); | ||
425 | else | ||
426 | print_header(1); | ||
427 | |||
428 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
429 | if (cpu_top.pkgs > 1) | ||
430 | print_results(3, cpu); | ||
431 | else | ||
432 | print_results(1, cpu); | ||
433 | } | ||
434 | |||
435 | for (num = 0; num < avail_monitors; num++) | ||
436 | monitors[num]->unregister(); | ||
437 | |||
438 | cpu_topology_release(cpu_top); | ||
439 | return 0; | ||
440 | } | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h new file mode 100644 index 000000000000..9312ee1f2dbc --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef __CPUIDLE_INFO_HW__ | ||
9 | #define __CPUIDLE_INFO_HW__ | ||
10 | |||
11 | #include <stdarg.h> | ||
12 | #include <time.h> | ||
13 | |||
14 | #include "idle_monitor/idle_monitors.h" | ||
15 | |||
16 | #define MONITORS_MAX 20 | ||
17 | #define MONITOR_NAME_LEN 20 | ||
18 | #define CSTATE_NAME_LEN 5 | ||
19 | #define CSTATE_DESC_LEN 60 | ||
20 | |||
21 | int cpu_count; | ||
22 | |||
23 | /* Hard to define the right names ...: */ | ||
24 | enum power_range_e { | ||
25 | RANGE_THREAD, /* Lowest in topology hierarcy, AMD: core, Intel: thread | ||
26 | kernel sysfs: cpu */ | ||
27 | RANGE_CORE, /* AMD: unit, Intel: core, kernel_sysfs: core_id */ | ||
28 | RANGE_PACKAGE, /* Package, processor socket */ | ||
29 | RANGE_MACHINE, /* Machine, platform wide */ | ||
30 | RANGE_MAX }; | ||
31 | |||
32 | typedef struct cstate { | ||
33 | int id; | ||
34 | enum power_range_e range; | ||
35 | char name[CSTATE_NAME_LEN]; | ||
36 | char desc[CSTATE_DESC_LEN]; | ||
37 | |||
38 | /* either provide a percentage or a general count */ | ||
39 | int (*get_count_percent)(unsigned int self_id, double *percent, | ||
40 | unsigned int cpu); | ||
41 | int (*get_count)(unsigned int self_id, unsigned long long *count, | ||
42 | unsigned int cpu); | ||
43 | } cstate_t; | ||
44 | |||
45 | struct cpuidle_monitor { | ||
46 | /* Name must not contain whitespaces */ | ||
47 | char name[MONITOR_NAME_LEN]; | ||
48 | int name_len; | ||
49 | int hw_states_num; | ||
50 | cstate_t *hw_states; | ||
51 | int (*start) (void); | ||
52 | int (*stop) (void); | ||
53 | struct cpuidle_monitor* (*do_register) (void); | ||
54 | void (*unregister)(void); | ||
55 | unsigned int overflow_s; | ||
56 | int needs_root; | ||
57 | }; | ||
58 | |||
59 | extern long long timespec_diff_us(struct timespec start, struct timespec end); | ||
60 | |||
61 | #define print_overflow_err(mes, ov) \ | ||
62 | { \ | ||
63 | fprintf(stderr, gettext("Measure took %u seconds, but registers could " \ | ||
64 | "overflow at %u seconds, results " \ | ||
65 | "could be inaccurate\n"), mes, ov); \ | ||
66 | } | ||
67 | |||
68 | #endif /* __CPUIDLE_INFO_HW__ */ | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def new file mode 100644 index 000000000000..e3f8d9b2b18f --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def | |||
@@ -0,0 +1,7 @@ | |||
1 | #if defined(__i386__) || defined(__x86_64__) | ||
2 | DEF(amd_fam14h) | ||
3 | DEF(intel_nhm) | ||
4 | DEF(intel_snb) | ||
5 | DEF(mperf) | ||
6 | #endif | ||
7 | DEF(cpuidle_sysfs) | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h new file mode 100644 index 000000000000..4fcdeb1e07e8 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on the idea from Michael Matz <matz@suse.de> | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef _CPUIDLE_IDLE_MONITORS_H_ | ||
11 | #define _CPUIDLE_IDLE_MONITORS_H_ | ||
12 | |||
13 | #define DEF(x) extern struct cpuidle_monitor x ##_monitor; | ||
14 | #include "idle_monitors.def" | ||
15 | #undef DEF | ||
16 | extern struct cpuidle_monitor *all_monitors[]; | ||
17 | |||
18 | #endif /* _CPUIDLE_IDLE_MONITORS_H_ */ | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c new file mode 100644 index 000000000000..5650ab5a2c20 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #if defined(__i386__) || defined(__x86_64__) | ||
8 | |||
9 | #include <stdio.h> | ||
10 | #include <stdint.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | #include <limits.h> | ||
14 | |||
15 | #include <cpufreq.h> | ||
16 | |||
17 | #include "helpers/helpers.h" | ||
18 | #include "idle_monitor/cpupower-monitor.h" | ||
19 | |||
20 | #define MSR_APERF 0xE8 | ||
21 | #define MSR_MPERF 0xE7 | ||
22 | |||
23 | #define MSR_TSC 0x10 | ||
24 | |||
25 | #define MSR_AMD_HWCR 0xc0010015 | ||
26 | |||
27 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; | ||
28 | |||
29 | static int mperf_get_count_percent(unsigned int self_id, double *percent, | ||
30 | unsigned int cpu); | ||
31 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | ||
32 | unsigned int cpu); | ||
33 | static struct timespec time_start, time_end; | ||
34 | |||
35 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | ||
36 | { | ||
37 | .name = "C0", | ||
38 | .desc = N_("Processor Core not idle"), | ||
39 | .id = C0, | ||
40 | .range = RANGE_THREAD, | ||
41 | .get_count_percent = mperf_get_count_percent, | ||
42 | }, | ||
43 | { | ||
44 | .name = "Cx", | ||
45 | .desc = N_("Processor Core in an idle state"), | ||
46 | .id = Cx, | ||
47 | .range = RANGE_THREAD, | ||
48 | .get_count_percent = mperf_get_count_percent, | ||
49 | }, | ||
50 | |||
51 | { | ||
52 | .name = "Freq", | ||
53 | .desc = N_("Average Frequency (including boost) in MHz"), | ||
54 | .id = AVG_FREQ, | ||
55 | .range = RANGE_THREAD, | ||
56 | .get_count = mperf_get_count_freq, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; | ||
61 | static int max_freq_mode; | ||
62 | /* | ||
63 | * The max frequency mperf is ticking at (in C0), either retrieved via: | ||
64 | * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency | ||
65 | * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time | ||
66 | * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) | ||
67 | */ | ||
68 | static unsigned long max_frequency; | ||
69 | |||
70 | static unsigned long long tsc_at_measure_start; | ||
71 | static unsigned long long tsc_at_measure_end; | ||
72 | static unsigned long long *mperf_previous_count; | ||
73 | static unsigned long long *aperf_previous_count; | ||
74 | static unsigned long long *mperf_current_count; | ||
75 | static unsigned long long *aperf_current_count; | ||
76 | |||
77 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | ||
78 | static int *is_valid; | ||
79 | |||
80 | static int mperf_get_tsc(unsigned long long *tsc) | ||
81 | { | ||
82 | int ret; | ||
83 | ret = read_msr(0, MSR_TSC, tsc); | ||
84 | if (ret) | ||
85 | dprint("Reading TSC MSR failed, returning %llu\n", *tsc); | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | static int mperf_init_stats(unsigned int cpu) | ||
90 | { | ||
91 | unsigned long long val; | ||
92 | int ret; | ||
93 | |||
94 | ret = read_msr(cpu, MSR_APERF, &val); | ||
95 | aperf_previous_count[cpu] = val; | ||
96 | ret |= read_msr(cpu, MSR_MPERF, &val); | ||
97 | mperf_previous_count[cpu] = val; | ||
98 | is_valid[cpu] = !ret; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int mperf_measure_stats(unsigned int cpu) | ||
104 | { | ||
105 | unsigned long long val; | ||
106 | int ret; | ||
107 | |||
108 | ret = read_msr(cpu, MSR_APERF, &val); | ||
109 | aperf_current_count[cpu] = val; | ||
110 | ret |= read_msr(cpu, MSR_MPERF, &val); | ||
111 | mperf_current_count[cpu] = val; | ||
112 | is_valid[cpu] = !ret; | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int mperf_get_count_percent(unsigned int id, double *percent, | ||
118 | unsigned int cpu) | ||
119 | { | ||
120 | unsigned long long aperf_diff, mperf_diff, tsc_diff; | ||
121 | unsigned long long timediff; | ||
122 | |||
123 | if (!is_valid[cpu]) | ||
124 | return -1; | ||
125 | |||
126 | if (id != C0 && id != Cx) | ||
127 | return -1; | ||
128 | |||
129 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | ||
130 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | ||
131 | |||
132 | if (max_freq_mode == MAX_FREQ_TSC_REF) { | ||
133 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | ||
134 | *percent = 100.0 * mperf_diff / tsc_diff; | ||
135 | dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", | ||
136 | mperf_cstates[id].name, mperf_diff, tsc_diff); | ||
137 | } else if (max_freq_mode == MAX_FREQ_SYSFS) { | ||
138 | timediff = timespec_diff_us(time_start, time_end); | ||
139 | *percent = 100.0 * mperf_diff / timediff; | ||
140 | dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", | ||
141 | mperf_cstates[id].name, mperf_diff, timediff); | ||
142 | } else | ||
143 | return -1; | ||
144 | |||
145 | if (id == Cx) | ||
146 | *percent = 100.0 - *percent; | ||
147 | |||
148 | dprint("%s: previous: %llu - current: %llu - (%u)\n", | ||
149 | mperf_cstates[id].name, mperf_diff, aperf_diff, cpu); | ||
150 | dprint("%s: %f\n", mperf_cstates[id].name, *percent); | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | ||
155 | unsigned int cpu) | ||
156 | { | ||
157 | unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff; | ||
158 | |||
159 | if (id != AVG_FREQ) | ||
160 | return 1; | ||
161 | |||
162 | if (!is_valid[cpu]) | ||
163 | return -1; | ||
164 | |||
165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | ||
166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | ||
167 | |||
168 | if (max_freq_mode == MAX_FREQ_TSC_REF) { | ||
169 | /* Calculate max_freq from TSC count */ | ||
170 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | ||
171 | time_diff = timespec_diff_us(time_start, time_end); | ||
172 | max_frequency = tsc_diff / time_diff; | ||
173 | } | ||
174 | |||
175 | *count = max_frequency * ((double)aperf_diff / mperf_diff); | ||
176 | dprint("%s: Average freq based on %s maximum frequency:\n", | ||
177 | mperf_cstates[id].name, | ||
178 | (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); | ||
179 | dprint("%max_frequency: %lu", max_frequency); | ||
180 | dprint("aperf_diff: %llu\n", aperf_diff); | ||
181 | dprint("mperf_diff: %llu\n", mperf_diff); | ||
182 | dprint("avg freq: %llu\n", *count); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int mperf_start(void) | ||
187 | { | ||
188 | int cpu; | ||
189 | unsigned long long dbg; | ||
190 | |||
191 | clock_gettime(CLOCK_REALTIME, &time_start); | ||
192 | mperf_get_tsc(&tsc_at_measure_start); | ||
193 | |||
194 | for (cpu = 0; cpu < cpu_count; cpu++) | ||
195 | mperf_init_stats(cpu); | ||
196 | |||
197 | mperf_get_tsc(&dbg); | ||
198 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int mperf_stop(void) | ||
203 | { | ||
204 | unsigned long long dbg; | ||
205 | int cpu; | ||
206 | |||
207 | for (cpu = 0; cpu < cpu_count; cpu++) | ||
208 | mperf_measure_stats(cpu); | ||
209 | |||
210 | mperf_get_tsc(&tsc_at_measure_end); | ||
211 | clock_gettime(CLOCK_REALTIME, &time_end); | ||
212 | |||
213 | mperf_get_tsc(&dbg); | ||
214 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Mperf register is defined to tick at P0 (maximum) frequency | ||
221 | * | ||
222 | * Instead of reading out P0 which can be tricky to read out from HW, | ||
223 | * we use TSC counter if it reliably ticks at P0/mperf frequency. | ||
224 | * | ||
225 | * Still try to fall back to: | ||
226 | * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq | ||
227 | * on older Intel HW without invariant TSC feature. | ||
228 | * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but | ||
229 | * it's still double checked (MSR_AMD_HWCR)). | ||
230 | * | ||
231 | * On these machines the user would still get useful mperf | ||
232 | * stats when acpi-cpufreq driver is loaded. | ||
233 | */ | ||
234 | static int init_maxfreq_mode(void) | ||
235 | { | ||
236 | int ret; | ||
237 | unsigned long long hwcr; | ||
238 | unsigned long min; | ||
239 | |||
240 | if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) | ||
241 | goto use_sysfs; | ||
242 | |||
243 | if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { | ||
244 | /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf | ||
245 | * freq. | ||
246 | * A test whether hwcr is accessable/available would be: | ||
247 | * (cpupower_cpu_info.family > 0x10 || | ||
248 | * cpupower_cpu_info.family == 0x10 && | ||
249 | * cpupower_cpu_info.model >= 0x2)) | ||
250 | * This should be the case for all aperf/mperf | ||
251 | * capable AMD machines and is therefore safe to test here. | ||
252 | * Compare with Linus kernel git commit: acf01734b1747b1ec4 | ||
253 | */ | ||
254 | ret = read_msr(0, MSR_AMD_HWCR, &hwcr); | ||
255 | /* | ||
256 | * If the MSR read failed, assume a Xen system that did | ||
257 | * not explicitly provide access to it and assume TSC works | ||
258 | */ | ||
259 | if (ret != 0) { | ||
260 | dprint("TSC read 0x%x failed - assume TSC working\n", | ||
261 | MSR_AMD_HWCR); | ||
262 | return 0; | ||
263 | } else if (1 & (hwcr >> 24)) { | ||
264 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
265 | return 0; | ||
266 | } else { /* Use sysfs max frequency if available */ } | ||
267 | } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { | ||
268 | /* | ||
269 | * On Intel we assume mperf (in C0) is ticking at same | ||
270 | * rate than TSC | ||
271 | */ | ||
272 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
273 | return 0; | ||
274 | } | ||
275 | use_sysfs: | ||
276 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { | ||
277 | dprint("Cannot retrieve max freq from cpufreq kernel " | ||
278 | "subsystem\n"); | ||
279 | return -1; | ||
280 | } | ||
281 | max_freq_mode = MAX_FREQ_SYSFS; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * This monitor provides: | ||
287 | * | ||
288 | * 1) Average frequency a CPU resided in | ||
289 | * This always works if the CPU has aperf/mperf capabilities | ||
290 | * | ||
291 | * 2) C0 and Cx (any sleep state) time a CPU resided in | ||
292 | * Works if mperf timer stops ticking in sleep states which | ||
293 | * seem to be the case on all current HW. | ||
294 | * Both is directly retrieved from HW registers and is independent | ||
295 | * from kernel statistics. | ||
296 | */ | ||
297 | struct cpuidle_monitor mperf_monitor; | ||
298 | struct cpuidle_monitor *mperf_register(void) | ||
299 | { | ||
300 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | ||
301 | return NULL; | ||
302 | |||
303 | if (init_maxfreq_mode()) | ||
304 | return NULL; | ||
305 | |||
306 | /* Free this at program termination */ | ||
307 | is_valid = calloc(cpu_count, sizeof(int)); | ||
308 | mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); | ||
309 | aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); | ||
310 | mperf_current_count = calloc(cpu_count, sizeof(unsigned long long)); | ||
311 | aperf_current_count = calloc(cpu_count, sizeof(unsigned long long)); | ||
312 | |||
313 | mperf_monitor.name_len = strlen(mperf_monitor.name); | ||
314 | return &mperf_monitor; | ||
315 | } | ||
316 | |||
317 | void mperf_unregister(void) | ||
318 | { | ||
319 | free(mperf_previous_count); | ||
320 | free(aperf_previous_count); | ||
321 | free(mperf_current_count); | ||
322 | free(aperf_current_count); | ||
323 | free(is_valid); | ||
324 | } | ||
325 | |||
326 | struct cpuidle_monitor mperf_monitor = { | ||
327 | .name = "Mperf", | ||
328 | .hw_states_num = MPERF_CSTATE_COUNT, | ||
329 | .hw_states = mperf_cstates, | ||
330 | .start = mperf_start, | ||
331 | .stop = mperf_stop, | ||
332 | .do_register = mperf_register, | ||
333 | .unregister = mperf_unregister, | ||
334 | .needs_root = 1, | ||
335 | .overflow_s = 922000000 /* 922337203 seconds TSC overflow | ||
336 | at 20GHz */ | ||
337 | }; | ||
338 | #endif /* #if defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c new file mode 100644 index 000000000000..d2a91dd0d563 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on Len Brown's <lenb@kernel.org> turbostat tool. | ||
7 | */ | ||
8 | |||
9 | #if defined(__i386__) || defined(__x86_64__) | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | |||
16 | #include "helpers/helpers.h" | ||
17 | #include "idle_monitor/cpupower-monitor.h" | ||
18 | |||
19 | #define MSR_PKG_C3_RESIDENCY 0x3F8 | ||
20 | #define MSR_PKG_C6_RESIDENCY 0x3F9 | ||
21 | #define MSR_CORE_C3_RESIDENCY 0x3FC | ||
22 | #define MSR_CORE_C6_RESIDENCY 0x3FD | ||
23 | |||
24 | #define MSR_TSC 0x10 | ||
25 | |||
26 | #define NHM_CSTATE_COUNT 4 | ||
27 | |||
28 | enum intel_nhm_id { C3 = 0, C6, PC3, PC6, TSC = 0xFFFF }; | ||
29 | |||
30 | static int nhm_get_count_percent(unsigned int self_id, double *percent, | ||
31 | unsigned int cpu); | ||
32 | |||
33 | static cstate_t nhm_cstates[NHM_CSTATE_COUNT] = { | ||
34 | { | ||
35 | .name = "C3", | ||
36 | .desc = N_("Processor Core C3"), | ||
37 | .id = C3, | ||
38 | .range = RANGE_CORE, | ||
39 | .get_count_percent = nhm_get_count_percent, | ||
40 | }, | ||
41 | { | ||
42 | .name = "C6", | ||
43 | .desc = N_("Processor Core C6"), | ||
44 | .id = C6, | ||
45 | .range = RANGE_CORE, | ||
46 | .get_count_percent = nhm_get_count_percent, | ||
47 | }, | ||
48 | |||
49 | { | ||
50 | .name = "PC3", | ||
51 | .desc = N_("Processor Package C3"), | ||
52 | .id = PC3, | ||
53 | .range = RANGE_PACKAGE, | ||
54 | .get_count_percent = nhm_get_count_percent, | ||
55 | }, | ||
56 | { | ||
57 | .name = "PC6", | ||
58 | .desc = N_("Processor Package C6"), | ||
59 | .id = PC6, | ||
60 | .range = RANGE_PACKAGE, | ||
61 | .get_count_percent = nhm_get_count_percent, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | static unsigned long long tsc_at_measure_start; | ||
66 | static unsigned long long tsc_at_measure_end; | ||
67 | static unsigned long long *previous_count[NHM_CSTATE_COUNT]; | ||
68 | static unsigned long long *current_count[NHM_CSTATE_COUNT]; | ||
69 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | ||
70 | static int *is_valid; | ||
71 | |||
72 | static int nhm_get_count(enum intel_nhm_id id, unsigned long long *val, | ||
73 | unsigned int cpu) | ||
74 | { | ||
75 | int msr; | ||
76 | |||
77 | switch (id) { | ||
78 | case C3: | ||
79 | msr = MSR_CORE_C3_RESIDENCY; | ||
80 | break; | ||
81 | case C6: | ||
82 | msr = MSR_CORE_C6_RESIDENCY; | ||
83 | break; | ||
84 | case PC3: | ||
85 | msr = MSR_PKG_C3_RESIDENCY; | ||
86 | break; | ||
87 | case PC6: | ||
88 | msr = MSR_PKG_C6_RESIDENCY; | ||
89 | break; | ||
90 | case TSC: | ||
91 | msr = MSR_TSC; | ||
92 | break; | ||
93 | default: | ||
94 | return -1; | ||
95 | }; | ||
96 | if (read_msr(cpu, msr, val)) | ||
97 | return -1; | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int nhm_get_count_percent(unsigned int id, double *percent, | ||
103 | unsigned int cpu) | ||
104 | { | ||
105 | *percent = 0.0; | ||
106 | |||
107 | if (!is_valid[cpu]) | ||
108 | return -1; | ||
109 | |||
110 | *percent = (100.0 * | ||
111 | (current_count[id][cpu] - previous_count[id][cpu])) / | ||
112 | (tsc_at_measure_end - tsc_at_measure_start); | ||
113 | |||
114 | dprint("%s: previous: %llu - current: %llu - (%u)\n", | ||
115 | nhm_cstates[id].name, previous_count[id][cpu], | ||
116 | current_count[id][cpu], cpu); | ||
117 | |||
118 | dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", | ||
119 | nhm_cstates[id].name, | ||
120 | (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, | ||
121 | current_count[id][cpu] - previous_count[id][cpu], | ||
122 | *percent, cpu); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int nhm_start(void) | ||
128 | { | ||
129 | int num, cpu; | ||
130 | unsigned long long dbg, val; | ||
131 | |||
132 | nhm_get_count(TSC, &tsc_at_measure_start, 0); | ||
133 | |||
134 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | ||
135 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
136 | is_valid[cpu] = !nhm_get_count(num, &val, cpu); | ||
137 | previous_count[num][cpu] = val; | ||
138 | } | ||
139 | } | ||
140 | nhm_get_count(TSC, &dbg, 0); | ||
141 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int nhm_stop(void) | ||
146 | { | ||
147 | unsigned long long val; | ||
148 | unsigned long long dbg; | ||
149 | int num, cpu; | ||
150 | |||
151 | nhm_get_count(TSC, &tsc_at_measure_end, 0); | ||
152 | |||
153 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | ||
154 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
155 | is_valid[cpu] = !nhm_get_count(num, &val, cpu); | ||
156 | current_count[num][cpu] = val; | ||
157 | } | ||
158 | } | ||
159 | nhm_get_count(TSC, &dbg, 0); | ||
160 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | struct cpuidle_monitor intel_nhm_monitor; | ||
166 | |||
167 | struct cpuidle_monitor *intel_nhm_register(void) | ||
168 | { | ||
169 | int num; | ||
170 | |||
171 | if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL) | ||
172 | return NULL; | ||
173 | |||
174 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)) | ||
175 | return NULL; | ||
176 | |||
177 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | ||
178 | return NULL; | ||
179 | |||
180 | /* Free this at program termination */ | ||
181 | is_valid = calloc(cpu_count, sizeof(int)); | ||
182 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | ||
183 | previous_count[num] = calloc(cpu_count, | ||
184 | sizeof(unsigned long long)); | ||
185 | current_count[num] = calloc(cpu_count, | ||
186 | sizeof(unsigned long long)); | ||
187 | } | ||
188 | |||
189 | intel_nhm_monitor.name_len = strlen(intel_nhm_monitor.name); | ||
190 | return &intel_nhm_monitor; | ||
191 | } | ||
192 | |||
193 | void intel_nhm_unregister(void) | ||
194 | { | ||
195 | int num; | ||
196 | |||
197 | for (num = 0; num < NHM_CSTATE_COUNT; num++) { | ||
198 | free(previous_count[num]); | ||
199 | free(current_count[num]); | ||
200 | } | ||
201 | free(is_valid); | ||
202 | } | ||
203 | |||
204 | struct cpuidle_monitor intel_nhm_monitor = { | ||
205 | .name = "Nehalem", | ||
206 | .hw_states_num = NHM_CSTATE_COUNT, | ||
207 | .hw_states = nhm_cstates, | ||
208 | .start = nhm_start, | ||
209 | .stop = nhm_stop, | ||
210 | .do_register = intel_nhm_register, | ||
211 | .unregister = intel_nhm_unregister, | ||
212 | .needs_root = 1, | ||
213 | .overflow_s = 922000000 /* 922337203 seconds TSC overflow | ||
214 | at 20GHz */ | ||
215 | }; | ||
216 | #endif | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c new file mode 100644 index 000000000000..a1bc07cd53e1 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | * | ||
6 | * Based on Len Brown's <lenb@kernel.org> turbostat tool. | ||
7 | */ | ||
8 | |||
9 | #if defined(__i386__) || defined(__x86_64__) | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | |||
16 | #include "helpers/helpers.h" | ||
17 | #include "idle_monitor/cpupower-monitor.h" | ||
18 | |||
19 | #define MSR_PKG_C2_RESIDENCY 0x60D | ||
20 | #define MSR_PKG_C7_RESIDENCY 0x3FA | ||
21 | #define MSR_CORE_C7_RESIDENCY 0x3FE | ||
22 | |||
23 | #define MSR_TSC 0x10 | ||
24 | |||
25 | enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF }; | ||
26 | |||
27 | static int snb_get_count_percent(unsigned int self_id, double *percent, | ||
28 | unsigned int cpu); | ||
29 | |||
30 | static cstate_t snb_cstates[SNB_CSTATE_COUNT] = { | ||
31 | { | ||
32 | .name = "C7", | ||
33 | .desc = N_("Processor Core C7"), | ||
34 | .id = C7, | ||
35 | .range = RANGE_CORE, | ||
36 | .get_count_percent = snb_get_count_percent, | ||
37 | }, | ||
38 | { | ||
39 | .name = "PC2", | ||
40 | .desc = N_("Processor Package C2"), | ||
41 | .id = PC2, | ||
42 | .range = RANGE_PACKAGE, | ||
43 | .get_count_percent = snb_get_count_percent, | ||
44 | }, | ||
45 | { | ||
46 | .name = "PC7", | ||
47 | .desc = N_("Processor Package C7"), | ||
48 | .id = PC7, | ||
49 | .range = RANGE_PACKAGE, | ||
50 | .get_count_percent = snb_get_count_percent, | ||
51 | }, | ||
52 | }; | ||
53 | |||
54 | static unsigned long long tsc_at_measure_start; | ||
55 | static unsigned long long tsc_at_measure_end; | ||
56 | static unsigned long long *previous_count[SNB_CSTATE_COUNT]; | ||
57 | static unsigned long long *current_count[SNB_CSTATE_COUNT]; | ||
58 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | ||
59 | static int *is_valid; | ||
60 | |||
61 | static int snb_get_count(enum intel_snb_id id, unsigned long long *val, | ||
62 | unsigned int cpu) | ||
63 | { | ||
64 | int msr; | ||
65 | |||
66 | switch (id) { | ||
67 | case C7: | ||
68 | msr = MSR_CORE_C7_RESIDENCY; | ||
69 | break; | ||
70 | case PC2: | ||
71 | msr = MSR_PKG_C2_RESIDENCY; | ||
72 | break; | ||
73 | case PC7: | ||
74 | msr = MSR_PKG_C7_RESIDENCY; | ||
75 | break; | ||
76 | case TSC: | ||
77 | msr = MSR_TSC; | ||
78 | break; | ||
79 | default: | ||
80 | return -1; | ||
81 | }; | ||
82 | if (read_msr(cpu, msr, val)) | ||
83 | return -1; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int snb_get_count_percent(unsigned int id, double *percent, | ||
88 | unsigned int cpu) | ||
89 | { | ||
90 | *percent = 0.0; | ||
91 | |||
92 | if (!is_valid[cpu]) | ||
93 | return -1; | ||
94 | |||
95 | *percent = (100.0 * | ||
96 | (current_count[id][cpu] - previous_count[id][cpu])) / | ||
97 | (tsc_at_measure_end - tsc_at_measure_start); | ||
98 | |||
99 | dprint("%s: previous: %llu - current: %llu - (%u)\n", | ||
100 | snb_cstates[id].name, previous_count[id][cpu], | ||
101 | current_count[id][cpu], cpu); | ||
102 | |||
103 | dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", | ||
104 | snb_cstates[id].name, | ||
105 | (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, | ||
106 | current_count[id][cpu] - previous_count[id][cpu], | ||
107 | *percent, cpu); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int snb_start(void) | ||
113 | { | ||
114 | int num, cpu; | ||
115 | unsigned long long val; | ||
116 | |||
117 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { | ||
118 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
119 | snb_get_count(num, &val, cpu); | ||
120 | previous_count[num][cpu] = val; | ||
121 | } | ||
122 | } | ||
123 | snb_get_count(TSC, &tsc_at_measure_start, 0); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int snb_stop(void) | ||
128 | { | ||
129 | unsigned long long val; | ||
130 | int num, cpu; | ||
131 | |||
132 | snb_get_count(TSC, &tsc_at_measure_end, 0); | ||
133 | |||
134 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { | ||
135 | for (cpu = 0; cpu < cpu_count; cpu++) { | ||
136 | is_valid[cpu] = !snb_get_count(num, &val, cpu); | ||
137 | current_count[num][cpu] = val; | ||
138 | } | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | struct cpuidle_monitor intel_snb_monitor; | ||
144 | |||
145 | static struct cpuidle_monitor *snb_register(void) | ||
146 | { | ||
147 | int num; | ||
148 | |||
149 | if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL | ||
150 | || cpupower_cpu_info.family != 6) | ||
151 | return NULL; | ||
152 | |||
153 | if (cpupower_cpu_info.model != 0x2A | ||
154 | && cpupower_cpu_info.model != 0x2D) | ||
155 | return NULL; | ||
156 | |||
157 | is_valid = calloc(cpu_count, sizeof(int)); | ||
158 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { | ||
159 | previous_count[num] = calloc(cpu_count, | ||
160 | sizeof(unsigned long long)); | ||
161 | current_count[num] = calloc(cpu_count, | ||
162 | sizeof(unsigned long long)); | ||
163 | } | ||
164 | intel_snb_monitor.name_len = strlen(intel_snb_monitor.name); | ||
165 | return &intel_snb_monitor; | ||
166 | } | ||
167 | |||
168 | void snb_unregister(void) | ||
169 | { | ||
170 | int num; | ||
171 | free(is_valid); | ||
172 | for (num = 0; num < SNB_CSTATE_COUNT; num++) { | ||
173 | free(previous_count[num]); | ||
174 | free(current_count[num]); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | struct cpuidle_monitor intel_snb_monitor = { | ||
179 | .name = "SandyBridge", | ||
180 | .hw_states = snb_cstates, | ||
181 | .hw_states_num = SNB_CSTATE_COUNT, | ||
182 | .start = snb_start, | ||
183 | .stop = snb_stop, | ||
184 | .do_register = snb_register, | ||
185 | .unregister = snb_unregister, | ||
186 | .needs_root = 1, | ||
187 | .overflow_s = 922000000 /* 922337203 seconds TSC overflow | ||
188 | at 20GHz */ | ||
189 | }; | ||
190 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
diff --git a/tools/power/cpupower/utils/version-gen.sh b/tools/power/cpupower/utils/version-gen.sh new file mode 100755 index 000000000000..5ec41c556992 --- /dev/null +++ b/tools/power/cpupower/utils/version-gen.sh | |||
@@ -0,0 +1,35 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # Script which prints out the version to use for building cpupowerutils. | ||
4 | # Must be called from tools/power/cpupower/ | ||
5 | # | ||
6 | # Heavily based on tools/perf/util/PERF-VERSION-GEN . | ||
7 | |||
8 | LF=' | ||
9 | ' | ||
10 | |||
11 | # First check if there is a .git to get the version from git describe | ||
12 | # otherwise try to get the version from the kernel makefile | ||
13 | if test -d ../../../.git -o -f ../../../.git && | ||
14 | VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && | ||
15 | case "$VN" in | ||
16 | *$LF*) (exit 1) ;; | ||
17 | v[0-9]*) | ||
18 | git update-index -q --refresh | ||
19 | test -z "$(git diff-index --name-only HEAD --)" || | ||
20 | VN="$VN-dirty" ;; | ||
21 | esac | ||
22 | then | ||
23 | VN=$(echo "$VN" | sed -e 's/-/./g'); | ||
24 | else | ||
25 | eval $(grep '^VERSION[[:space:]]*=' ../../../Makefile|tr -d ' ') | ||
26 | eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ') | ||
27 | eval $(grep '^SUBLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ') | ||
28 | eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../../Makefile|tr -d ' ') | ||
29 | |||
30 | VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}" | ||
31 | fi | ||
32 | |||
33 | VN=$(expr "$VN" : v*'\(.*\)') | ||
34 | |||
35 | echo $VN | ||
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 6d8ef4a3a9b5..3c6f7808efae 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -128,53 +128,55 @@ unsigned long long get_msr(int cpu, off_t offset) | |||
128 | void print_header(void) | 128 | void print_header(void) |
129 | { | 129 | { |
130 | if (show_pkg) | 130 | if (show_pkg) |
131 | fprintf(stderr, "pkg "); | 131 | fprintf(stderr, "pk"); |
132 | if (show_core) | 132 | if (show_core) |
133 | fprintf(stderr, "core"); | 133 | fprintf(stderr, " cr"); |
134 | if (show_cpu) | 134 | if (show_cpu) |
135 | fprintf(stderr, " CPU"); | 135 | fprintf(stderr, " CPU"); |
136 | if (do_nhm_cstates) | 136 | if (do_nhm_cstates) |
137 | fprintf(stderr, " %%c0 "); | 137 | fprintf(stderr, " %%c0 "); |
138 | if (has_aperf) | 138 | if (has_aperf) |
139 | fprintf(stderr, " GHz"); | 139 | fprintf(stderr, " GHz"); |
140 | fprintf(stderr, " TSC"); | 140 | fprintf(stderr, " TSC"); |
141 | if (do_nhm_cstates) | 141 | if (do_nhm_cstates) |
142 | fprintf(stderr, " %%c1 "); | 142 | fprintf(stderr, " %%c1"); |
143 | if (do_nhm_cstates) | 143 | if (do_nhm_cstates) |
144 | fprintf(stderr, " %%c3 "); | 144 | fprintf(stderr, " %%c3"); |
145 | if (do_nhm_cstates) | 145 | if (do_nhm_cstates) |
146 | fprintf(stderr, " %%c6 "); | 146 | fprintf(stderr, " %%c6"); |
147 | if (do_snb_cstates) | 147 | if (do_snb_cstates) |
148 | fprintf(stderr, " %%c7 "); | 148 | fprintf(stderr, " %%c7"); |
149 | if (do_snb_cstates) | 149 | if (do_snb_cstates) |
150 | fprintf(stderr, " %%pc2 "); | 150 | fprintf(stderr, " %%pc2"); |
151 | if (do_nhm_cstates) | 151 | if (do_nhm_cstates) |
152 | fprintf(stderr, " %%pc3 "); | 152 | fprintf(stderr, " %%pc3"); |
153 | if (do_nhm_cstates) | 153 | if (do_nhm_cstates) |
154 | fprintf(stderr, " %%pc6 "); | 154 | fprintf(stderr, " %%pc6"); |
155 | if (do_snb_cstates) | 155 | if (do_snb_cstates) |
156 | fprintf(stderr, " %%pc7 "); | 156 | fprintf(stderr, " %%pc7"); |
157 | if (extra_msr_offset) | 157 | if (extra_msr_offset) |
158 | fprintf(stderr, " MSR 0x%x ", extra_msr_offset); | 158 | fprintf(stderr, " MSR 0x%x ", extra_msr_offset); |
159 | 159 | ||
160 | putc('\n', stderr); | 160 | putc('\n', stderr); |
161 | } | 161 | } |
162 | 162 | ||
163 | void dump_cnt(struct counters *cnt) | 163 | void dump_cnt(struct counters *cnt) |
164 | { | 164 | { |
165 | fprintf(stderr, "package: %d ", cnt->pkg); | 165 | if (!cnt) |
166 | fprintf(stderr, "core:: %d ", cnt->core); | 166 | return; |
167 | fprintf(stderr, "CPU: %d ", cnt->cpu); | 167 | if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg); |
168 | fprintf(stderr, "TSC: %016llX\n", cnt->tsc); | 168 | if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core); |
169 | fprintf(stderr, "c3: %016llX\n", cnt->c3); | 169 | if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu); |
170 | fprintf(stderr, "c6: %016llX\n", cnt->c6); | 170 | if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc); |
171 | fprintf(stderr, "c7: %016llX\n", cnt->c7); | 171 | if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3); |
172 | fprintf(stderr, "aperf: %016llX\n", cnt->aperf); | 172 | if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6); |
173 | fprintf(stderr, "pc2: %016llX\n", cnt->pc2); | 173 | if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7); |
174 | fprintf(stderr, "pc3: %016llX\n", cnt->pc3); | 174 | if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf); |
175 | fprintf(stderr, "pc6: %016llX\n", cnt->pc6); | 175 | if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2); |
176 | fprintf(stderr, "pc7: %016llX\n", cnt->pc7); | 176 | if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3); |
177 | fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); | 177 | if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6); |
178 | if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7); | ||
179 | if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); | ||
178 | } | 180 | } |
179 | 181 | ||
180 | void dump_list(struct counters *cnt) | 182 | void dump_list(struct counters *cnt) |
@@ -194,14 +196,14 @@ void print_cnt(struct counters *p) | |||
194 | /* topology columns, print blanks on 1st (average) line */ | 196 | /* topology columns, print blanks on 1st (average) line */ |
195 | if (p == cnt_average) { | 197 | if (p == cnt_average) { |
196 | if (show_pkg) | 198 | if (show_pkg) |
197 | fprintf(stderr, " "); | 199 | fprintf(stderr, " "); |
198 | if (show_core) | 200 | if (show_core) |
199 | fprintf(stderr, " "); | 201 | fprintf(stderr, " "); |
200 | if (show_cpu) | 202 | if (show_cpu) |
201 | fprintf(stderr, " "); | 203 | fprintf(stderr, " "); |
202 | } else { | 204 | } else { |
203 | if (show_pkg) | 205 | if (show_pkg) |
204 | fprintf(stderr, "%4d", p->pkg); | 206 | fprintf(stderr, "%d", p->pkg); |
205 | if (show_core) | 207 | if (show_core) |
206 | fprintf(stderr, "%4d", p->core); | 208 | fprintf(stderr, "%4d", p->core); |
207 | if (show_cpu) | 209 | if (show_cpu) |
@@ -241,22 +243,22 @@ void print_cnt(struct counters *p) | |||
241 | if (!skip_c1) | 243 | if (!skip_c1) |
242 | fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); | 244 | fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); |
243 | else | 245 | else |
244 | fprintf(stderr, " ****"); | 246 | fprintf(stderr, " ****"); |
245 | } | 247 | } |
246 | if (do_nhm_cstates) | 248 | if (do_nhm_cstates) |
247 | fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc); | 249 | fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc); |
248 | if (do_nhm_cstates) | 250 | if (do_nhm_cstates) |
249 | fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc); | 251 | fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc); |
250 | if (do_snb_cstates) | 252 | if (do_snb_cstates) |
251 | fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc); | 253 | fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); |
252 | if (do_snb_cstates) | 254 | if (do_snb_cstates) |
253 | fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc); | 255 | fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc); |
254 | if (do_nhm_cstates) | 256 | if (do_nhm_cstates) |
255 | fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc); | 257 | fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc); |
256 | if (do_nhm_cstates) | 258 | if (do_nhm_cstates) |
257 | fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc); | 259 | fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc); |
258 | if (do_snb_cstates) | 260 | if (do_snb_cstates) |
259 | fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc); | 261 | fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc); |
260 | if (extra_msr_offset) | 262 | if (extra_msr_offset) |
261 | fprintf(stderr, " 0x%016llx", p->extra_msr); | 263 | fprintf(stderr, " 0x%016llx", p->extra_msr); |
262 | putc('\n', stderr); | 264 | putc('\n', stderr); |
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 2618ef2ba31f..33c5c7ee148f 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c | |||
@@ -137,7 +137,6 @@ void cmdline(int argc, char **argv) | |||
137 | void validate_cpuid(void) | 137 | void validate_cpuid(void) |
138 | { | 138 | { |
139 | unsigned int eax, ebx, ecx, edx, max_level; | 139 | unsigned int eax, ebx, ecx, edx, max_level; |
140 | char brand[16]; | ||
141 | unsigned int fms, family, model, stepping; | 140 | unsigned int fms, family, model, stepping; |
142 | 141 | ||
143 | eax = ebx = ecx = edx = 0; | 142 | eax = ebx = ecx = edx = 0; |
@@ -160,8 +159,8 @@ void validate_cpuid(void) | |||
160 | model += ((fms >> 16) & 0xf) << 4; | 159 | model += ((fms >> 16) & 0xf) << 4; |
161 | 160 | ||
162 | if (verbose > 1) | 161 | if (verbose > 1) |
163 | printf("CPUID %s %d levels family:model:stepping " | 162 | printf("CPUID %d levels family:model:stepping " |
164 | "0x%x:%x:%x (%d:%d:%d)\n", brand, max_level, | 163 | "0x%x:%x:%x (%d:%d:%d)\n", max_level, |
165 | family, model, stepping, family, model, stepping); | 164 | family, model, stepping, family, model, stepping); |
166 | 165 | ||
167 | if (!(edx & (1 << 5))) { | 166 | if (!(edx & (1 << 5))) { |
diff --git a/tools/slub/slabinfo.c b/tools/slub/slabinfo.c index 516551c9f172..164cbcf61106 100644 --- a/tools/slub/slabinfo.c +++ b/tools/slub/slabinfo.c | |||
@@ -2,8 +2,9 @@ | |||
2 | * Slabinfo: Tool to get reports about slabs | 2 | * Slabinfo: Tool to get reports about slabs |
3 | * | 3 | * |
4 | * (C) 2007 sgi, Christoph Lameter | 4 | * (C) 2007 sgi, Christoph Lameter |
5 | * (C) 2011 Linux Foundation, Christoph Lameter | ||
5 | * | 6 | * |
6 | * Compile by: | 7 | * Compile with: |
7 | * | 8 | * |
8 | * gcc -o slabinfo slabinfo.c | 9 | * gcc -o slabinfo slabinfo.c |
9 | */ | 10 | */ |
@@ -39,6 +40,9 @@ struct slabinfo { | |||
39 | unsigned long cpuslab_flush, deactivate_full, deactivate_empty; | 40 | unsigned long cpuslab_flush, deactivate_full, deactivate_empty; |
40 | unsigned long deactivate_to_head, deactivate_to_tail; | 41 | unsigned long deactivate_to_head, deactivate_to_tail; |
41 | unsigned long deactivate_remote_frees, order_fallback; | 42 | unsigned long deactivate_remote_frees, order_fallback; |
43 | unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail; | ||
44 | unsigned long alloc_node_mismatch, deactivate_bypass; | ||
45 | unsigned long cpu_partial_alloc, cpu_partial_free; | ||
42 | int numa[MAX_NODES]; | 46 | int numa[MAX_NODES]; |
43 | int numa_partial[MAX_NODES]; | 47 | int numa_partial[MAX_NODES]; |
44 | } slabinfo[MAX_SLABS]; | 48 | } slabinfo[MAX_SLABS]; |
@@ -99,7 +103,7 @@ static void fatal(const char *x, ...) | |||
99 | 103 | ||
100 | static void usage(void) | 104 | static void usage(void) |
101 | { | 105 | { |
102 | printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n" | 106 | printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n" |
103 | "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" | 107 | "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" |
104 | "-a|--aliases Show aliases\n" | 108 | "-a|--aliases Show aliases\n" |
105 | "-A|--activity Most active slabs first\n" | 109 | "-A|--activity Most active slabs first\n" |
@@ -293,7 +297,7 @@ int line = 0; | |||
293 | static void first_line(void) | 297 | static void first_line(void) |
294 | { | 298 | { |
295 | if (show_activity) | 299 | if (show_activity) |
296 | printf("Name Objects Alloc Free %%Fast Fallb O\n"); | 300 | printf("Name Objects Alloc Free %%Fast Fallb O CmpX UL\n"); |
297 | else | 301 | else |
298 | printf("Name Objects Objsize Space " | 302 | printf("Name Objects Objsize Space " |
299 | "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); | 303 | "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); |
@@ -379,14 +383,14 @@ static void show_tracking(struct slabinfo *s) | |||
379 | printf("\n%s: Kernel object allocation\n", s->name); | 383 | printf("\n%s: Kernel object allocation\n", s->name); |
380 | printf("-----------------------------------------------------------------------\n"); | 384 | printf("-----------------------------------------------------------------------\n"); |
381 | if (read_slab_obj(s, "alloc_calls")) | 385 | if (read_slab_obj(s, "alloc_calls")) |
382 | printf(buffer); | 386 | printf("%s", buffer); |
383 | else | 387 | else |
384 | printf("No Data\n"); | 388 | printf("No Data\n"); |
385 | 389 | ||
386 | printf("\n%s: Kernel object freeing\n", s->name); | 390 | printf("\n%s: Kernel object freeing\n", s->name); |
387 | printf("------------------------------------------------------------------------\n"); | 391 | printf("------------------------------------------------------------------------\n"); |
388 | if (read_slab_obj(s, "free_calls")) | 392 | if (read_slab_obj(s, "free_calls")) |
389 | printf(buffer); | 393 | printf("%s", buffer); |
390 | else | 394 | else |
391 | printf("No Data\n"); | 395 | printf("No Data\n"); |
392 | 396 | ||
@@ -400,7 +404,7 @@ static void ops(struct slabinfo *s) | |||
400 | if (read_slab_obj(s, "ops")) { | 404 | if (read_slab_obj(s, "ops")) { |
401 | printf("\n%s: kmem_cache operations\n", s->name); | 405 | printf("\n%s: kmem_cache operations\n", s->name); |
402 | printf("--------------------------------------------\n"); | 406 | printf("--------------------------------------------\n"); |
403 | printf(buffer); | 407 | printf("%s", buffer); |
404 | } else | 408 | } else |
405 | printf("\n%s has no kmem_cache operations\n", s->name); | 409 | printf("\n%s has no kmem_cache operations\n", s->name); |
406 | } | 410 | } |
@@ -452,6 +456,11 @@ static void slab_stats(struct slabinfo *s) | |||
452 | s->alloc_from_partial * 100 / total_alloc, | 456 | s->alloc_from_partial * 100 / total_alloc, |
453 | s->free_remove_partial * 100 / total_free); | 457 | s->free_remove_partial * 100 / total_free); |
454 | 458 | ||
459 | printf("Cpu partial list %8lu %8lu %3lu %3lu\n", | ||
460 | s->cpu_partial_alloc, s->cpu_partial_free, | ||
461 | s->cpu_partial_alloc * 100 / total_alloc, | ||
462 | s->cpu_partial_free * 100 / total_free); | ||
463 | |||
455 | printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", | 464 | printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n", |
456 | s->deactivate_remote_frees, s->free_frozen, | 465 | s->deactivate_remote_frees, s->free_frozen, |
457 | s->deactivate_remote_frees * 100 / total_alloc, | 466 | s->deactivate_remote_frees * 100 / total_alloc, |
@@ -462,19 +471,32 @@ static void slab_stats(struct slabinfo *s) | |||
462 | if (s->cpuslab_flush) | 471 | if (s->cpuslab_flush) |
463 | printf("Flushes %8lu\n", s->cpuslab_flush); | 472 | printf("Flushes %8lu\n", s->cpuslab_flush); |
464 | 473 | ||
465 | if (s->alloc_refill) | ||
466 | printf("Refill %8lu\n", s->alloc_refill); | ||
467 | |||
468 | total = s->deactivate_full + s->deactivate_empty + | 474 | total = s->deactivate_full + s->deactivate_empty + |
469 | s->deactivate_to_head + s->deactivate_to_tail; | 475 | s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass; |
470 | 476 | ||
471 | if (total) | 477 | if (total) { |
472 | printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) " | 478 | printf("\nSlab Deactivation Ocurrences %%\n"); |
473 | "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n", | 479 | printf("-------------------------------------------------\n"); |
474 | s->deactivate_full, (s->deactivate_full * 100) / total, | 480 | printf("Slab full %7lu %3lu%%\n", |
475 | s->deactivate_empty, (s->deactivate_empty * 100) / total, | 481 | s->deactivate_full, (s->deactivate_full * 100) / total); |
476 | s->deactivate_to_head, (s->deactivate_to_head * 100) / total, | 482 | printf("Slab empty %7lu %3lu%%\n", |
483 | s->deactivate_empty, (s->deactivate_empty * 100) / total); | ||
484 | printf("Moved to head of partial list %7lu %3lu%%\n", | ||
485 | s->deactivate_to_head, (s->deactivate_to_head * 100) / total); | ||
486 | printf("Moved to tail of partial list %7lu %3lu%%\n", | ||
477 | s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); | 487 | s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); |
488 | printf("Deactivation bypass %7lu %3lu%%\n", | ||
489 | s->deactivate_bypass, (s->deactivate_bypass * 100) / total); | ||
490 | printf("Refilled from foreign frees %7lu %3lu%%\n", | ||
491 | s->alloc_refill, (s->alloc_refill * 100) / total); | ||
492 | printf("Node mismatch %7lu %3lu%%\n", | ||
493 | s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total); | ||
494 | } | ||
495 | |||
496 | if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail) | ||
497 | printf("\nCmpxchg_double Looping\n------------------------\n"); | ||
498 | printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n", | ||
499 | s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail); | ||
478 | } | 500 | } |
479 | 501 | ||
480 | static void report(struct slabinfo *s) | 502 | static void report(struct slabinfo *s) |
@@ -573,12 +595,13 @@ static void slabcache(struct slabinfo *s) | |||
573 | total_alloc = s->alloc_fastpath + s->alloc_slowpath; | 595 | total_alloc = s->alloc_fastpath + s->alloc_slowpath; |
574 | total_free = s->free_fastpath + s->free_slowpath; | 596 | total_free = s->free_fastpath + s->free_slowpath; |
575 | 597 | ||
576 | printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n", | 598 | printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n", |
577 | s->name, s->objects, | 599 | s->name, s->objects, |
578 | total_alloc, total_free, | 600 | total_alloc, total_free, |
579 | total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, | 601 | total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0, |
580 | total_free ? (s->free_fastpath * 100 / total_free) : 0, | 602 | total_free ? (s->free_fastpath * 100 / total_free) : 0, |
581 | s->order_fallback, s->order); | 603 | s->order_fallback, s->order, s->cmpxchg_double_fail, |
604 | s->cmpxchg_double_cpu_fail); | ||
582 | } | 605 | } |
583 | else | 606 | else |
584 | printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", | 607 | printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n", |
@@ -1128,7 +1151,7 @@ static void read_slab_dir(void) | |||
1128 | switch (de->d_type) { | 1151 | switch (de->d_type) { |
1129 | case DT_LNK: | 1152 | case DT_LNK: |
1130 | alias->name = strdup(de->d_name); | 1153 | alias->name = strdup(de->d_name); |
1131 | count = readlink(de->d_name, buffer, sizeof(buffer)); | 1154 | count = readlink(de->d_name, buffer, sizeof(buffer)-1); |
1132 | 1155 | ||
1133 | if (count < 0) | 1156 | if (count < 0) |
1134 | fatal("Cannot read symlink %s\n", de->d_name); | 1157 | fatal("Cannot read symlink %s\n", de->d_name); |
@@ -1190,6 +1213,12 @@ static void read_slab_dir(void) | |||
1190 | slab->deactivate_to_tail = get_obj("deactivate_to_tail"); | 1213 | slab->deactivate_to_tail = get_obj("deactivate_to_tail"); |
1191 | slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); | 1214 | slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); |
1192 | slab->order_fallback = get_obj("order_fallback"); | 1215 | slab->order_fallback = get_obj("order_fallback"); |
1216 | slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail"); | ||
1217 | slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail"); | ||
1218 | slab->cpu_partial_alloc = get_obj("cpu_partial_alloc"); | ||
1219 | slab->cpu_partial_free = get_obj("cpu_partial_free"); | ||
1220 | slab->alloc_node_mismatch = get_obj("alloc_node_mismatch"); | ||
1221 | slab->deactivate_bypass = get_obj("deactivate_bypass"); | ||
1193 | chdir(".."); | 1222 | chdir(".."); |
1194 | if (slab->name[0] == ':') | 1223 | if (slab->name[0] == ':') |
1195 | alias_targets++; | 1224 | alias_targets++; |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index cef28e6632b9..8b4c2535b266 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -27,7 +27,7 @@ $default{"TEST_TYPE"} = "test"; | |||
27 | $default{"BUILD_TYPE"} = "randconfig"; | 27 | $default{"BUILD_TYPE"} = "randconfig"; |
28 | $default{"MAKE_CMD"} = "make"; | 28 | $default{"MAKE_CMD"} = "make"; |
29 | $default{"TIMEOUT"} = 120; | 29 | $default{"TIMEOUT"} = 120; |
30 | $default{"TMP_DIR"} = "/tmp/ktest"; | 30 | $default{"TMP_DIR"} = "/tmp/ktest/\${MACHINE}"; |
31 | $default{"SLEEP_TIME"} = 60; # sleep time between tests | 31 | $default{"SLEEP_TIME"} = 60; # sleep time between tests |
32 | $default{"BUILD_NOCLEAN"} = 0; | 32 | $default{"BUILD_NOCLEAN"} = 0; |
33 | $default{"REBOOT_ON_ERROR"} = 0; | 33 | $default{"REBOOT_ON_ERROR"} = 0; |
@@ -41,6 +41,8 @@ $default{"CLEAR_LOG"} = 0; | |||
41 | $default{"BISECT_MANUAL"} = 0; | 41 | $default{"BISECT_MANUAL"} = 0; |
42 | $default{"BISECT_SKIP"} = 1; | 42 | $default{"BISECT_SKIP"} = 1; |
43 | $default{"SUCCESS_LINE"} = "login:"; | 43 | $default{"SUCCESS_LINE"} = "login:"; |
44 | $default{"DETECT_TRIPLE_FAULT"} = 1; | ||
45 | $default{"NO_INSTALL"} = 0; | ||
44 | $default{"BOOTED_TIMEOUT"} = 1; | 46 | $default{"BOOTED_TIMEOUT"} = 1; |
45 | $default{"DIE_ON_FAILURE"} = 1; | 47 | $default{"DIE_ON_FAILURE"} = 1; |
46 | $default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; | 48 | $default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; |
@@ -62,6 +64,10 @@ my $output_config; | |||
62 | my $test_type; | 64 | my $test_type; |
63 | my $build_type; | 65 | my $build_type; |
64 | my $build_options; | 66 | my $build_options; |
67 | my $pre_build; | ||
68 | my $post_build; | ||
69 | my $pre_build_die; | ||
70 | my $post_build_die; | ||
65 | my $reboot_type; | 71 | my $reboot_type; |
66 | my $reboot_script; | 72 | my $reboot_script; |
67 | my $power_cycle; | 73 | my $power_cycle; |
@@ -79,14 +85,20 @@ my $grub_number; | |||
79 | my $target; | 85 | my $target; |
80 | my $make; | 86 | my $make; |
81 | my $post_install; | 87 | my $post_install; |
88 | my $no_install; | ||
82 | my $noclean; | 89 | my $noclean; |
83 | my $minconfig; | 90 | my $minconfig; |
91 | my $start_minconfig; | ||
92 | my $start_minconfig_defined; | ||
93 | my $output_minconfig; | ||
94 | my $ignore_config; | ||
84 | my $addconfig; | 95 | my $addconfig; |
85 | my $in_bisect = 0; | 96 | my $in_bisect = 0; |
86 | my $bisect_bad = ""; | 97 | my $bisect_bad = ""; |
87 | my $reverse_bisect; | 98 | my $reverse_bisect; |
88 | my $bisect_manual; | 99 | my $bisect_manual; |
89 | my $bisect_skip; | 100 | my $bisect_skip; |
101 | my $config_bisect_good; | ||
90 | my $in_patchcheck = 0; | 102 | my $in_patchcheck = 0; |
91 | my $run_test; | 103 | my $run_test; |
92 | my $redirect; | 104 | my $redirect; |
@@ -98,10 +110,14 @@ my $monitor_cnt = 0; | |||
98 | my $sleep_time; | 110 | my $sleep_time; |
99 | my $bisect_sleep_time; | 111 | my $bisect_sleep_time; |
100 | my $patchcheck_sleep_time; | 112 | my $patchcheck_sleep_time; |
113 | my $ignore_warnings; | ||
101 | my $store_failures; | 114 | my $store_failures; |
115 | my $test_name; | ||
102 | my $timeout; | 116 | my $timeout; |
103 | my $booted_timeout; | 117 | my $booted_timeout; |
118 | my $detect_triplefault; | ||
104 | my $console; | 119 | my $console; |
120 | my $reboot_success_line; | ||
105 | my $success_line; | 121 | my $success_line; |
106 | my $stop_after_success; | 122 | my $stop_after_success; |
107 | my $stop_after_failure; | 123 | my $stop_after_failure; |
@@ -115,6 +131,13 @@ my $successes = 0; | |||
115 | my %entered_configs; | 131 | my %entered_configs; |
116 | my %config_help; | 132 | my %config_help; |
117 | my %variable; | 133 | my %variable; |
134 | my %force_config; | ||
135 | |||
136 | # do not force reboots on config problems | ||
137 | my $no_reboot = 1; | ||
138 | |||
139 | # default variables that can be used | ||
140 | chomp ($variable{"PWD"} = `pwd`); | ||
118 | 141 | ||
119 | $config_help{"MACHINE"} = << "EOF" | 142 | $config_help{"MACHINE"} = << "EOF" |
120 | The machine hostname that you will test. | 143 | The machine hostname that you will test. |
@@ -204,9 +227,30 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF" | |||
204 | EOF | 227 | EOF |
205 | ; | 228 | ; |
206 | 229 | ||
230 | sub read_yn { | ||
231 | my ($prompt) = @_; | ||
232 | |||
233 | my $ans; | ||
234 | |||
235 | for (;;) { | ||
236 | print "$prompt [Y/n] "; | ||
237 | $ans = <STDIN>; | ||
238 | chomp $ans; | ||
239 | if ($ans =~ /^\s*$/) { | ||
240 | $ans = "y"; | ||
241 | } | ||
242 | last if ($ans =~ /^y$/i || $ans =~ /^n$/i); | ||
243 | print "Please answer either 'y' or 'n'.\n"; | ||
244 | } | ||
245 | if ($ans !~ /^y$/i) { | ||
246 | return 0; | ||
247 | } | ||
248 | return 1; | ||
249 | } | ||
207 | 250 | ||
208 | sub get_ktest_config { | 251 | sub get_ktest_config { |
209 | my ($config) = @_; | 252 | my ($config) = @_; |
253 | my $ans; | ||
210 | 254 | ||
211 | return if (defined($opt{$config})); | 255 | return if (defined($opt{$config})); |
212 | 256 | ||
@@ -220,16 +264,17 @@ sub get_ktest_config { | |||
220 | if (defined($default{$config})) { | 264 | if (defined($default{$config})) { |
221 | print "\[$default{$config}\] "; | 265 | print "\[$default{$config}\] "; |
222 | } | 266 | } |
223 | $entered_configs{$config} = <STDIN>; | 267 | $ans = <STDIN>; |
224 | $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/; | 268 | $ans =~ s/^\s*(.*\S)\s*$/$1/; |
225 | if ($entered_configs{$config} =~ /^\s*$/) { | 269 | if ($ans =~ /^\s*$/) { |
226 | if ($default{$config}) { | 270 | if ($default{$config}) { |
227 | $entered_configs{$config} = $default{$config}; | 271 | $ans = $default{$config}; |
228 | } else { | 272 | } else { |
229 | print "Your answer can not be blank\n"; | 273 | print "Your answer can not be blank\n"; |
230 | next; | 274 | next; |
231 | } | 275 | } |
232 | } | 276 | } |
277 | $entered_configs{$config} = process_variables($ans); | ||
233 | last; | 278 | last; |
234 | } | 279 | } |
235 | } | 280 | } |
@@ -264,7 +309,7 @@ sub get_ktest_configs { | |||
264 | } | 309 | } |
265 | 310 | ||
266 | sub process_variables { | 311 | sub process_variables { |
267 | my ($value) = @_; | 312 | my ($value, $remove_undef) = @_; |
268 | my $retval = ""; | 313 | my $retval = ""; |
269 | 314 | ||
270 | # We want to check for '\', and it is just easier | 315 | # We want to check for '\', and it is just easier |
@@ -282,6 +327,10 @@ sub process_variables { | |||
282 | $retval = "$retval$begin"; | 327 | $retval = "$retval$begin"; |
283 | if (defined($variable{$var})) { | 328 | if (defined($variable{$var})) { |
284 | $retval = "$retval$variable{$var}"; | 329 | $retval = "$retval$variable{$var}"; |
330 | } elsif (defined($remove_undef) && $remove_undef) { | ||
331 | # for if statements, any variable that is not defined, | ||
332 | # we simple convert to 0 | ||
333 | $retval = "${retval}0"; | ||
285 | } else { | 334 | } else { |
286 | # put back the origin piece. | 335 | # put back the origin piece. |
287 | $retval = "$retval\$\{$var\}"; | 336 | $retval = "$retval\$\{$var\}"; |
@@ -297,10 +346,17 @@ sub process_variables { | |||
297 | } | 346 | } |
298 | 347 | ||
299 | sub set_value { | 348 | sub set_value { |
300 | my ($lvalue, $rvalue) = @_; | 349 | my ($lvalue, $rvalue, $override, $overrides, $name) = @_; |
301 | 350 | ||
302 | if (defined($opt{$lvalue})) { | 351 | if (defined($opt{$lvalue})) { |
303 | die "Error: Option $lvalue defined more than once!\n"; | 352 | if (!$override || defined(${$overrides}{$lvalue})) { |
353 | my $extra = ""; | ||
354 | if ($override) { | ||
355 | $extra = "In the same override section!\n"; | ||
356 | } | ||
357 | die "$name: $.: Option $lvalue defined more than once!\n$extra"; | ||
358 | } | ||
359 | ${$overrides}{$lvalue} = $rvalue; | ||
304 | } | 360 | } |
305 | if ($rvalue =~ /^\s*$/) { | 361 | if ($rvalue =~ /^\s*$/) { |
306 | delete $opt{$lvalue}; | 362 | delete $opt{$lvalue}; |
@@ -321,84 +377,274 @@ sub set_variable { | |||
321 | } | 377 | } |
322 | } | 378 | } |
323 | 379 | ||
324 | sub read_config { | 380 | sub process_compare { |
325 | my ($config) = @_; | 381 | my ($lval, $cmp, $rval) = @_; |
382 | |||
383 | # remove whitespace | ||
384 | |||
385 | $lval =~ s/^\s*//; | ||
386 | $lval =~ s/\s*$//; | ||
387 | |||
388 | $rval =~ s/^\s*//; | ||
389 | $rval =~ s/\s*$//; | ||
390 | |||
391 | if ($cmp eq "==") { | ||
392 | return $lval eq $rval; | ||
393 | } elsif ($cmp eq "!=") { | ||
394 | return $lval ne $rval; | ||
395 | } | ||
396 | |||
397 | my $statement = "$lval $cmp $rval"; | ||
398 | my $ret = eval $statement; | ||
399 | |||
400 | # $@ stores error of eval | ||
401 | if ($@) { | ||
402 | return -1; | ||
403 | } | ||
404 | |||
405 | return $ret; | ||
406 | } | ||
407 | |||
408 | sub value_defined { | ||
409 | my ($val) = @_; | ||
410 | |||
411 | return defined($variable{$2}) || | ||
412 | defined($opt{$2}); | ||
413 | } | ||
414 | |||
415 | my $d = 0; | ||
416 | sub process_expression { | ||
417 | my ($name, $val) = @_; | ||
418 | |||
419 | my $c = $d++; | ||
420 | |||
421 | while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) { | ||
422 | my $express = $1; | ||
423 | |||
424 | if (process_expression($name, $express)) { | ||
425 | $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /; | ||
426 | } else { | ||
427 | $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | $d--; | ||
432 | my $OR = "\\|\\|"; | ||
433 | my $AND = "\\&\\&"; | ||
434 | |||
435 | while ($val =~ s/^(.*?)($OR|$AND)//) { | ||
436 | my $express = $1; | ||
437 | my $op = $2; | ||
326 | 438 | ||
327 | open(IN, $config) || die "can't read file $config"; | 439 | if (process_expression($name, $express)) { |
440 | if ($op eq "||") { | ||
441 | return 1; | ||
442 | } | ||
443 | } else { | ||
444 | if ($op eq "&&") { | ||
445 | return 0; | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if ($val =~ /(.*)(==|\!=|>=|<=|>|<)(.*)/) { | ||
451 | my $ret = process_compare($1, $2, $3); | ||
452 | if ($ret < 0) { | ||
453 | die "$name: $.: Unable to process comparison\n"; | ||
454 | } | ||
455 | return $ret; | ||
456 | } | ||
457 | |||
458 | if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) { | ||
459 | if (defined $1) { | ||
460 | return !value_defined($2); | ||
461 | } else { | ||
462 | return value_defined($2); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | if ($val =~ /^\s*0\s*$/) { | ||
467 | return 0; | ||
468 | } elsif ($val =~ /^\s*\d+\s*$/) { | ||
469 | return 1; | ||
470 | } | ||
471 | |||
472 | die ("$name: $.: Undefined content $val in if statement\n"); | ||
473 | } | ||
474 | |||
475 | sub process_if { | ||
476 | my ($name, $value) = @_; | ||
477 | |||
478 | # Convert variables and replace undefined ones with 0 | ||
479 | my $val = process_variables($value, 1); | ||
480 | my $ret = process_expression $name, $val; | ||
481 | |||
482 | return $ret; | ||
483 | } | ||
484 | |||
485 | sub __read_config { | ||
486 | my ($config, $current_test_num) = @_; | ||
487 | |||
488 | my $in; | ||
489 | open($in, $config) || die "can't read file $config"; | ||
328 | 490 | ||
329 | my $name = $config; | 491 | my $name = $config; |
330 | $name =~ s,.*/(.*),$1,; | 492 | $name =~ s,.*/(.*),$1,; |
331 | 493 | ||
332 | my $test_num = 0; | 494 | my $test_num = $$current_test_num; |
333 | my $default = 1; | 495 | my $default = 1; |
334 | my $repeat = 1; | 496 | my $repeat = 1; |
335 | my $num_tests_set = 0; | 497 | my $num_tests_set = 0; |
336 | my $skip = 0; | 498 | my $skip = 0; |
337 | my $rest; | 499 | my $rest; |
500 | my $line; | ||
501 | my $test_case = 0; | ||
502 | my $if = 0; | ||
503 | my $if_set = 0; | ||
504 | my $override = 0; | ||
338 | 505 | ||
339 | while (<IN>) { | 506 | my %overrides; |
507 | |||
508 | while (<$in>) { | ||
340 | 509 | ||
341 | # ignore blank lines and comments | 510 | # ignore blank lines and comments |
342 | next if (/^\s*$/ || /\s*\#/); | 511 | next if (/^\s*$/ || /\s*\#/); |
343 | 512 | ||
344 | if (/^\s*TEST_START(.*)/) { | 513 | if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) { |
345 | 514 | ||
346 | $rest = $1; | 515 | my $type = $1; |
516 | $rest = $2; | ||
517 | $line = $2; | ||
347 | 518 | ||
348 | if ($num_tests_set) { | 519 | my $old_test_num; |
349 | die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; | 520 | my $old_repeat; |
350 | } | 521 | $override = 0; |
351 | 522 | ||
352 | my $old_test_num = $test_num; | 523 | if ($type eq "TEST_START") { |
353 | my $old_repeat = $repeat; | ||
354 | 524 | ||
355 | $test_num += $repeat; | 525 | if ($num_tests_set) { |
356 | $default = 0; | 526 | die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; |
357 | $repeat = 1; | 527 | } |
528 | |||
529 | $old_test_num = $test_num; | ||
530 | $old_repeat = $repeat; | ||
531 | |||
532 | $test_num += $repeat; | ||
533 | $default = 0; | ||
534 | $repeat = 1; | ||
535 | } else { | ||
536 | $default = 1; | ||
537 | } | ||
358 | 538 | ||
359 | if ($rest =~ /\s+SKIP(.*)/) { | 539 | # If SKIP is anywhere in the line, the command will be skipped |
360 | $rest = $1; | 540 | if ($rest =~ s/\s+SKIP\b//) { |
361 | $skip = 1; | 541 | $skip = 1; |
362 | } else { | 542 | } else { |
543 | $test_case = 1; | ||
363 | $skip = 0; | 544 | $skip = 0; |
364 | } | 545 | } |
365 | 546 | ||
366 | if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) { | 547 | if ($rest =~ s/\sELSE\b//) { |
367 | $repeat = $1; | 548 | if (!$if) { |
368 | $rest = $2; | 549 | die "$name: $.: ELSE found with out matching IF section\n$_"; |
369 | $repeat_tests{"$test_num"} = $repeat; | 550 | } |
551 | $if = 0; | ||
552 | |||
553 | if ($if_set) { | ||
554 | $skip = 1; | ||
555 | } else { | ||
556 | $skip = 0; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if ($rest =~ s/\sIF\s+(.*)//) { | ||
561 | if (process_if($name, $1)) { | ||
562 | $if_set = 1; | ||
563 | } else { | ||
564 | $skip = 1; | ||
565 | } | ||
566 | $if = 1; | ||
567 | } else { | ||
568 | $if = 0; | ||
569 | $if_set = 0; | ||
370 | } | 570 | } |
371 | 571 | ||
372 | if ($rest =~ /\s+SKIP(.*)/) { | 572 | if (!$skip) { |
373 | $rest = $1; | 573 | if ($type eq "TEST_START") { |
374 | $skip = 1; | 574 | if ($rest =~ s/\s+ITERATE\s+(\d+)//) { |
575 | $repeat = $1; | ||
576 | $repeat_tests{"$test_num"} = $repeat; | ||
577 | } | ||
578 | } elsif ($rest =~ s/\sOVERRIDE\b//) { | ||
579 | # DEFAULT only | ||
580 | $override = 1; | ||
581 | # Clear previous overrides | ||
582 | %overrides = (); | ||
583 | } | ||
375 | } | 584 | } |
376 | 585 | ||
377 | if ($rest !~ /^\s*$/) { | 586 | if (!$skip && $rest !~ /^\s*$/) { |
378 | die "$name: $.: Gargbage found after TEST_START\n$_"; | 587 | die "$name: $.: Gargbage found after $type\n$_"; |
379 | } | 588 | } |
380 | 589 | ||
381 | if ($skip) { | 590 | if ($skip && $type eq "TEST_START") { |
382 | $test_num = $old_test_num; | 591 | $test_num = $old_test_num; |
383 | $repeat = $old_repeat; | 592 | $repeat = $old_repeat; |
384 | } | 593 | } |
385 | 594 | ||
386 | } elsif (/^\s*DEFAULTS(.*)$/) { | 595 | } elsif (/^\s*ELSE\b(.*)$/) { |
387 | $default = 1; | 596 | if (!$if) { |
388 | 597 | die "$name: $.: ELSE found with out matching IF section\n$_"; | |
598 | } | ||
389 | $rest = $1; | 599 | $rest = $1; |
390 | 600 | if ($if_set) { | |
391 | if ($rest =~ /\s+SKIP(.*)/) { | ||
392 | $rest = $1; | ||
393 | $skip = 1; | 601 | $skip = 1; |
602 | $rest = ""; | ||
394 | } else { | 603 | } else { |
395 | $skip = 0; | 604 | $skip = 0; |
605 | |||
606 | if ($rest =~ /\sIF\s+(.*)/) { | ||
607 | # May be a ELSE IF section. | ||
608 | if (!process_if($name, $1)) { | ||
609 | $skip = 1; | ||
610 | } | ||
611 | $rest = ""; | ||
612 | } else { | ||
613 | $if = 0; | ||
614 | } | ||
396 | } | 615 | } |
397 | 616 | ||
398 | if ($rest !~ /^\s*$/) { | 617 | if ($rest !~ /^\s*$/) { |
399 | die "$name: $.: Gargbage found after DEFAULTS\n$_"; | 618 | die "$name: $.: Gargbage found after DEFAULTS\n$_"; |
400 | } | 619 | } |
401 | 620 | ||
621 | } elsif (/^\s*INCLUDE\s+(\S+)/) { | ||
622 | |||
623 | next if ($skip); | ||
624 | |||
625 | if (!$default) { | ||
626 | die "$name: $.: INCLUDE can only be done in default sections\n$_"; | ||
627 | } | ||
628 | |||
629 | my $file = process_variables($1); | ||
630 | |||
631 | if ($file !~ m,^/,) { | ||
632 | # check the path of the config file first | ||
633 | if ($config =~ m,(.*)/,) { | ||
634 | if (-f "$1/$file") { | ||
635 | $file = "$1/$file"; | ||
636 | } | ||
637 | } | ||
638 | } | ||
639 | |||
640 | if ( ! -r $file ) { | ||
641 | die "$name: $.: Can't read file $file\n$_"; | ||
642 | } | ||
643 | |||
644 | if (__read_config($file, \$test_num)) { | ||
645 | $test_case = 1; | ||
646 | } | ||
647 | |||
402 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { | 648 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { |
403 | 649 | ||
404 | next if ($skip); | 650 | next if ($skip); |
@@ -424,10 +670,10 @@ sub read_config { | |||
424 | } | 670 | } |
425 | 671 | ||
426 | if ($default || $lvalue =~ /\[\d+\]$/) { | 672 | if ($default || $lvalue =~ /\[\d+\]$/) { |
427 | set_value($lvalue, $rvalue); | 673 | set_value($lvalue, $rvalue, $override, \%overrides, $name); |
428 | } else { | 674 | } else { |
429 | my $val = "$lvalue\[$test_num\]"; | 675 | my $val = "$lvalue\[$test_num\]"; |
430 | set_value($val, $rvalue); | 676 | set_value($val, $rvalue, $override, \%overrides, $name); |
431 | 677 | ||
432 | if ($repeat > 1) { | 678 | if ($repeat > 1) { |
433 | $repeats{$val} = $repeat; | 679 | $repeats{$val} = $repeat; |
@@ -454,16 +700,38 @@ sub read_config { | |||
454 | } | 700 | } |
455 | } | 701 | } |
456 | 702 | ||
457 | close(IN); | ||
458 | |||
459 | if ($test_num) { | 703 | if ($test_num) { |
460 | $test_num += $repeat - 1; | 704 | $test_num += $repeat - 1; |
461 | $opt{"NUM_TESTS"} = $test_num; | 705 | $opt{"NUM_TESTS"} = $test_num; |
462 | } | 706 | } |
463 | 707 | ||
708 | close($in); | ||
709 | |||
710 | $$current_test_num = $test_num; | ||
711 | |||
712 | return $test_case; | ||
713 | } | ||
714 | |||
715 | sub read_config { | ||
716 | my ($config) = @_; | ||
717 | |||
718 | my $test_case; | ||
719 | my $test_num = 0; | ||
720 | |||
721 | $test_case = __read_config $config, \$test_num; | ||
722 | |||
464 | # make sure we have all mandatory configs | 723 | # make sure we have all mandatory configs |
465 | get_ktest_configs; | 724 | get_ktest_configs; |
466 | 725 | ||
726 | # was a test specified? | ||
727 | if (!$test_case) { | ||
728 | print "No test case specified.\n"; | ||
729 | print "What test case would you like to run?\n"; | ||
730 | my $ans = <STDIN>; | ||
731 | chomp $ans; | ||
732 | $default{"TEST_TYPE"} = $ans; | ||
733 | } | ||
734 | |||
467 | # set any defaults | 735 | # set any defaults |
468 | 736 | ||
469 | foreach my $default (keys %default) { | 737 | foreach my $default (keys %default) { |
@@ -473,6 +741,85 @@ sub read_config { | |||
473 | } | 741 | } |
474 | } | 742 | } |
475 | 743 | ||
744 | sub __eval_option { | ||
745 | my ($option, $i) = @_; | ||
746 | |||
747 | # Add space to evaluate the character before $ | ||
748 | $option = " $option"; | ||
749 | my $retval = ""; | ||
750 | my $repeated = 0; | ||
751 | my $parent = 0; | ||
752 | |||
753 | foreach my $test (keys %repeat_tests) { | ||
754 | if ($i >= $test && | ||
755 | $i < $test + $repeat_tests{$test}) { | ||
756 | |||
757 | $repeated = 1; | ||
758 | $parent = $test; | ||
759 | last; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { | ||
764 | my $start = $1; | ||
765 | my $var = $2; | ||
766 | my $end = $3; | ||
767 | |||
768 | # Append beginning of line | ||
769 | $retval = "$retval$start"; | ||
770 | |||
771 | # If the iteration option OPT[$i] exists, then use that. | ||
772 | # otherwise see if the default OPT (without [$i]) exists. | ||
773 | |||
774 | my $o = "$var\[$i\]"; | ||
775 | my $parento = "$var\[$parent\]"; | ||
776 | |||
777 | if (defined($opt{$o})) { | ||
778 | $o = $opt{$o}; | ||
779 | $retval = "$retval$o"; | ||
780 | } elsif ($repeated && defined($opt{$parento})) { | ||
781 | $o = $opt{$parento}; | ||
782 | $retval = "$retval$o"; | ||
783 | } elsif (defined($opt{$var})) { | ||
784 | $o = $opt{$var}; | ||
785 | $retval = "$retval$o"; | ||
786 | } else { | ||
787 | $retval = "$retval\$\{$var\}"; | ||
788 | } | ||
789 | |||
790 | $option = $end; | ||
791 | } | ||
792 | |||
793 | $retval = "$retval$option"; | ||
794 | |||
795 | $retval =~ s/^ //; | ||
796 | |||
797 | return $retval; | ||
798 | } | ||
799 | |||
800 | sub eval_option { | ||
801 | my ($option, $i) = @_; | ||
802 | |||
803 | my $prev = ""; | ||
804 | |||
805 | # Since an option can evaluate to another option, | ||
806 | # keep iterating until we do not evaluate any more | ||
807 | # options. | ||
808 | my $r = 0; | ||
809 | while ($prev ne $option) { | ||
810 | # Check for recursive evaluations. | ||
811 | # 100 deep should be more than enough. | ||
812 | if ($r++ > 100) { | ||
813 | die "Over 100 evaluations accurred with $option\n" . | ||
814 | "Check for recursive variables\n"; | ||
815 | } | ||
816 | $prev = $option; | ||
817 | $option = __eval_option($option, $i); | ||
818 | } | ||
819 | |||
820 | return $option; | ||
821 | } | ||
822 | |||
476 | sub _logit { | 823 | sub _logit { |
477 | if (defined($opt{"LOG_FILE"})) { | 824 | if (defined($opt{"LOG_FILE"})) { |
478 | open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; | 825 | open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; |
@@ -495,8 +842,20 @@ sub doprint { | |||
495 | } | 842 | } |
496 | 843 | ||
497 | sub run_command; | 844 | sub run_command; |
845 | sub start_monitor; | ||
846 | sub end_monitor; | ||
847 | sub wait_for_monitor; | ||
498 | 848 | ||
499 | sub reboot { | 849 | sub reboot { |
850 | my ($time) = @_; | ||
851 | |||
852 | if (defined($time)) { | ||
853 | start_monitor; | ||
854 | # flush out current monitor | ||
855 | # May contain the reboot success line | ||
856 | wait_for_monitor 1; | ||
857 | } | ||
858 | |||
500 | # try to reboot normally | 859 | # try to reboot normally |
501 | if (run_command $reboot) { | 860 | if (run_command $reboot) { |
502 | if (defined($powercycle_after_reboot)) { | 861 | if (defined($powercycle_after_reboot)) { |
@@ -507,12 +866,17 @@ sub reboot { | |||
507 | # nope? power cycle it. | 866 | # nope? power cycle it. |
508 | run_command "$power_cycle"; | 867 | run_command "$power_cycle"; |
509 | } | 868 | } |
869 | |||
870 | if (defined($time)) { | ||
871 | wait_for_monitor($time, $reboot_success_line); | ||
872 | end_monitor; | ||
873 | } | ||
510 | } | 874 | } |
511 | 875 | ||
512 | sub do_not_reboot { | 876 | sub do_not_reboot { |
513 | my $i = $iteration; | 877 | my $i = $iteration; |
514 | 878 | ||
515 | return $test_type eq "build" || | 879 | return $test_type eq "build" || $no_reboot || |
516 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || | 880 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || |
517 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); | 881 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); |
518 | } | 882 | } |
@@ -585,16 +949,29 @@ sub end_monitor { | |||
585 | } | 949 | } |
586 | 950 | ||
587 | sub wait_for_monitor { | 951 | sub wait_for_monitor { |
588 | my ($time) = @_; | 952 | my ($time, $stop) = @_; |
953 | my $full_line = ""; | ||
589 | my $line; | 954 | my $line; |
955 | my $booted = 0; | ||
590 | 956 | ||
591 | doprint "** Wait for monitor to settle down **\n"; | 957 | doprint "** Wait for monitor to settle down **\n"; |
592 | 958 | ||
593 | # read the monitor and wait for the system to calm down | 959 | # read the monitor and wait for the system to calm down |
594 | do { | 960 | while (!$booted) { |
595 | $line = wait_for_input($monitor_fp, $time); | 961 | $line = wait_for_input($monitor_fp, $time); |
596 | print "$line" if (defined($line)); | 962 | last if (!defined($line)); |
597 | } while (defined($line)); | 963 | print "$line"; |
964 | $full_line .= $line; | ||
965 | |||
966 | if (defined($stop) && $full_line =~ /$stop/) { | ||
967 | doprint "wait for monitor detected $stop\n"; | ||
968 | $booted = 1; | ||
969 | } | ||
970 | |||
971 | if ($line =~ /\n/) { | ||
972 | $full_line = ""; | ||
973 | } | ||
974 | } | ||
598 | print "** Monitor flushed **\n"; | 975 | print "** Monitor flushed **\n"; |
599 | } | 976 | } |
600 | 977 | ||
@@ -611,15 +988,18 @@ sub fail { | |||
611 | # no need to reboot for just building. | 988 | # no need to reboot for just building. |
612 | if (!do_not_reboot) { | 989 | if (!do_not_reboot) { |
613 | doprint "REBOOTING\n"; | 990 | doprint "REBOOTING\n"; |
614 | reboot; | 991 | reboot $sleep_time; |
615 | start_monitor; | 992 | } |
616 | wait_for_monitor $sleep_time; | 993 | |
617 | end_monitor; | 994 | my $name = ""; |
995 | |||
996 | if (defined($test_name)) { | ||
997 | $name = " ($test_name)"; | ||
618 | } | 998 | } |
619 | 999 | ||
620 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; | 1000 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; |
621 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; | 1001 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; |
622 | doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n"; | 1002 | doprint "KTEST RESULT: TEST $i$name Failed: ", @_, "\n"; |
623 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; | 1003 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; |
624 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; | 1004 | doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; |
625 | 1005 | ||
@@ -740,9 +1120,12 @@ sub get_grub_index { | |||
740 | open(IN, "$ssh_grub |") | 1120 | open(IN, "$ssh_grub |") |
741 | or die "unable to get menu.lst"; | 1121 | or die "unable to get menu.lst"; |
742 | 1122 | ||
1123 | my $found = 0; | ||
1124 | |||
743 | while (<IN>) { | 1125 | while (<IN>) { |
744 | if (/^\s*title\s+$grub_menu\s*$/) { | 1126 | if (/^\s*title\s+$grub_menu\s*$/) { |
745 | $grub_number++; | 1127 | $grub_number++; |
1128 | $found = 1; | ||
746 | last; | 1129 | last; |
747 | } elsif (/^\s*title\s/) { | 1130 | } elsif (/^\s*title\s/) { |
748 | $grub_number++; | 1131 | $grub_number++; |
@@ -751,7 +1134,7 @@ sub get_grub_index { | |||
751 | close(IN); | 1134 | close(IN); |
752 | 1135 | ||
753 | die "Could not find '$grub_menu' in /boot/grub/menu on $machine" | 1136 | die "Could not find '$grub_menu' in /boot/grub/menu on $machine" |
754 | if ($grub_number < 0); | 1137 | if (!$found); |
755 | doprint "$grub_number\n"; | 1138 | doprint "$grub_number\n"; |
756 | } | 1139 | } |
757 | 1140 | ||
@@ -788,7 +1171,8 @@ sub wait_for_input | |||
788 | 1171 | ||
789 | sub reboot_to { | 1172 | sub reboot_to { |
790 | if ($reboot_type eq "grub") { | 1173 | if ($reboot_type eq "grub") { |
791 | run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'"; | 1174 | run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; |
1175 | reboot; | ||
792 | return; | 1176 | return; |
793 | } | 1177 | } |
794 | 1178 | ||
@@ -836,17 +1220,35 @@ sub monitor { | |||
836 | my $failure_start; | 1220 | my $failure_start; |
837 | my $monitor_start = time; | 1221 | my $monitor_start = time; |
838 | my $done = 0; | 1222 | my $done = 0; |
1223 | my $version_found = 0; | ||
839 | 1224 | ||
840 | while (!$done) { | 1225 | while (!$done) { |
841 | 1226 | ||
842 | if ($booted) { | 1227 | if ($bug && defined($stop_after_failure) && |
1228 | $stop_after_failure >= 0) { | ||
1229 | my $time = $stop_after_failure - (time - $failure_start); | ||
1230 | $line = wait_for_input($monitor_fp, $time); | ||
1231 | if (!defined($line)) { | ||
1232 | doprint "bug timed out after $booted_timeout seconds\n"; | ||
1233 | doprint "Test forced to stop after $stop_after_failure seconds after failure\n"; | ||
1234 | last; | ||
1235 | } | ||
1236 | } elsif ($booted) { | ||
843 | $line = wait_for_input($monitor_fp, $booted_timeout); | 1237 | $line = wait_for_input($monitor_fp, $booted_timeout); |
1238 | if (!defined($line)) { | ||
1239 | my $s = $booted_timeout == 1 ? "" : "s"; | ||
1240 | doprint "Successful boot found: break after $booted_timeout second$s\n"; | ||
1241 | last; | ||
1242 | } | ||
844 | } else { | 1243 | } else { |
845 | $line = wait_for_input($monitor_fp); | 1244 | $line = wait_for_input($monitor_fp); |
1245 | if (!defined($line)) { | ||
1246 | my $s = $timeout == 1 ? "" : "s"; | ||
1247 | doprint "Timed out after $timeout second$s\n"; | ||
1248 | last; | ||
1249 | } | ||
846 | } | 1250 | } |
847 | 1251 | ||
848 | last if (!defined($line)); | ||
849 | |||
850 | doprint $line; | 1252 | doprint $line; |
851 | print DMESG $line; | 1253 | print DMESG $line; |
852 | 1254 | ||
@@ -896,6 +1298,22 @@ sub monitor { | |||
896 | $bug = 1; | 1298 | $bug = 1; |
897 | } | 1299 | } |
898 | 1300 | ||
1301 | # Detect triple faults by testing the banner | ||
1302 | if ($full_line =~ /\bLinux version (\S+).*\n/) { | ||
1303 | if ($1 eq $version) { | ||
1304 | $version_found = 1; | ||
1305 | } elsif ($version_found && $detect_triplefault) { | ||
1306 | # We already booted into the kernel we are testing, | ||
1307 | # but now we booted into another kernel? | ||
1308 | # Consider this a triple fault. | ||
1309 | doprint "Aleady booted in Linux kernel $version, but now\n"; | ||
1310 | doprint "we booted into Linux kernel $1.\n"; | ||
1311 | doprint "Assuming that this is a triple fault.\n"; | ||
1312 | doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n"; | ||
1313 | last; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
899 | if ($line =~ /\n/) { | 1317 | if ($line =~ /\n/) { |
900 | $full_line = ""; | 1318 | $full_line = ""; |
901 | } | 1319 | } |
@@ -923,8 +1341,20 @@ sub monitor { | |||
923 | return 1; | 1341 | return 1; |
924 | } | 1342 | } |
925 | 1343 | ||
1344 | sub do_post_install { | ||
1345 | |||
1346 | return if (!defined($post_install)); | ||
1347 | |||
1348 | my $cp_post_install = $post_install; | ||
1349 | $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; | ||
1350 | run_command "$cp_post_install" or | ||
1351 | dodie "Failed to run post install"; | ||
1352 | } | ||
1353 | |||
926 | sub install { | 1354 | sub install { |
927 | 1355 | ||
1356 | return if ($no_install); | ||
1357 | |||
928 | run_scp "$outputdir/$build_target", "$target_image" or | 1358 | run_scp "$outputdir/$build_target", "$target_image" or |
929 | dodie "failed to copy image"; | 1359 | dodie "failed to copy image"; |
930 | 1360 | ||
@@ -942,6 +1372,7 @@ sub install { | |||
942 | close(IN); | 1372 | close(IN); |
943 | 1373 | ||
944 | if (!$install_mods) { | 1374 | if (!$install_mods) { |
1375 | do_post_install; | ||
945 | doprint "No modules needed\n"; | 1376 | doprint "No modules needed\n"; |
946 | return; | 1377 | return; |
947 | } | 1378 | } |
@@ -964,17 +1395,34 @@ sub install { | |||
964 | 1395 | ||
965 | unlink "$tmpdir/$modtar"; | 1396 | unlink "$tmpdir/$modtar"; |
966 | 1397 | ||
967 | run_ssh "'(cd / && tar xf /tmp/$modtar)'" or | 1398 | run_ssh "'(cd / && tar xjf /tmp/$modtar)'" or |
968 | dodie "failed to tar modules"; | 1399 | dodie "failed to tar modules"; |
969 | 1400 | ||
970 | run_ssh "rm -f /tmp/$modtar"; | 1401 | run_ssh "rm -f /tmp/$modtar"; |
971 | 1402 | ||
972 | return if (!defined($post_install)); | 1403 | do_post_install; |
1404 | } | ||
973 | 1405 | ||
974 | my $cp_post_install = $post_install; | 1406 | sub get_version { |
975 | $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; | 1407 | # get the release name |
976 | run_command "$cp_post_install" or | 1408 | doprint "$make kernelrelease ... "; |
977 | dodie "Failed to run post install"; | 1409 | $version = `$make kernelrelease | tail -1`; |
1410 | chomp($version); | ||
1411 | doprint "$version\n"; | ||
1412 | } | ||
1413 | |||
1414 | sub start_monitor_and_boot { | ||
1415 | # Make sure the stable kernel has finished booting | ||
1416 | start_monitor; | ||
1417 | wait_for_monitor 5; | ||
1418 | end_monitor; | ||
1419 | |||
1420 | get_grub_index; | ||
1421 | get_version; | ||
1422 | install; | ||
1423 | |||
1424 | start_monitor; | ||
1425 | return monitor; | ||
978 | } | 1426 | } |
979 | 1427 | ||
980 | sub check_buildlog { | 1428 | sub check_buildlog { |
@@ -1009,24 +1457,88 @@ sub check_buildlog { | |||
1009 | return 1; | 1457 | return 1; |
1010 | } | 1458 | } |
1011 | 1459 | ||
1460 | sub apply_min_config { | ||
1461 | my $outconfig = "$output_config.new"; | ||
1462 | |||
1463 | # Read the config file and remove anything that | ||
1464 | # is in the force_config hash (from minconfig and others) | ||
1465 | # then add the force config back. | ||
1466 | |||
1467 | doprint "Applying minimum configurations into $output_config.new\n"; | ||
1468 | |||
1469 | open (OUT, ">$outconfig") or | ||
1470 | dodie "Can't create $outconfig"; | ||
1471 | |||
1472 | if (-f $output_config) { | ||
1473 | open (IN, $output_config) or | ||
1474 | dodie "Failed to open $output_config"; | ||
1475 | while (<IN>) { | ||
1476 | if (/^(# )?(CONFIG_[^\s=]*)/) { | ||
1477 | next if (defined($force_config{$2})); | ||
1478 | } | ||
1479 | print OUT; | ||
1480 | } | ||
1481 | close IN; | ||
1482 | } | ||
1483 | foreach my $config (keys %force_config) { | ||
1484 | print OUT "$force_config{$config}\n"; | ||
1485 | } | ||
1486 | close OUT; | ||
1487 | |||
1488 | run_command "mv $outconfig $output_config"; | ||
1489 | } | ||
1490 | |||
1012 | sub make_oldconfig { | 1491 | sub make_oldconfig { |
1013 | my ($defconfig) = @_; | ||
1014 | 1492 | ||
1015 | if (!run_command "$defconfig $make oldnoconfig") { | 1493 | my @force_list = keys %force_config; |
1494 | |||
1495 | if ($#force_list >= 0) { | ||
1496 | apply_min_config; | ||
1497 | } | ||
1498 | |||
1499 | if (!run_command "$make oldnoconfig") { | ||
1016 | # Perhaps oldnoconfig doesn't exist in this version of the kernel | 1500 | # Perhaps oldnoconfig doesn't exist in this version of the kernel |
1017 | # try a yes '' | oldconfig | 1501 | # try a yes '' | oldconfig |
1018 | doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; | 1502 | doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; |
1019 | run_command "yes '' | $defconfig $make oldconfig" or | 1503 | run_command "yes '' | $make oldconfig" or |
1020 | dodie "failed make config oldconfig"; | 1504 | dodie "failed make config oldconfig"; |
1021 | } | 1505 | } |
1022 | } | 1506 | } |
1023 | 1507 | ||
1508 | # read a config file and use this to force new configs. | ||
1509 | sub load_force_config { | ||
1510 | my ($config) = @_; | ||
1511 | |||
1512 | open(IN, $config) or | ||
1513 | dodie "failed to read $config"; | ||
1514 | while (<IN>) { | ||
1515 | chomp; | ||
1516 | if (/^(CONFIG[^\s=]*)(\s*=.*)/) { | ||
1517 | $force_config{$1} = $_; | ||
1518 | } elsif (/^# (CONFIG_\S*) is not set/) { | ||
1519 | $force_config{$1} = $_; | ||
1520 | } | ||
1521 | } | ||
1522 | close IN; | ||
1523 | } | ||
1524 | |||
1024 | sub build { | 1525 | sub build { |
1025 | my ($type) = @_; | 1526 | my ($type) = @_; |
1026 | my $defconfig = ""; | ||
1027 | 1527 | ||
1028 | unlink $buildlog; | 1528 | unlink $buildlog; |
1029 | 1529 | ||
1530 | # Failed builds should not reboot the target | ||
1531 | my $save_no_reboot = $no_reboot; | ||
1532 | $no_reboot = 1; | ||
1533 | |||
1534 | if (defined($pre_build)) { | ||
1535 | my $ret = run_command $pre_build; | ||
1536 | if (!$ret && defined($pre_build_die) && | ||
1537 | $pre_build_die) { | ||
1538 | dodie "failed to pre_build\n"; | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1030 | if ($type =~ /^useconfig:(.*)/) { | 1542 | if ($type =~ /^useconfig:(.*)/) { |
1031 | run_command "cp $1 $output_config" or | 1543 | run_command "cp $1 $output_config" or |
1032 | dodie "could not copy $1 to .config"; | 1544 | dodie "could not copy $1 to .config"; |
@@ -1041,15 +1553,15 @@ sub build { | |||
1041 | # allow for empty configs | 1553 | # allow for empty configs |
1042 | run_command "touch $output_config"; | 1554 | run_command "touch $output_config"; |
1043 | 1555 | ||
1044 | run_command "mv $output_config $outputdir/config_temp" or | 1556 | if (!$noclean) { |
1045 | dodie "moving .config"; | 1557 | run_command "mv $output_config $outputdir/config_temp" or |
1558 | dodie "moving .config"; | ||
1046 | 1559 | ||
1047 | if (!$noclean && !run_command "$make mrproper") { | 1560 | run_command "$make mrproper" or dodie "make mrproper"; |
1048 | dodie "make mrproper"; | ||
1049 | } | ||
1050 | 1561 | ||
1051 | run_command "mv $outputdir/config_temp $output_config" or | 1562 | run_command "mv $outputdir/config_temp $output_config" or |
1052 | dodie "moving config_temp"; | 1563 | dodie "moving config_temp"; |
1564 | } | ||
1053 | 1565 | ||
1054 | } elsif (!$noclean) { | 1566 | } elsif (!$noclean) { |
1055 | unlink "$output_config"; | 1567 | unlink "$output_config"; |
@@ -1063,24 +1575,38 @@ sub build { | |||
1063 | close(OUT); | 1575 | close(OUT); |
1064 | 1576 | ||
1065 | if (defined($minconfig)) { | 1577 | if (defined($minconfig)) { |
1066 | $defconfig = "KCONFIG_ALLCONFIG=$minconfig"; | 1578 | load_force_config($minconfig); |
1067 | } | 1579 | } |
1068 | 1580 | ||
1069 | if ($type eq "oldnoconfig") { | 1581 | if ($type ne "oldnoconfig") { |
1070 | make_oldconfig $defconfig; | 1582 | run_command "$make $type" or |
1071 | } else { | ||
1072 | run_command "$defconfig $make $type" or | ||
1073 | dodie "failed make config"; | 1583 | dodie "failed make config"; |
1074 | } | 1584 | } |
1585 | # Run old config regardless, to enforce min configurations | ||
1586 | make_oldconfig; | ||
1075 | 1587 | ||
1076 | $redirect = "$buildlog"; | 1588 | $redirect = "$buildlog"; |
1077 | if (!run_command "$make $build_options") { | 1589 | my $build_ret = run_command "$make $build_options"; |
1078 | undef $redirect; | 1590 | undef $redirect; |
1591 | |||
1592 | if (defined($post_build)) { | ||
1593 | my $ret = run_command $post_build; | ||
1594 | if (!$ret && defined($post_build_die) && | ||
1595 | $post_build_die) { | ||
1596 | dodie "failed to post_build\n"; | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | if (!$build_ret) { | ||
1079 | # bisect may need this to pass | 1601 | # bisect may need this to pass |
1080 | return 0 if ($in_bisect); | 1602 | if ($in_bisect) { |
1603 | $no_reboot = $save_no_reboot; | ||
1604 | return 0; | ||
1605 | } | ||
1081 | fail "failed build" and return 0; | 1606 | fail "failed build" and return 0; |
1082 | } | 1607 | } |
1083 | undef $redirect; | 1608 | |
1609 | $no_reboot = $save_no_reboot; | ||
1084 | 1610 | ||
1085 | return 1; | 1611 | return 1; |
1086 | } | 1612 | } |
@@ -1102,29 +1628,24 @@ sub success { | |||
1102 | 1628 | ||
1103 | $successes++; | 1629 | $successes++; |
1104 | 1630 | ||
1631 | my $name = ""; | ||
1632 | |||
1633 | if (defined($test_name)) { | ||
1634 | $name = " ($test_name)"; | ||
1635 | } | ||
1636 | |||
1105 | doprint "\n\n*******************************************\n"; | 1637 | doprint "\n\n*******************************************\n"; |
1106 | doprint "*******************************************\n"; | 1638 | doprint "*******************************************\n"; |
1107 | doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n"; | 1639 | doprint "KTEST RESULT: TEST $i$name SUCCESS!!!! **\n"; |
1108 | doprint "*******************************************\n"; | 1640 | doprint "*******************************************\n"; |
1109 | doprint "*******************************************\n"; | 1641 | doprint "*******************************************\n"; |
1110 | 1642 | ||
1111 | if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { | 1643 | if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { |
1112 | doprint "Reboot and wait $sleep_time seconds\n"; | 1644 | doprint "Reboot and wait $sleep_time seconds\n"; |
1113 | reboot; | 1645 | reboot $sleep_time; |
1114 | start_monitor; | ||
1115 | wait_for_monitor $sleep_time; | ||
1116 | end_monitor; | ||
1117 | } | 1646 | } |
1118 | } | 1647 | } |
1119 | 1648 | ||
1120 | sub get_version { | ||
1121 | # get the release name | ||
1122 | doprint "$make kernelrelease ... "; | ||
1123 | $version = `$make kernelrelease | tail -1`; | ||
1124 | chomp($version); | ||
1125 | doprint "$version\n"; | ||
1126 | } | ||
1127 | |||
1128 | sub answer_bisect { | 1649 | sub answer_bisect { |
1129 | for (;;) { | 1650 | for (;;) { |
1130 | doprint "Pass or fail? [p/f]"; | 1651 | doprint "Pass or fail? [p/f]"; |
@@ -1262,10 +1783,7 @@ sub run_git_bisect { | |||
1262 | 1783 | ||
1263 | sub bisect_reboot { | 1784 | sub bisect_reboot { |
1264 | doprint "Reboot and sleep $bisect_sleep_time seconds\n"; | 1785 | doprint "Reboot and sleep $bisect_sleep_time seconds\n"; |
1265 | reboot; | 1786 | reboot $bisect_sleep_time; |
1266 | start_monitor; | ||
1267 | wait_for_monitor $bisect_sleep_time; | ||
1268 | end_monitor; | ||
1269 | } | 1787 | } |
1270 | 1788 | ||
1271 | # returns 1 on success, 0 on failure, -1 on skip | 1789 | # returns 1 on success, 0 on failure, -1 on skip |
@@ -1289,12 +1807,7 @@ sub run_bisect_test { | |||
1289 | dodie "Failed on build" if $failed; | 1807 | dodie "Failed on build" if $failed; |
1290 | 1808 | ||
1291 | # Now boot the box | 1809 | # Now boot the box |
1292 | get_grub_index; | 1810 | start_monitor_and_boot or $failed = 1; |
1293 | get_version; | ||
1294 | install; | ||
1295 | |||
1296 | start_monitor; | ||
1297 | monitor or $failed = 1; | ||
1298 | 1811 | ||
1299 | if ($type ne "boot") { | 1812 | if ($type ne "boot") { |
1300 | if ($failed && $bisect_skip) { | 1813 | if ($failed && $bisect_skip) { |
@@ -1473,21 +1986,27 @@ my %null_config; | |||
1473 | 1986 | ||
1474 | my %dependency; | 1987 | my %dependency; |
1475 | 1988 | ||
1476 | sub process_config_ignore { | 1989 | sub assign_configs { |
1477 | my ($config) = @_; | 1990 | my ($hash, $config) = @_; |
1478 | 1991 | ||
1479 | open (IN, $config) | 1992 | open (IN, $config) |
1480 | or dodie "Failed to read $config"; | 1993 | or dodie "Failed to read $config"; |
1481 | 1994 | ||
1482 | while (<IN>) { | 1995 | while (<IN>) { |
1483 | if (/^((CONFIG\S*)=.*)/) { | 1996 | if (/^((CONFIG\S*)=.*)/) { |
1484 | $config_ignore{$2} = $1; | 1997 | ${$hash}{$2} = $1; |
1485 | } | 1998 | } |
1486 | } | 1999 | } |
1487 | 2000 | ||
1488 | close(IN); | 2001 | close(IN); |
1489 | } | 2002 | } |
1490 | 2003 | ||
2004 | sub process_config_ignore { | ||
2005 | my ($config) = @_; | ||
2006 | |||
2007 | assign_configs \%config_ignore, $config; | ||
2008 | } | ||
2009 | |||
1491 | sub read_current_config { | 2010 | sub read_current_config { |
1492 | my ($config_ref) = @_; | 2011 | my ($config_ref) = @_; |
1493 | 2012 | ||
@@ -1546,7 +2065,7 @@ sub create_config { | |||
1546 | close(OUT); | 2065 | close(OUT); |
1547 | 2066 | ||
1548 | # exit; | 2067 | # exit; |
1549 | make_oldconfig ""; | 2068 | make_oldconfig; |
1550 | } | 2069 | } |
1551 | 2070 | ||
1552 | sub compare_configs { | 2071 | sub compare_configs { |
@@ -1718,6 +2237,10 @@ sub config_bisect { | |||
1718 | 2237 | ||
1719 | my $tmpconfig = "$tmpdir/use_config"; | 2238 | my $tmpconfig = "$tmpdir/use_config"; |
1720 | 2239 | ||
2240 | if (defined($config_bisect_good)) { | ||
2241 | process_config_ignore $config_bisect_good; | ||
2242 | } | ||
2243 | |||
1721 | # Make the file with the bad config and the min config | 2244 | # Make the file with the bad config and the min config |
1722 | if (defined($minconfig)) { | 2245 | if (defined($minconfig)) { |
1723 | # read the min config for things to ignore | 2246 | # read the min config for things to ignore |
@@ -1727,15 +2250,8 @@ sub config_bisect { | |||
1727 | unlink $tmpconfig; | 2250 | unlink $tmpconfig; |
1728 | } | 2251 | } |
1729 | 2252 | ||
1730 | # Add other configs | ||
1731 | if (defined($addconfig)) { | ||
1732 | run_command "cat $addconfig >> $tmpconfig" or | ||
1733 | dodie "failed to append $addconfig"; | ||
1734 | } | ||
1735 | |||
1736 | my $defconfig = ""; | ||
1737 | if (-f $tmpconfig) { | 2253 | if (-f $tmpconfig) { |
1738 | $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig"; | 2254 | load_force_config($tmpconfig); |
1739 | process_config_ignore $tmpconfig; | 2255 | process_config_ignore $tmpconfig; |
1740 | } | 2256 | } |
1741 | 2257 | ||
@@ -1755,8 +2271,8 @@ sub config_bisect { | |||
1755 | } | 2271 | } |
1756 | close(IN); | 2272 | close(IN); |
1757 | 2273 | ||
1758 | # Now run oldconfig with the minconfig (and addconfigs) | 2274 | # Now run oldconfig with the minconfig |
1759 | make_oldconfig $defconfig; | 2275 | make_oldconfig; |
1760 | 2276 | ||
1761 | # check to see what we lost (or gained) | 2277 | # check to see what we lost (or gained) |
1762 | open (IN, $output_config) | 2278 | open (IN, $output_config) |
@@ -1830,10 +2346,7 @@ sub config_bisect { | |||
1830 | 2346 | ||
1831 | sub patchcheck_reboot { | 2347 | sub patchcheck_reboot { |
1832 | doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; | 2348 | doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; |
1833 | reboot; | 2349 | reboot $patchcheck_sleep_time; |
1834 | start_monitor; | ||
1835 | wait_for_monitor $patchcheck_sleep_time; | ||
1836 | end_monitor; | ||
1837 | } | 2350 | } |
1838 | 2351 | ||
1839 | sub patchcheck { | 2352 | sub patchcheck { |
@@ -1882,6 +2395,13 @@ sub patchcheck { | |||
1882 | @list = reverse @list; | 2395 | @list = reverse @list; |
1883 | 2396 | ||
1884 | my $save_clean = $noclean; | 2397 | my $save_clean = $noclean; |
2398 | my %ignored_warnings; | ||
2399 | |||
2400 | if (defined($ignore_warnings)) { | ||
2401 | foreach my $sha1 (split /\s+/, $ignore_warnings) { | ||
2402 | $ignored_warnings{$sha1} = 1; | ||
2403 | } | ||
2404 | } | ||
1885 | 2405 | ||
1886 | $in_patchcheck = 1; | 2406 | $in_patchcheck = 1; |
1887 | foreach my $item (@list) { | 2407 | foreach my $item (@list) { |
@@ -1908,18 +2428,16 @@ sub patchcheck { | |||
1908 | build "oldconfig" or return 0; | 2428 | build "oldconfig" or return 0; |
1909 | } | 2429 | } |
1910 | 2430 | ||
1911 | check_buildlog $sha1 or return 0; | ||
1912 | 2431 | ||
1913 | next if ($type eq "build"); | 2432 | if (!defined($ignored_warnings{$sha1})) { |
2433 | check_buildlog $sha1 or return 0; | ||
2434 | } | ||
1914 | 2435 | ||
1915 | get_grub_index; | 2436 | next if ($type eq "build"); |
1916 | get_version; | ||
1917 | install; | ||
1918 | 2437 | ||
1919 | my $failed = 0; | 2438 | my $failed = 0; |
1920 | 2439 | ||
1921 | start_monitor; | 2440 | start_monitor_and_boot or $failed = 1; |
1922 | monitor or $failed = 1; | ||
1923 | 2441 | ||
1924 | if (!$failed && $type ne "boot"){ | 2442 | if (!$failed && $type ne "boot"){ |
1925 | do_run_test or $failed = 1; | 2443 | do_run_test or $failed = 1; |
@@ -1936,24 +2454,529 @@ sub patchcheck { | |||
1936 | return 1; | 2454 | return 1; |
1937 | } | 2455 | } |
1938 | 2456 | ||
2457 | my %depends; | ||
2458 | my %depcount; | ||
2459 | my $iflevel = 0; | ||
2460 | my @ifdeps; | ||
2461 | |||
2462 | # prevent recursion | ||
2463 | my %read_kconfigs; | ||
2464 | |||
2465 | sub add_dep { | ||
2466 | # $config depends on $dep | ||
2467 | my ($config, $dep) = @_; | ||
2468 | |||
2469 | if (defined($depends{$config})) { | ||
2470 | $depends{$config} .= " " . $dep; | ||
2471 | } else { | ||
2472 | $depends{$config} = $dep; | ||
2473 | } | ||
2474 | |||
2475 | # record the number of configs depending on $dep | ||
2476 | if (defined $depcount{$dep}) { | ||
2477 | $depcount{$dep}++; | ||
2478 | } else { | ||
2479 | $depcount{$dep} = 1; | ||
2480 | } | ||
2481 | } | ||
2482 | |||
2483 | # taken from streamline_config.pl | ||
2484 | sub read_kconfig { | ||
2485 | my ($kconfig) = @_; | ||
2486 | |||
2487 | my $state = "NONE"; | ||
2488 | my $config; | ||
2489 | my @kconfigs; | ||
2490 | |||
2491 | my $cont = 0; | ||
2492 | my $line; | ||
2493 | |||
2494 | |||
2495 | if (! -f $kconfig) { | ||
2496 | doprint "file $kconfig does not exist, skipping\n"; | ||
2497 | return; | ||
2498 | } | ||
2499 | |||
2500 | open(KIN, "$kconfig") | ||
2501 | or die "Can't open $kconfig"; | ||
2502 | while (<KIN>) { | ||
2503 | chomp; | ||
2504 | |||
2505 | # Make sure that lines ending with \ continue | ||
2506 | if ($cont) { | ||
2507 | $_ = $line . " " . $_; | ||
2508 | } | ||
2509 | |||
2510 | if (s/\\$//) { | ||
2511 | $cont = 1; | ||
2512 | $line = $_; | ||
2513 | next; | ||
2514 | } | ||
2515 | |||
2516 | $cont = 0; | ||
2517 | |||
2518 | # collect any Kconfig sources | ||
2519 | if (/^source\s*"(.*)"/) { | ||
2520 | $kconfigs[$#kconfigs+1] = $1; | ||
2521 | } | ||
2522 | |||
2523 | # configs found | ||
2524 | if (/^\s*(menu)?config\s+(\S+)\s*$/) { | ||
2525 | $state = "NEW"; | ||
2526 | $config = $2; | ||
2527 | |||
2528 | for (my $i = 0; $i < $iflevel; $i++) { | ||
2529 | add_dep $config, $ifdeps[$i]; | ||
2530 | } | ||
2531 | |||
2532 | # collect the depends for the config | ||
2533 | } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { | ||
2534 | |||
2535 | add_dep $config, $1; | ||
2536 | |||
2537 | # Get the configs that select this config | ||
2538 | } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) { | ||
2539 | |||
2540 | # selected by depends on config | ||
2541 | add_dep $1, $config; | ||
2542 | |||
2543 | # Check for if statements | ||
2544 | } elsif (/^if\s+(.*\S)\s*$/) { | ||
2545 | my $deps = $1; | ||
2546 | # remove beginning and ending non text | ||
2547 | $deps =~ s/^[^a-zA-Z0-9_]*//; | ||
2548 | $deps =~ s/[^a-zA-Z0-9_]*$//; | ||
2549 | |||
2550 | my @deps = split /[^a-zA-Z0-9_]+/, $deps; | ||
2551 | |||
2552 | $ifdeps[$iflevel++] = join ':', @deps; | ||
2553 | |||
2554 | } elsif (/^endif/) { | ||
2555 | |||
2556 | $iflevel-- if ($iflevel); | ||
2557 | |||
2558 | # stop on "help" | ||
2559 | } elsif (/^\s*help\s*$/) { | ||
2560 | $state = "NONE"; | ||
2561 | } | ||
2562 | } | ||
2563 | close(KIN); | ||
2564 | |||
2565 | # read in any configs that were found. | ||
2566 | foreach $kconfig (@kconfigs) { | ||
2567 | if (!defined($read_kconfigs{$kconfig})) { | ||
2568 | $read_kconfigs{$kconfig} = 1; | ||
2569 | read_kconfig("$builddir/$kconfig"); | ||
2570 | } | ||
2571 | } | ||
2572 | } | ||
2573 | |||
2574 | sub read_depends { | ||
2575 | # find out which arch this is by the kconfig file | ||
2576 | open (IN, $output_config) | ||
2577 | or dodie "Failed to read $output_config"; | ||
2578 | my $arch; | ||
2579 | while (<IN>) { | ||
2580 | if (m,Linux/(\S+)\s+\S+\s+Kernel Configuration,) { | ||
2581 | $arch = $1; | ||
2582 | last; | ||
2583 | } | ||
2584 | } | ||
2585 | close IN; | ||
2586 | |||
2587 | if (!defined($arch)) { | ||
2588 | doprint "Could not find arch from config file\n"; | ||
2589 | doprint "no dependencies used\n"; | ||
2590 | return; | ||
2591 | } | ||
2592 | |||
2593 | # arch is really the subarch, we need to know | ||
2594 | # what directory to look at. | ||
2595 | if ($arch eq "i386" || $arch eq "x86_64") { | ||
2596 | $arch = "x86"; | ||
2597 | } elsif ($arch =~ /^tile/) { | ||
2598 | $arch = "tile"; | ||
2599 | } | ||
2600 | |||
2601 | my $kconfig = "$builddir/arch/$arch/Kconfig"; | ||
2602 | |||
2603 | if (! -f $kconfig && $arch =~ /\d$/) { | ||
2604 | my $orig = $arch; | ||
2605 | # some subarchs have numbers, truncate them | ||
2606 | $arch =~ s/\d*$//; | ||
2607 | $kconfig = "$builddir/arch/$arch/Kconfig"; | ||
2608 | if (! -f $kconfig) { | ||
2609 | doprint "No idea what arch dir $orig is for\n"; | ||
2610 | doprint "no dependencies used\n"; | ||
2611 | return; | ||
2612 | } | ||
2613 | } | ||
2614 | |||
2615 | read_kconfig($kconfig); | ||
2616 | } | ||
2617 | |||
2618 | sub read_config_list { | ||
2619 | my ($config) = @_; | ||
2620 | |||
2621 | open (IN, $config) | ||
2622 | or dodie "Failed to read $config"; | ||
2623 | |||
2624 | while (<IN>) { | ||
2625 | if (/^((CONFIG\S*)=.*)/) { | ||
2626 | if (!defined($config_ignore{$2})) { | ||
2627 | $config_list{$2} = $1; | ||
2628 | } | ||
2629 | } | ||
2630 | } | ||
2631 | |||
2632 | close(IN); | ||
2633 | } | ||
2634 | |||
2635 | sub read_output_config { | ||
2636 | my ($config) = @_; | ||
2637 | |||
2638 | assign_configs \%config_ignore, $config; | ||
2639 | } | ||
2640 | |||
2641 | sub make_new_config { | ||
2642 | my @configs = @_; | ||
2643 | |||
2644 | open (OUT, ">$output_config") | ||
2645 | or dodie "Failed to write $output_config"; | ||
2646 | |||
2647 | foreach my $config (@configs) { | ||
2648 | print OUT "$config\n"; | ||
2649 | } | ||
2650 | close OUT; | ||
2651 | } | ||
2652 | |||
2653 | sub chomp_config { | ||
2654 | my ($config) = @_; | ||
2655 | |||
2656 | $config =~ s/CONFIG_//; | ||
2657 | |||
2658 | return $config; | ||
2659 | } | ||
2660 | |||
2661 | sub get_depends { | ||
2662 | my ($dep) = @_; | ||
2663 | |||
2664 | my $kconfig = chomp_config $dep; | ||
2665 | |||
2666 | $dep = $depends{"$kconfig"}; | ||
2667 | |||
2668 | # the dep string we have saves the dependencies as they | ||
2669 | # were found, including expressions like ! && ||. We | ||
2670 | # want to split this out into just an array of configs. | ||
2671 | |||
2672 | my $valid = "A-Za-z_0-9"; | ||
2673 | |||
2674 | my @configs; | ||
2675 | |||
2676 | while ($dep =~ /[$valid]/) { | ||
2677 | |||
2678 | if ($dep =~ /^[^$valid]*([$valid]+)/) { | ||
2679 | my $conf = "CONFIG_" . $1; | ||
2680 | |||
2681 | $configs[$#configs + 1] = $conf; | ||
2682 | |||
2683 | $dep =~ s/^[^$valid]*[$valid]+//; | ||
2684 | } else { | ||
2685 | die "this should never happen"; | ||
2686 | } | ||
2687 | } | ||
2688 | |||
2689 | return @configs; | ||
2690 | } | ||
2691 | |||
2692 | my %min_configs; | ||
2693 | my %keep_configs; | ||
2694 | my %save_configs; | ||
2695 | my %processed_configs; | ||
2696 | my %nochange_config; | ||
2697 | |||
2698 | sub test_this_config { | ||
2699 | my ($config) = @_; | ||
2700 | |||
2701 | my $found; | ||
2702 | |||
2703 | # if we already processed this config, skip it | ||
2704 | if (defined($processed_configs{$config})) { | ||
2705 | return undef; | ||
2706 | } | ||
2707 | $processed_configs{$config} = 1; | ||
2708 | |||
2709 | # if this config failed during this round, skip it | ||
2710 | if (defined($nochange_config{$config})) { | ||
2711 | return undef; | ||
2712 | } | ||
2713 | |||
2714 | my $kconfig = chomp_config $config; | ||
2715 | |||
2716 | # Test dependencies first | ||
2717 | if (defined($depends{"$kconfig"})) { | ||
2718 | my @parents = get_depends $config; | ||
2719 | foreach my $parent (@parents) { | ||
2720 | # if the parent is in the min config, check it first | ||
2721 | next if (!defined($min_configs{$parent})); | ||
2722 | $found = test_this_config($parent); | ||
2723 | if (defined($found)) { | ||
2724 | return $found; | ||
2725 | } | ||
2726 | } | ||
2727 | } | ||
2728 | |||
2729 | # Remove this config from the list of configs | ||
2730 | # do a make oldnoconfig and then read the resulting | ||
2731 | # .config to make sure it is missing the config that | ||
2732 | # we had before | ||
2733 | my %configs = %min_configs; | ||
2734 | delete $configs{$config}; | ||
2735 | make_new_config ((values %configs), (values %keep_configs)); | ||
2736 | make_oldconfig; | ||
2737 | undef %configs; | ||
2738 | assign_configs \%configs, $output_config; | ||
2739 | |||
2740 | return $config if (!defined($configs{$config})); | ||
2741 | |||
2742 | doprint "disabling config $config did not change .config\n"; | ||
2743 | |||
2744 | $nochange_config{$config} = 1; | ||
2745 | |||
2746 | return undef; | ||
2747 | } | ||
2748 | |||
2749 | sub make_min_config { | ||
2750 | my ($i) = @_; | ||
2751 | |||
2752 | if (!defined($output_minconfig)) { | ||
2753 | fail "OUTPUT_MIN_CONFIG not defined" and return; | ||
2754 | } | ||
2755 | |||
2756 | # If output_minconfig exists, and the start_minconfig | ||
2757 | # came from min_config, than ask if we should use | ||
2758 | # that instead. | ||
2759 | if (-f $output_minconfig && !$start_minconfig_defined) { | ||
2760 | print "$output_minconfig exists\n"; | ||
2761 | if (read_yn " Use it as minconfig?") { | ||
2762 | $start_minconfig = $output_minconfig; | ||
2763 | } | ||
2764 | } | ||
2765 | |||
2766 | if (!defined($start_minconfig)) { | ||
2767 | fail "START_MIN_CONFIG or MIN_CONFIG not defined" and return; | ||
2768 | } | ||
2769 | |||
2770 | my $temp_config = "$tmpdir/temp_config"; | ||
2771 | |||
2772 | # First things first. We build an allnoconfig to find | ||
2773 | # out what the defaults are that we can't touch. | ||
2774 | # Some are selections, but we really can't handle selections. | ||
2775 | |||
2776 | my $save_minconfig = $minconfig; | ||
2777 | undef $minconfig; | ||
2778 | |||
2779 | run_command "$make allnoconfig" or return 0; | ||
2780 | |||
2781 | read_depends; | ||
2782 | |||
2783 | process_config_ignore $output_config; | ||
2784 | |||
2785 | undef %save_configs; | ||
2786 | undef %min_configs; | ||
2787 | |||
2788 | if (defined($ignore_config)) { | ||
2789 | # make sure the file exists | ||
2790 | `touch $ignore_config`; | ||
2791 | assign_configs \%save_configs, $ignore_config; | ||
2792 | } | ||
2793 | |||
2794 | %keep_configs = %save_configs; | ||
2795 | |||
2796 | doprint "Load initial configs from $start_minconfig\n"; | ||
2797 | |||
2798 | # Look at the current min configs, and save off all the | ||
2799 | # ones that were set via the allnoconfig | ||
2800 | assign_configs \%min_configs, $start_minconfig; | ||
2801 | |||
2802 | my @config_keys = keys %min_configs; | ||
2803 | |||
2804 | # All configs need a depcount | ||
2805 | foreach my $config (@config_keys) { | ||
2806 | my $kconfig = chomp_config $config; | ||
2807 | if (!defined $depcount{$kconfig}) { | ||
2808 | $depcount{$kconfig} = 0; | ||
2809 | } | ||
2810 | } | ||
2811 | |||
2812 | # Remove anything that was set by the make allnoconfig | ||
2813 | # we shouldn't need them as they get set for us anyway. | ||
2814 | foreach my $config (@config_keys) { | ||
2815 | # Remove anything in the ignore_config | ||
2816 | if (defined($keep_configs{$config})) { | ||
2817 | my $file = $ignore_config; | ||
2818 | $file =~ s,.*/(.*?)$,$1,; | ||
2819 | doprint "$config set by $file ... ignored\n"; | ||
2820 | delete $min_configs{$config}; | ||
2821 | next; | ||
2822 | } | ||
2823 | # But make sure the settings are the same. If a min config | ||
2824 | # sets a selection, we do not want to get rid of it if | ||
2825 | # it is not the same as what we have. Just move it into | ||
2826 | # the keep configs. | ||
2827 | if (defined($config_ignore{$config})) { | ||
2828 | if ($config_ignore{$config} ne $min_configs{$config}) { | ||
2829 | doprint "$config is in allnoconfig as '$config_ignore{$config}'"; | ||
2830 | doprint " but it is '$min_configs{$config}' in minconfig .. keeping\n"; | ||
2831 | $keep_configs{$config} = $min_configs{$config}; | ||
2832 | } else { | ||
2833 | doprint "$config set by allnoconfig ... ignored\n"; | ||
2834 | } | ||
2835 | delete $min_configs{$config}; | ||
2836 | } | ||
2837 | } | ||
2838 | |||
2839 | my $done = 0; | ||
2840 | my $take_two = 0; | ||
2841 | |||
2842 | while (!$done) { | ||
2843 | |||
2844 | my $config; | ||
2845 | my $found; | ||
2846 | |||
2847 | # Now disable each config one by one and do a make oldconfig | ||
2848 | # till we find a config that changes our list. | ||
2849 | |||
2850 | my @test_configs = keys %min_configs; | ||
2851 | |||
2852 | # Sort keys by who is most dependent on | ||
2853 | @test_configs = sort { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} } | ||
2854 | @test_configs ; | ||
2855 | |||
2856 | # Put configs that did not modify the config at the end. | ||
2857 | my $reset = 1; | ||
2858 | for (my $i = 0; $i < $#test_configs; $i++) { | ||
2859 | if (!defined($nochange_config{$test_configs[0]})) { | ||
2860 | $reset = 0; | ||
2861 | last; | ||
2862 | } | ||
2863 | # This config didn't change the .config last time. | ||
2864 | # Place it at the end | ||
2865 | my $config = shift @test_configs; | ||
2866 | push @test_configs, $config; | ||
2867 | } | ||
2868 | |||
2869 | # if every test config has failed to modify the .config file | ||
2870 | # in the past, then reset and start over. | ||
2871 | if ($reset) { | ||
2872 | undef %nochange_config; | ||
2873 | } | ||
2874 | |||
2875 | undef %processed_configs; | ||
2876 | |||
2877 | foreach my $config (@test_configs) { | ||
2878 | |||
2879 | $found = test_this_config $config; | ||
2880 | |||
2881 | last if (defined($found)); | ||
2882 | |||
2883 | # oh well, try another config | ||
2884 | } | ||
2885 | |||
2886 | if (!defined($found)) { | ||
2887 | # we could have failed due to the nochange_config hash | ||
2888 | # reset and try again | ||
2889 | if (!$take_two) { | ||
2890 | undef %nochange_config; | ||
2891 | $take_two = 1; | ||
2892 | next; | ||
2893 | } | ||
2894 | doprint "No more configs found that we can disable\n"; | ||
2895 | $done = 1; | ||
2896 | last; | ||
2897 | } | ||
2898 | $take_two = 0; | ||
2899 | |||
2900 | $config = $found; | ||
2901 | |||
2902 | doprint "Test with $config disabled\n"; | ||
2903 | |||
2904 | # set in_bisect to keep build and monitor from dieing | ||
2905 | $in_bisect = 1; | ||
2906 | |||
2907 | my $failed = 0; | ||
2908 | build "oldconfig"; | ||
2909 | start_monitor_and_boot or $failed = 1; | ||
2910 | end_monitor; | ||
2911 | |||
2912 | $in_bisect = 0; | ||
2913 | |||
2914 | if ($failed) { | ||
2915 | doprint "$min_configs{$config} is needed to boot the box... keeping\n"; | ||
2916 | # this config is needed, add it to the ignore list. | ||
2917 | $keep_configs{$config} = $min_configs{$config}; | ||
2918 | $save_configs{$config} = $min_configs{$config}; | ||
2919 | delete $min_configs{$config}; | ||
2920 | |||
2921 | # update new ignore configs | ||
2922 | if (defined($ignore_config)) { | ||
2923 | open (OUT, ">$temp_config") | ||
2924 | or die "Can't write to $temp_config"; | ||
2925 | foreach my $config (keys %save_configs) { | ||
2926 | print OUT "$save_configs{$config}\n"; | ||
2927 | } | ||
2928 | close OUT; | ||
2929 | run_command "mv $temp_config $ignore_config" or | ||
2930 | dodie "failed to copy update to $ignore_config"; | ||
2931 | } | ||
2932 | |||
2933 | } else { | ||
2934 | # We booted without this config, remove it from the minconfigs. | ||
2935 | doprint "$config is not needed, disabling\n"; | ||
2936 | |||
2937 | delete $min_configs{$config}; | ||
2938 | |||
2939 | # Also disable anything that is not enabled in this config | ||
2940 | my %configs; | ||
2941 | assign_configs \%configs, $output_config; | ||
2942 | my @config_keys = keys %min_configs; | ||
2943 | foreach my $config (@config_keys) { | ||
2944 | if (!defined($configs{$config})) { | ||
2945 | doprint "$config is not set, disabling\n"; | ||
2946 | delete $min_configs{$config}; | ||
2947 | } | ||
2948 | } | ||
2949 | |||
2950 | # Save off all the current mandidory configs | ||
2951 | open (OUT, ">$temp_config") | ||
2952 | or die "Can't write to $temp_config"; | ||
2953 | foreach my $config (keys %keep_configs) { | ||
2954 | print OUT "$keep_configs{$config}\n"; | ||
2955 | } | ||
2956 | foreach my $config (keys %min_configs) { | ||
2957 | print OUT "$min_configs{$config}\n"; | ||
2958 | } | ||
2959 | close OUT; | ||
2960 | |||
2961 | run_command "mv $temp_config $output_minconfig" or | ||
2962 | dodie "failed to copy update to $output_minconfig"; | ||
2963 | } | ||
2964 | |||
2965 | doprint "Reboot and wait $sleep_time seconds\n"; | ||
2966 | reboot $sleep_time; | ||
2967 | } | ||
2968 | |||
2969 | success $i; | ||
2970 | return 1; | ||
2971 | } | ||
2972 | |||
1939 | $#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n"; | 2973 | $#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n"; |
1940 | 2974 | ||
1941 | if ($#ARGV == 0) { | 2975 | if ($#ARGV == 0) { |
1942 | $ktest_config = $ARGV[0]; | 2976 | $ktest_config = $ARGV[0]; |
1943 | if (! -f $ktest_config) { | 2977 | if (! -f $ktest_config) { |
1944 | print "$ktest_config does not exist.\n"; | 2978 | print "$ktest_config does not exist.\n"; |
1945 | my $ans; | 2979 | if (!read_yn "Create it?") { |
1946 | for (;;) { | ||
1947 | print "Create it? [Y/n] "; | ||
1948 | $ans = <STDIN>; | ||
1949 | chomp $ans; | ||
1950 | if ($ans =~ /^\s*$/) { | ||
1951 | $ans = "y"; | ||
1952 | } | ||
1953 | last if ($ans =~ /^y$/i || $ans =~ /^n$/i); | ||
1954 | print "Please answer either 'y' or 'n'.\n"; | ||
1955 | } | ||
1956 | if ($ans !~ /^y$/i) { | ||
1957 | exit 0; | 2980 | exit 0; |
1958 | } | 2981 | } |
1959 | } | 2982 | } |
@@ -1977,6 +3000,10 @@ EOF | |||
1977 | } | 3000 | } |
1978 | read_config $ktest_config; | 3001 | read_config $ktest_config; |
1979 | 3002 | ||
3003 | if (defined($opt{"LOG_FILE"})) { | ||
3004 | $opt{"LOG_FILE"} = eval_option($opt{"LOG_FILE"}, -1); | ||
3005 | } | ||
3006 | |||
1980 | # Append any configs entered in manually to the config file. | 3007 | # Append any configs entered in manually to the config file. |
1981 | my @new_configs = keys %entered_configs; | 3008 | my @new_configs = keys %entered_configs; |
1982 | if ($#new_configs >= 0) { | 3009 | if ($#new_configs >= 0) { |
@@ -2045,75 +3072,21 @@ sub __set_test_option { | |||
2045 | return undef; | 3072 | return undef; |
2046 | } | 3073 | } |
2047 | 3074 | ||
2048 | sub eval_option { | ||
2049 | my ($option, $i) = @_; | ||
2050 | |||
2051 | # Add space to evaluate the character before $ | ||
2052 | $option = " $option"; | ||
2053 | my $retval = ""; | ||
2054 | |||
2055 | while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { | ||
2056 | my $start = $1; | ||
2057 | my $var = $2; | ||
2058 | my $end = $3; | ||
2059 | |||
2060 | # Append beginning of line | ||
2061 | $retval = "$retval$start"; | ||
2062 | |||
2063 | # If the iteration option OPT[$i] exists, then use that. | ||
2064 | # otherwise see if the default OPT (without [$i]) exists. | ||
2065 | |||
2066 | my $o = "$var\[$i\]"; | ||
2067 | |||
2068 | if (defined($opt{$o})) { | ||
2069 | $o = $opt{$o}; | ||
2070 | $retval = "$retval$o"; | ||
2071 | } elsif (defined($opt{$var})) { | ||
2072 | $o = $opt{$var}; | ||
2073 | $retval = "$retval$o"; | ||
2074 | } else { | ||
2075 | $retval = "$retval\$\{$var\}"; | ||
2076 | } | ||
2077 | |||
2078 | $option = $end; | ||
2079 | } | ||
2080 | |||
2081 | $retval = "$retval$option"; | ||
2082 | |||
2083 | $retval =~ s/^ //; | ||
2084 | |||
2085 | return $retval; | ||
2086 | } | ||
2087 | |||
2088 | sub set_test_option { | 3075 | sub set_test_option { |
2089 | my ($name, $i) = @_; | 3076 | my ($name, $i) = @_; |
2090 | 3077 | ||
2091 | my $option = __set_test_option($name, $i); | 3078 | my $option = __set_test_option($name, $i); |
2092 | return $option if (!defined($option)); | 3079 | return $option if (!defined($option)); |
2093 | 3080 | ||
2094 | my $prev = ""; | 3081 | return eval_option($option, $i); |
2095 | |||
2096 | # Since an option can evaluate to another option, | ||
2097 | # keep iterating until we do not evaluate any more | ||
2098 | # options. | ||
2099 | my $r = 0; | ||
2100 | while ($prev ne $option) { | ||
2101 | # Check for recursive evaluations. | ||
2102 | # 100 deep should be more than enough. | ||
2103 | if ($r++ > 100) { | ||
2104 | die "Over 100 evaluations accurred with $name\n" . | ||
2105 | "Check for recursive variables\n"; | ||
2106 | } | ||
2107 | $prev = $option; | ||
2108 | $option = eval_option($option, $i); | ||
2109 | } | ||
2110 | |||
2111 | return $option; | ||
2112 | } | 3082 | } |
2113 | 3083 | ||
2114 | # First we need to do is the builds | 3084 | # First we need to do is the builds |
2115 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | 3085 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { |
2116 | 3086 | ||
3087 | # Do not reboot on failing test options | ||
3088 | $no_reboot = 1; | ||
3089 | |||
2117 | $iteration = $i; | 3090 | $iteration = $i; |
2118 | 3091 | ||
2119 | my $makecmd = set_test_option("MAKE_CMD", $i); | 3092 | my $makecmd = set_test_option("MAKE_CMD", $i); |
@@ -2126,15 +3099,23 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2126 | $test_type = set_test_option("TEST_TYPE", $i); | 3099 | $test_type = set_test_option("TEST_TYPE", $i); |
2127 | $build_type = set_test_option("BUILD_TYPE", $i); | 3100 | $build_type = set_test_option("BUILD_TYPE", $i); |
2128 | $build_options = set_test_option("BUILD_OPTIONS", $i); | 3101 | $build_options = set_test_option("BUILD_OPTIONS", $i); |
3102 | $pre_build = set_test_option("PRE_BUILD", $i); | ||
3103 | $post_build = set_test_option("POST_BUILD", $i); | ||
3104 | $pre_build_die = set_test_option("PRE_BUILD_DIE", $i); | ||
3105 | $post_build_die = set_test_option("POST_BUILD_DIE", $i); | ||
2129 | $power_cycle = set_test_option("POWER_CYCLE", $i); | 3106 | $power_cycle = set_test_option("POWER_CYCLE", $i); |
2130 | $reboot = set_test_option("REBOOT", $i); | 3107 | $reboot = set_test_option("REBOOT", $i); |
2131 | $noclean = set_test_option("BUILD_NOCLEAN", $i); | 3108 | $noclean = set_test_option("BUILD_NOCLEAN", $i); |
2132 | $minconfig = set_test_option("MIN_CONFIG", $i); | 3109 | $minconfig = set_test_option("MIN_CONFIG", $i); |
3110 | $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i); | ||
3111 | $start_minconfig = set_test_option("START_MIN_CONFIG", $i); | ||
3112 | $ignore_config = set_test_option("IGNORE_CONFIG", $i); | ||
2133 | $run_test = set_test_option("TEST", $i); | 3113 | $run_test = set_test_option("TEST", $i); |
2134 | $addconfig = set_test_option("ADD_CONFIG", $i); | 3114 | $addconfig = set_test_option("ADD_CONFIG", $i); |
2135 | $reboot_type = set_test_option("REBOOT_TYPE", $i); | 3115 | $reboot_type = set_test_option("REBOOT_TYPE", $i); |
2136 | $grub_menu = set_test_option("GRUB_MENU", $i); | 3116 | $grub_menu = set_test_option("GRUB_MENU", $i); |
2137 | $post_install = set_test_option("POST_INSTALL", $i); | 3117 | $post_install = set_test_option("POST_INSTALL", $i); |
3118 | $no_install = set_test_option("NO_INSTALL", $i); | ||
2138 | $reboot_script = set_test_option("REBOOT_SCRIPT", $i); | 3119 | $reboot_script = set_test_option("REBOOT_SCRIPT", $i); |
2139 | $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); | 3120 | $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); |
2140 | $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); | 3121 | $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); |
@@ -2145,13 +3126,18 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2145 | $sleep_time = set_test_option("SLEEP_TIME", $i); | 3126 | $sleep_time = set_test_option("SLEEP_TIME", $i); |
2146 | $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); | 3127 | $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); |
2147 | $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); | 3128 | $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); |
3129 | $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i); | ||
2148 | $bisect_manual = set_test_option("BISECT_MANUAL", $i); | 3130 | $bisect_manual = set_test_option("BISECT_MANUAL", $i); |
2149 | $bisect_skip = set_test_option("BISECT_SKIP", $i); | 3131 | $bisect_skip = set_test_option("BISECT_SKIP", $i); |
3132 | $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i); | ||
2150 | $store_failures = set_test_option("STORE_FAILURES", $i); | 3133 | $store_failures = set_test_option("STORE_FAILURES", $i); |
3134 | $test_name = set_test_option("TEST_NAME", $i); | ||
2151 | $timeout = set_test_option("TIMEOUT", $i); | 3135 | $timeout = set_test_option("TIMEOUT", $i); |
2152 | $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); | 3136 | $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); |
2153 | $console = set_test_option("CONSOLE", $i); | 3137 | $console = set_test_option("CONSOLE", $i); |
3138 | $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); | ||
2154 | $success_line = set_test_option("SUCCESS_LINE", $i); | 3139 | $success_line = set_test_option("SUCCESS_LINE", $i); |
3140 | $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i); | ||
2155 | $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); | 3141 | $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); |
2156 | $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); | 3142 | $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); |
2157 | $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); | 3143 | $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); |
@@ -2161,11 +3147,20 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2161 | $target_image = set_test_option("TARGET_IMAGE", $i); | 3147 | $target_image = set_test_option("TARGET_IMAGE", $i); |
2162 | $localversion = set_test_option("LOCALVERSION", $i); | 3148 | $localversion = set_test_option("LOCALVERSION", $i); |
2163 | 3149 | ||
3150 | $start_minconfig_defined = 1; | ||
3151 | |||
3152 | if (!defined($start_minconfig)) { | ||
3153 | $start_minconfig_defined = 0; | ||
3154 | $start_minconfig = $minconfig; | ||
3155 | } | ||
3156 | |||
2164 | chdir $builddir || die "can't change directory to $builddir"; | 3157 | chdir $builddir || die "can't change directory to $builddir"; |
2165 | 3158 | ||
2166 | if (!-d $tmpdir) { | 3159 | foreach my $dir ($tmpdir, $outputdir) { |
2167 | mkpath($tmpdir) or | 3160 | if (!-d $dir) { |
2168 | die "can't create $tmpdir"; | 3161 | mkpath($dir) or |
3162 | die "can't create $dir"; | ||
3163 | } | ||
2169 | } | 3164 | } |
2170 | 3165 | ||
2171 | $ENV{"SSH_USER"} = $ssh_user; | 3166 | $ENV{"SSH_USER"} = $ssh_user; |
@@ -2193,22 +3188,30 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2193 | $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"}; | 3188 | $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"}; |
2194 | } | 3189 | } |
2195 | 3190 | ||
3191 | if ($test_type eq "make_min_config") { | ||
3192 | $run_type = ""; | ||
3193 | } | ||
3194 | |||
2196 | # mistake in config file? | 3195 | # mistake in config file? |
2197 | if (!defined($run_type)) { | 3196 | if (!defined($run_type)) { |
2198 | $run_type = "ERROR"; | 3197 | $run_type = "ERROR"; |
2199 | } | 3198 | } |
2200 | 3199 | ||
3200 | my $installme = ""; | ||
3201 | $installme = " no_install" if ($no_install); | ||
3202 | |||
2201 | doprint "\n\n"; | 3203 | doprint "\n\n"; |
2202 | doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n"; | 3204 | doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n"; |
2203 | 3205 | ||
2204 | unlink $dmesg; | 3206 | unlink $dmesg; |
2205 | unlink $buildlog; | 3207 | unlink $buildlog; |
2206 | 3208 | ||
2207 | if (!defined($minconfig)) { | 3209 | if (defined($addconfig)) { |
2208 | $minconfig = $addconfig; | 3210 | my $min = $minconfig; |
2209 | 3211 | if (!defined($minconfig)) { | |
2210 | } elsif (defined($addconfig)) { | 3212 | $min = ""; |
2211 | run_command "cat $addconfig $minconfig > $tmpdir/add_config" or | 3213 | } |
3214 | run_command "cat $addconfig $min > $tmpdir/add_config" or | ||
2212 | dodie "Failed to create temp config"; | 3215 | dodie "Failed to create temp config"; |
2213 | $minconfig = "$tmpdir/add_config"; | 3216 | $minconfig = "$tmpdir/add_config"; |
2214 | } | 3217 | } |
@@ -2219,6 +3222,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2219 | die "failed to checkout $checkout"; | 3222 | die "failed to checkout $checkout"; |
2220 | } | 3223 | } |
2221 | 3224 | ||
3225 | $no_reboot = 0; | ||
3226 | |||
3227 | |||
2222 | if ($test_type eq "bisect") { | 3228 | if ($test_type eq "bisect") { |
2223 | bisect $i; | 3229 | bisect $i; |
2224 | next; | 3230 | next; |
@@ -2228,20 +3234,25 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
2228 | } elsif ($test_type eq "patchcheck") { | 3234 | } elsif ($test_type eq "patchcheck") { |
2229 | patchcheck $i; | 3235 | patchcheck $i; |
2230 | next; | 3236 | next; |
3237 | } elsif ($test_type eq "make_min_config") { | ||
3238 | make_min_config $i; | ||
3239 | next; | ||
2231 | } | 3240 | } |
2232 | 3241 | ||
2233 | if ($build_type ne "nobuild") { | 3242 | if ($build_type ne "nobuild") { |
2234 | build $build_type or next; | 3243 | build $build_type or next; |
2235 | } | 3244 | } |
2236 | 3245 | ||
2237 | if ($test_type ne "build") { | 3246 | if ($test_type eq "install") { |
2238 | get_grub_index; | ||
2239 | get_version; | 3247 | get_version; |
2240 | install; | 3248 | install; |
3249 | success $i; | ||
3250 | next; | ||
3251 | } | ||
2241 | 3252 | ||
3253 | if ($test_type ne "build") { | ||
2242 | my $failed = 0; | 3254 | my $failed = 0; |
2243 | start_monitor; | 3255 | start_monitor_and_boot or $failed = 1; |
2244 | monitor or $failed = 1;; | ||
2245 | 3256 | ||
2246 | if (!$failed && $test_type ne "boot" && defined($run_test)) { | 3257 | if (!$failed && $test_type ne "boot" && defined($run_test)) { |
2247 | do_run_test or $failed = 1; | 3258 | do_run_test or $failed = 1; |
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 48cbcc80602a..dbedfa196727 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf | |||
@@ -72,6 +72,128 @@ | |||
72 | # the same option name under the same test or as default | 72 | # the same option name under the same test or as default |
73 | # ktest will fail to execute, and no tests will run. | 73 | # ktest will fail to execute, and no tests will run. |
74 | # | 74 | # |
75 | # DEFAULTS OVERRIDE | ||
76 | # | ||
77 | # Options defined in the DEFAULTS section can not be duplicated | ||
78 | # even if they are defined in two different DEFAULT sections. | ||
79 | # This is done to catch mistakes where an option is added but | ||
80 | # the previous option was forgotten about and not commented. | ||
81 | # | ||
82 | # The OVERRIDE keyword can be added to a section to allow this | ||
83 | # section to override other DEFAULT sections values that have | ||
84 | # been defined previously. It will only override options that | ||
85 | # have been defined before its use. Options defined later | ||
86 | # in a non override section will still error. The same option | ||
87 | # can not be defined in the same section even if that section | ||
88 | # is marked OVERRIDE. | ||
89 | # | ||
90 | # | ||
91 | # | ||
92 | # Both TEST_START and DEFAULTS sections can also have the IF keyword | ||
93 | # The value after the IF must evaluate into a 0 or non 0 positive | ||
94 | # integer, and can use the config variables (explained below). | ||
95 | # | ||
96 | # DEFAULTS IF ${IS_X86_32} | ||
97 | # | ||
98 | # The above will process the DEFAULTS section if the config | ||
99 | # variable IS_X86_32 evaluates to a non zero positive integer | ||
100 | # otherwise if it evaluates to zero, it will act the same | ||
101 | # as if the SKIP keyword was used. | ||
102 | # | ||
103 | # The ELSE keyword can be used directly after a section with | ||
104 | # a IF statement. | ||
105 | # | ||
106 | # TEST_START IF ${RUN_NET_TESTS} | ||
107 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
108 | # | ||
109 | # ELSE | ||
110 | # | ||
111 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-normal | ||
112 | # | ||
113 | # | ||
114 | # The ELSE keyword can also contain an IF statement to allow multiple | ||
115 | # if then else sections. But all the sections must be either | ||
116 | # DEFAULT or TEST_START, they can not be a mixture. | ||
117 | # | ||
118 | # TEST_START IF ${RUN_NET_TESTS} | ||
119 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
120 | # | ||
121 | # ELSE IF ${RUN_DISK_TESTS} | ||
122 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-tests | ||
123 | # | ||
124 | # ELSE IF ${RUN_CPU_TESTS} | ||
125 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-cpu | ||
126 | # | ||
127 | # ELSE | ||
128 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network | ||
129 | # | ||
130 | # The if statement may also have comparisons that will and for | ||
131 | # == and !=, strings may be used for both sides. | ||
132 | # | ||
133 | # BOX_TYPE := x86_32 | ||
134 | # | ||
135 | # DEFAULTS IF ${BOX_TYPE} == x86_32 | ||
136 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-32 | ||
137 | # ELSE | ||
138 | # BUILD_TYPE = useconfig:${CONFIG_DIR}/config-64 | ||
139 | # | ||
140 | # The DEFINED keyword can be used by the IF statements too. | ||
141 | # It returns true if the given config variable or option has been defined | ||
142 | # or false otherwise. | ||
143 | # | ||
144 | # | ||
145 | # DEFAULTS IF DEFINED USE_CC | ||
146 | # CC := ${USE_CC} | ||
147 | # ELSE | ||
148 | # CC := gcc | ||
149 | # | ||
150 | # | ||
151 | # As well as NOT DEFINED. | ||
152 | # | ||
153 | # DEFAULTS IF NOT DEFINED MAKE_CMD | ||
154 | # MAKE_CMD := make ARCH=x86 | ||
155 | # | ||
156 | # | ||
157 | # And/or ops (&&,||) may also be used to make complex conditionals. | ||
158 | # | ||
159 | # TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf | ||
160 | # | ||
161 | # Notice the use of paranthesis. Without any paranthesis the above would be | ||
162 | # processed the same as: | ||
163 | # | ||
164 | # TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf) | ||
165 | # | ||
166 | # | ||
167 | # | ||
168 | # INCLUDE file | ||
169 | # | ||
170 | # The INCLUDE keyword may be used in DEFAULT sections. This will | ||
171 | # read another config file and process that file as well. The included | ||
172 | # file can include other files, add new test cases or default | ||
173 | # statements. Config variables will be passed to these files and changes | ||
174 | # to config variables will be seen by top level config files. Including | ||
175 | # a file is processed just like the contents of the file was cut and pasted | ||
176 | # into the top level file, except, that include files that end with | ||
177 | # TEST_START sections will have that section ended at the end of | ||
178 | # the include file. That is, an included file is included followed | ||
179 | # by another DEFAULT keyword. | ||
180 | # | ||
181 | # Unlike other files referenced in this config, the file path does not need | ||
182 | # to be absolute. If the file does not start with '/', then the directory | ||
183 | # that the current config file was located in is used. If no config by the | ||
184 | # given name is found there, then the current directory is searched. | ||
185 | # | ||
186 | # INCLUDE myfile | ||
187 | # DEFAULT | ||
188 | # | ||
189 | # is the same as: | ||
190 | # | ||
191 | # INCLUDE myfile | ||
192 | # | ||
193 | # Note, if the include file does not contain a full path, the file is | ||
194 | # searched first by the location of the original include file, and then | ||
195 | # by the location that ktest.pl was executed in. | ||
196 | # | ||
75 | 197 | ||
76 | #### Config variables #### | 198 | #### Config variables #### |
77 | # | 199 | # |
@@ -253,9 +375,10 @@ | |||
253 | 375 | ||
254 | # The default test type (default test) | 376 | # The default test type (default test) |
255 | # The test types may be: | 377 | # The test types may be: |
256 | # build - only build the kernel, do nothing else | 378 | # build - only build the kernel, do nothing else |
257 | # boot - build and boot the kernel | 379 | # install - build and install, but do nothing else (does not reboot) |
258 | # test - build, boot and if TEST is set, run the test script | 380 | # boot - build, install, and boot the kernel |
381 | # test - build, boot and if TEST is set, run the test script | ||
259 | # (If TEST is not set, it defaults back to boot) | 382 | # (If TEST is not set, it defaults back to boot) |
260 | # bisect - Perform a bisect on the kernel (see BISECT_TYPE below) | 383 | # bisect - Perform a bisect on the kernel (see BISECT_TYPE below) |
261 | # patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) | 384 | # patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) |
@@ -293,6 +416,45 @@ | |||
293 | # or on some systems: | 416 | # or on some systems: |
294 | #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION | 417 | #POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION |
295 | 418 | ||
419 | # If for some reason you just want to boot the kernel and you do not | ||
420 | # want the test to install anything new. For example, you may just want | ||
421 | # to boot test the same kernel over and over and do not want to go through | ||
422 | # the hassle of installing anything, you can set this option to 1 | ||
423 | # (default 0) | ||
424 | #NO_INSTALL = 1 | ||
425 | |||
426 | # If there is a script that you require to run before the build is done | ||
427 | # you can specify it with PRE_BUILD. | ||
428 | # | ||
429 | # One example may be if you must add a temporary patch to the build to | ||
430 | # fix a unrelated bug to perform a patchcheck test. This will apply the | ||
431 | # patch before each build that is made. Use the POST_BUILD to do a git reset --hard | ||
432 | # to remove the patch. | ||
433 | # | ||
434 | # (default undef) | ||
435 | #PRE_BUILD = cd ${BUILD_DIR} && patch -p1 < /tmp/temp.patch | ||
436 | |||
437 | # To specify if the test should fail if the PRE_BUILD fails, | ||
438 | # PRE_BUILD_DIE needs to be set to 1. Otherwise the PRE_BUILD | ||
439 | # result is ignored. | ||
440 | # (default 0) | ||
441 | # PRE_BUILD_DIE = 1 | ||
442 | |||
443 | # If there is a script that should run after the build is done | ||
444 | # you can specify it with POST_BUILD. | ||
445 | # | ||
446 | # As the example in PRE_BUILD, POST_BUILD can be used to reset modifications | ||
447 | # made by the PRE_BUILD. | ||
448 | # | ||
449 | # (default undef) | ||
450 | #POST_BUILD = cd ${BUILD_DIR} && git reset --hard | ||
451 | |||
452 | # To specify if the test should fail if the POST_BUILD fails, | ||
453 | # POST_BUILD_DIE needs to be set to 1. Otherwise the POST_BUILD | ||
454 | # result is ignored. | ||
455 | # (default 0) | ||
456 | #POST_BUILD_DIE = 1 | ||
457 | |||
296 | # Way to reboot the box to the test kernel. | 458 | # Way to reboot the box to the test kernel. |
297 | # Only valid options so far are "grub" and "script" | 459 | # Only valid options so far are "grub" and "script" |
298 | # (default grub) | 460 | # (default grub) |
@@ -360,8 +522,8 @@ | |||
360 | #ADD_CONFIG = /home/test/config-broken | 522 | #ADD_CONFIG = /home/test/config-broken |
361 | 523 | ||
362 | # The location on the host where to write temp files | 524 | # The location on the host where to write temp files |
363 | # (default /tmp/ktest) | 525 | # (default /tmp/ktest/${MACHINE}) |
364 | #TMP_DIR = /tmp/ktest | 526 | #TMP_DIR = /tmp/ktest/${MACHINE} |
365 | 527 | ||
366 | # Optional log file to write the status (recommended) | 528 | # Optional log file to write the status (recommended) |
367 | # Note, this is a DEFAULT section only option. | 529 | # Note, this is a DEFAULT section only option. |
@@ -383,6 +545,14 @@ | |||
383 | # (default "login:") | 545 | # (default "login:") |
384 | #SUCCESS_LINE = login: | 546 | #SUCCESS_LINE = login: |
385 | 547 | ||
548 | # To speed up between reboots, defining a line that the | ||
549 | # default kernel produces that represents that the default | ||
550 | # kernel has successfully booted and can be used to pass | ||
551 | # a new test kernel to it. Otherwise ktest.pl will wait till | ||
552 | # SLEEP_TIME to continue. | ||
553 | # (default undefined) | ||
554 | #REBOOT_SUCCESS_LINE = login: | ||
555 | |||
386 | # In case the console constantly fills the screen, having | 556 | # In case the console constantly fills the screen, having |
387 | # a specified time to stop the test after success is recommended. | 557 | # a specified time to stop the test after success is recommended. |
388 | # (in seconds) | 558 | # (in seconds) |
@@ -448,6 +618,8 @@ | |||
448 | # another test. If a reboot to the reliable kernel happens, | 618 | # another test. If a reboot to the reliable kernel happens, |
449 | # we wait SLEEP_TIME for the console to stop producing output | 619 | # we wait SLEEP_TIME for the console to stop producing output |
450 | # before starting the next test. | 620 | # before starting the next test. |
621 | # | ||
622 | # You can speed up reboot times even more by setting REBOOT_SUCCESS_LINE. | ||
451 | # (default 60) | 623 | # (default 60) |
452 | #SLEEP_TIME = 60 | 624 | #SLEEP_TIME = 60 |
453 | 625 | ||
@@ -518,6 +690,16 @@ | |||
518 | # The variables SSH_USER and MACHINE are defined. | 690 | # The variables SSH_USER and MACHINE are defined. |
519 | #REBOOT = ssh $SSH_USER@$MACHINE reboot | 691 | #REBOOT = ssh $SSH_USER@$MACHINE reboot |
520 | 692 | ||
693 | # The way triple faults are detected is by testing the kernel | ||
694 | # banner. If the kernel banner for the kernel we are testing is | ||
695 | # found, and then later a kernel banner for another kernel version | ||
696 | # is found, it is considered that we encountered a triple fault, | ||
697 | # and there is no panic or callback, but simply a reboot. | ||
698 | # To disable this (because it did a false positive) set the following | ||
699 | # to 0. | ||
700 | # (default 1) | ||
701 | #DETECT_TRIPLE_FAULT = 0 | ||
702 | |||
521 | #### Per test run options #### | 703 | #### Per test run options #### |
522 | # The following options are only allowed in TEST_START sections. | 704 | # The following options are only allowed in TEST_START sections. |
523 | # They are ignored in the DEFAULTS sections. | 705 | # They are ignored in the DEFAULTS sections. |
@@ -535,6 +717,12 @@ | |||
535 | # all preceding tests until a new CHECKOUT is set. | 717 | # all preceding tests until a new CHECKOUT is set. |
536 | # | 718 | # |
537 | # | 719 | # |
720 | # TEST_NAME = name | ||
721 | # | ||
722 | # If you want the test to have a name that is displayed in | ||
723 | # the test result banner at the end of the test, then use this | ||
724 | # option. This is useful to search for the RESULT keyword and | ||
725 | # not have to translate a test number to a test in the config. | ||
538 | # | 726 | # |
539 | # For TEST_TYPE = patchcheck | 727 | # For TEST_TYPE = patchcheck |
540 | # | 728 | # |
@@ -556,7 +744,12 @@ | |||
556 | # build, boot, test. | 744 | # build, boot, test. |
557 | # | 745 | # |
558 | # Note, the build test will look for warnings, if a warning occurred | 746 | # Note, the build test will look for warnings, if a warning occurred |
559 | # in a file that a commit touches, the build will fail. | 747 | # in a file that a commit touches, the build will fail, unless |
748 | # IGNORE_WARNINGS is set for the given commit's sha1 | ||
749 | # | ||
750 | # IGNORE_WARNINGS can be used to disable the failure of patchcheck | ||
751 | # on a particuler commit (SHA1). You can add more than one commit | ||
752 | # by adding a list of SHA1s that are space delimited. | ||
560 | # | 753 | # |
561 | # If BUILD_NOCLEAN is set, then make mrproper will not be run on | 754 | # If BUILD_NOCLEAN is set, then make mrproper will not be run on |
562 | # any of the builds, just like all other TEST_TYPE tests. But | 755 | # any of the builds, just like all other TEST_TYPE tests. But |
@@ -571,6 +764,7 @@ | |||
571 | # PATCHCHECK_TYPE = boot | 764 | # PATCHCHECK_TYPE = boot |
572 | # PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7 | 765 | # PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7 |
573 | # PATCHCHECK_END = HEAD~2 | 766 | # PATCHCHECK_END = HEAD~2 |
767 | # IGNORE_WARNINGS = 42f9c6b69b54946ffc0515f57d01dc7f5c0e4712 0c17ca2c7187f431d8ffc79e81addc730f33d128 | ||
574 | # | 768 | # |
575 | # | 769 | # |
576 | # | 770 | # |
@@ -739,13 +933,18 @@ | |||
739 | # boot - bad builds but fails to boot | 933 | # boot - bad builds but fails to boot |
740 | # test - bad boots but fails a test | 934 | # test - bad boots but fails a test |
741 | # | 935 | # |
742 | # CONFIG_BISECT is the config that failed to boot | 936 | # CONFIG_BISECT is the config that failed to boot |
937 | # | ||
938 | # If BISECT_MANUAL is set, it will pause between iterations. | ||
939 | # This is useful to use just ktest.pl just for the config bisect. | ||
940 | # If you set it to build, it will run the bisect and you can | ||
941 | # control what happens in between iterations. It will ask you if | ||
942 | # the test succeeded or not and continue the config bisect. | ||
743 | # | 943 | # |
744 | # If BISECT_MANUAL is set, it will pause between iterations. | 944 | # CONFIG_BISECT_GOOD (optional) |
745 | # This is useful to use just ktest.pl just for the config bisect. | 945 | # If you have a good config to start with, then you |
746 | # If you set it to build, it will run the bisect and you can | 946 | # can specify it with CONFIG_BISECT_GOOD. Otherwise |
747 | # control what happens in between iterations. It will ask you if | 947 | # the MIN_CONFIG is the base. |
748 | # the test succeeded or not and continue the config bisect. | ||
749 | # | 948 | # |
750 | # Example: | 949 | # Example: |
751 | # TEST_START | 950 | # TEST_START |
@@ -755,3 +954,68 @@ | |||
755 | # MIN_CONFIG = /home/test/config-min | 954 | # MIN_CONFIG = /home/test/config-min |
756 | # BISECT_MANUAL = 1 | 955 | # BISECT_MANUAL = 1 |
757 | # | 956 | # |
957 | # | ||
958 | # | ||
959 | # For TEST_TYPE = make_min_config | ||
960 | # | ||
961 | # After doing a make localyesconfig, your kernel configuration may | ||
962 | # not be the most useful minimum configuration. Having a true minimum | ||
963 | # config that you can use against other configs is very useful if | ||
964 | # someone else has a config that breaks on your code. By only forcing | ||
965 | # those configurations that are truly required to boot your machine | ||
966 | # will give you less of a chance that one of your set configurations | ||
967 | # will make the bug go away. This will give you a better chance to | ||
968 | # be able to reproduce the reported bug matching the broken config. | ||
969 | # | ||
970 | # Note, this does take some time, and may require you to run the | ||
971 | # test over night, or perhaps over the weekend. But it also allows | ||
972 | # you to interrupt it, and gives you the current minimum config | ||
973 | # that was found till that time. | ||
974 | # | ||
975 | # Note, this test automatically assumes a BUILD_TYPE of oldconfig | ||
976 | # and its test type acts like boot. | ||
977 | # TODO: add a test version that makes the config do more than just | ||
978 | # boot, like having network access. | ||
979 | # | ||
980 | # To save time, the test does not just grab any option and test | ||
981 | # it. The Kconfig files are examined to determine the dependencies | ||
982 | # of the configs. If a config is chosen that depends on another | ||
983 | # config, that config will be checked first. By checking the | ||
984 | # parents first, we can eliminate whole groups of configs that | ||
985 | # may have been enabled. | ||
986 | # | ||
987 | # For example, if a USB device config is chosen and depends on CONFIG_USB, | ||
988 | # the CONFIG_USB will be tested before the device. If CONFIG_USB is | ||
989 | # found not to be needed, it, as well as all configs that depend on | ||
990 | # it, will be disabled and removed from the current min_config. | ||
991 | # | ||
992 | # OUTPUT_MIN_CONFIG is the path and filename of the file that will | ||
993 | # be created from the MIN_CONFIG. If you interrupt the test, set | ||
994 | # this file as your new min config, and use it to continue the test. | ||
995 | # This file does not need to exist on start of test. | ||
996 | # This file is not created until a config is found that can be removed. | ||
997 | # If this file exists, you will be prompted if you want to use it | ||
998 | # as the min_config (overriding MIN_CONFIG) if START_MIN_CONFIG | ||
999 | # is not defined. | ||
1000 | # (required field) | ||
1001 | # | ||
1002 | # START_MIN_CONFIG is the config to use to start the test with. | ||
1003 | # you can set this as the same OUTPUT_MIN_CONFIG, but if you do | ||
1004 | # the OUTPUT_MIN_CONFIG file must exist. | ||
1005 | # (default MIN_CONFIG) | ||
1006 | # | ||
1007 | # IGNORE_CONFIG is used to specify a config file that has configs that | ||
1008 | # you already know must be set. Configs are written here that have | ||
1009 | # been tested and proved to be required. It is best to define this | ||
1010 | # file if you intend on interrupting the test and running it where | ||
1011 | # it left off. New configs that it finds will be written to this file | ||
1012 | # and will not be tested again in later runs. | ||
1013 | # (optional) | ||
1014 | # | ||
1015 | # Example: | ||
1016 | # | ||
1017 | # TEST_TYPE = make_min_config | ||
1018 | # OUTPUT_MIN_CONFIG = /path/to/config-new-min | ||
1019 | # START_MIN_CONFIG = /path/to/config-min | ||
1020 | # IGNORE_CONFIG = /path/to/config-tested | ||
1021 | # | ||