1 /**************************************************************************
3 * Copyright 2013 Marek Olšák <maraeo@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 /* This file contains code for reading CPU load for displaying on the HUD.
31 #include "hud/hud_private.h"
32 #include "os/os_time.h"
33 #include "util/u_memory.h"
36 #ifdef PIPE_OS_WINDOWS
41 #ifdef PIPE_OS_WINDOWS
43 static inline uint64_t
44 filetime_to_scalar(FILETIME ft
)
47 uli
.LowPart
= ft
.dwLowDateTime
;
48 uli
.HighPart
= ft
.dwHighDateTime
;
53 get_cpu_stats(unsigned cpu_index
, uint64_t *busy_time
, uint64_t *total_time
)
56 FILETIME ftNow
, ftCreation
, ftExit
, ftKernel
, ftUser
;
58 GetSystemInfo(&sysInfo
);
59 assert(sysInfo
.dwNumberOfProcessors
>= 1);
60 if (cpu_index
!= ALL_CPUS
&& cpu_index
>= sysInfo
.dwNumberOfProcessors
) {
61 /* Tell hud_get_num_cpus there are only this many CPUs. */
65 /* Get accumulated user and sys time for all threads */
66 if (!GetProcessTimes(GetCurrentProcess(), &ftCreation
, &ftExit
,
70 GetSystemTimeAsFileTime(&ftNow
);
72 *busy_time
= filetime_to_scalar(ftUser
) + filetime_to_scalar(ftKernel
);
73 *total_time
= filetime_to_scalar(ftNow
) - filetime_to_scalar(ftCreation
);
75 /* busy_time already has the time accross all cpus.
76 * XXX: if we want 100% to mean one CPU, 200% two cpus, eliminate the
79 *total_time
*= sysInfo
.dwNumberOfProcessors
;
81 /* XXX: we ignore cpu_index, i.e, we assume that the individual CPU usage
82 * and the system usage are one and the same.
90 get_cpu_stats(unsigned cpu_index
, uint64_t *busy_time
, uint64_t *total_time
)
96 if (cpu_index
== ALL_CPUS
)
97 strcpy(cpuname
, "cpu");
99 sprintf(cpuname
, "cpu%u", cpu_index
);
101 f
= fopen("/proc/stat", "r");
105 while (!feof(f
) && fgets(line
, sizeof(line
), f
)) {
106 if (strstr(line
, cpuname
) == line
) {
111 "%s %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
112 " %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
113 " %"PRIu64
" %"PRIu64
"",
114 cpuname
, &v
[0], &v
[1], &v
[2], &v
[3], &v
[4], &v
[5],
115 &v
[6], &v
[7], &v
[8], &v
[9], &v
[10], &v
[11]);
121 /* user + nice + system */
122 *busy_time
= v
[0] + v
[1] + v
[2];
123 *total_time
= *busy_time
;
125 /* ... + idle + iowait + irq + softirq + ... */
126 for (i
= 3; i
< num
-1; i
++) {
141 uint64_t last_cpu_busy
, last_cpu_total
, last_time
;
145 query_cpu_load(struct hud_graph
*gr
)
147 struct cpu_info
*info
= gr
->query_data
;
148 uint64_t now
= os_time_get();
150 if (info
->last_time
) {
151 if (info
->last_time
+ gr
->pane
->period
<= now
) {
152 uint64_t cpu_busy
, cpu_total
, cpu_load
;
154 get_cpu_stats(info
->cpu_index
, &cpu_busy
, &cpu_total
);
156 cpu_load
= (cpu_busy
- info
->last_cpu_busy
) * 100 /
157 (double)(cpu_total
- info
->last_cpu_total
);
158 hud_graph_add_value(gr
, cpu_load
);
160 info
->last_cpu_busy
= cpu_busy
;
161 info
->last_cpu_total
= cpu_total
;
162 info
->last_time
= now
;
167 info
->last_time
= now
;
168 get_cpu_stats(info
->cpu_index
, &info
->last_cpu_busy
,
169 &info
->last_cpu_total
);
174 free_query_data(void *p
)
180 hud_cpu_graph_install(struct hud_pane
*pane
, unsigned cpu_index
)
182 struct hud_graph
*gr
;
183 struct cpu_info
*info
;
184 uint64_t busy
, total
;
186 /* see if the cpu exists */
187 if (cpu_index
!= ALL_CPUS
&& !get_cpu_stats(cpu_index
, &busy
, &total
)) {
191 gr
= CALLOC_STRUCT(hud_graph
);
195 if (cpu_index
== ALL_CPUS
)
196 strcpy(gr
->name
, "cpu");
198 sprintf(gr
->name
, "cpu%u", cpu_index
);
200 gr
->query_data
= CALLOC_STRUCT(cpu_info
);
201 if (!gr
->query_data
) {
206 gr
->query_new_value
= query_cpu_load
;
208 /* Don't use free() as our callback as that messes up Gallium's
209 * memory debugger. Use simple free_query_data() wrapper.
211 gr
->free_query_data
= free_query_data
;
213 info
= gr
->query_data
;
214 info
->cpu_index
= cpu_index
;
216 hud_pane_add_graph(pane
, gr
);
217 hud_pane_set_max_value(pane
, 100);
221 hud_get_num_cpus(void)
223 uint64_t busy
, total
;
226 while (get_cpu_stats(i
, &busy
, &total
))