1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2013 Marek Olšák <maraeo@gmail.com> 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/* This file contains code for reading CPU load for displaying on the HUD. 29bf215546Sopenharmony_ci */ 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "hud/hud_private.h" 32bf215546Sopenharmony_ci#include "util/os_time.h" 33bf215546Sopenharmony_ci#include "os/os_thread.h" 34bf215546Sopenharmony_ci#include "util/u_memory.h" 35bf215546Sopenharmony_ci#include "util/u_queue.h" 36bf215546Sopenharmony_ci#include <stdio.h> 37bf215546Sopenharmony_ci#include <inttypes.h> 38bf215546Sopenharmony_ci#ifdef PIPE_OS_WINDOWS 39bf215546Sopenharmony_ci#include <windows.h> 40bf215546Sopenharmony_ci#endif 41bf215546Sopenharmony_ci#if defined(PIPE_OS_BSD) 42bf215546Sopenharmony_ci#include <sys/types.h> 43bf215546Sopenharmony_ci#include <sys/sysctl.h> 44bf215546Sopenharmony_ci#if defined(PIPE_OS_NETBSD) || defined(PIPE_OS_OPENBSD) 45bf215546Sopenharmony_ci#include <sys/sched.h> 46bf215546Sopenharmony_ci#else 47bf215546Sopenharmony_ci#include <sys/resource.h> 48bf215546Sopenharmony_ci#endif 49bf215546Sopenharmony_ci#endif 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci#ifdef PIPE_OS_WINDOWS 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic inline uint64_t 55bf215546Sopenharmony_cifiletime_to_scalar(FILETIME ft) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci ULARGE_INTEGER uli; 58bf215546Sopenharmony_ci uli.LowPart = ft.dwLowDateTime; 59bf215546Sopenharmony_ci uli.HighPart = ft.dwHighDateTime; 60bf215546Sopenharmony_ci return uli.QuadPart; 61bf215546Sopenharmony_ci} 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_cistatic boolean 64bf215546Sopenharmony_ciget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci SYSTEM_INFO sysInfo; 67bf215546Sopenharmony_ci FILETIME ftNow, ftCreation, ftExit, ftKernel, ftUser; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci GetSystemInfo(&sysInfo); 70bf215546Sopenharmony_ci assert(sysInfo.dwNumberOfProcessors >= 1); 71bf215546Sopenharmony_ci if (cpu_index != ALL_CPUS && cpu_index >= sysInfo.dwNumberOfProcessors) { 72bf215546Sopenharmony_ci /* Tell hud_get_num_cpus there are only this many CPUs. */ 73bf215546Sopenharmony_ci return FALSE; 74bf215546Sopenharmony_ci } 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci /* Get accumulated user and sys time for all threads */ 77bf215546Sopenharmony_ci if (!GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, 78bf215546Sopenharmony_ci &ftKernel, &ftUser)) 79bf215546Sopenharmony_ci return FALSE; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci GetSystemTimeAsFileTime(&ftNow); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci *busy_time = filetime_to_scalar(ftUser) + filetime_to_scalar(ftKernel); 84bf215546Sopenharmony_ci *total_time = filetime_to_scalar(ftNow) - filetime_to_scalar(ftCreation); 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci /* busy_time already has the time accross all cpus. 87bf215546Sopenharmony_ci * XXX: if we want 100% to mean one CPU, 200% two cpus, eliminate the 88bf215546Sopenharmony_ci * following line. 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_ci *total_time *= sysInfo.dwNumberOfProcessors; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci /* XXX: we ignore cpu_index, i.e, we assume that the individual CPU usage 93bf215546Sopenharmony_ci * and the system usage are one and the same. 94bf215546Sopenharmony_ci */ 95bf215546Sopenharmony_ci return TRUE; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci#elif defined(PIPE_OS_BSD) 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_cistatic boolean 101bf215546Sopenharmony_ciget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 102bf215546Sopenharmony_ci{ 103bf215546Sopenharmony_ci#if defined(PIPE_OS_NETBSD) || defined(PIPE_OS_OPENBSD) 104bf215546Sopenharmony_ci uint64_t cp_time[CPUSTATES]; 105bf215546Sopenharmony_ci#else 106bf215546Sopenharmony_ci long cp_time[CPUSTATES]; 107bf215546Sopenharmony_ci#endif 108bf215546Sopenharmony_ci size_t len; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci if (cpu_index == ALL_CPUS) { 111bf215546Sopenharmony_ci len = sizeof(cp_time); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci#if defined(PIPE_OS_NETBSD) 114bf215546Sopenharmony_ci int mib[] = { CTL_KERN, KERN_CP_TIME }; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 117bf215546Sopenharmony_ci return FALSE; 118bf215546Sopenharmony_ci#elif defined(PIPE_OS_OPENBSD) 119bf215546Sopenharmony_ci int mib[] = { CTL_KERN, KERN_CPTIME }; 120bf215546Sopenharmony_ci long sum_cp_time[CPUSTATES]; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci len = sizeof(sum_cp_time); 123bf215546Sopenharmony_ci if (sysctl(mib, ARRAY_SIZE(mib), sum_cp_time, &len, NULL, 0) == -1) 124bf215546Sopenharmony_ci return FALSE; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci for (int state = 0; state < CPUSTATES; state++) 127bf215546Sopenharmony_ci cp_time[state] = sum_cp_time[state]; 128bf215546Sopenharmony_ci#else 129bf215546Sopenharmony_ci if (sysctlbyname("kern.cp_time", cp_time, &len, NULL, 0) == -1) 130bf215546Sopenharmony_ci return FALSE; 131bf215546Sopenharmony_ci#endif 132bf215546Sopenharmony_ci } else { 133bf215546Sopenharmony_ci#if defined(PIPE_OS_NETBSD) 134bf215546Sopenharmony_ci int mib[] = { CTL_KERN, KERN_CP_TIME, cpu_index }; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci len = sizeof(cp_time); 137bf215546Sopenharmony_ci if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 138bf215546Sopenharmony_ci return FALSE; 139bf215546Sopenharmony_ci#elif defined(PIPE_OS_OPENBSD) 140bf215546Sopenharmony_ci int mib[] = { CTL_KERN, KERN_CPTIME2, cpu_index }; 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci len = sizeof(cp_time); 143bf215546Sopenharmony_ci if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 144bf215546Sopenharmony_ci return FALSE; 145bf215546Sopenharmony_ci#else 146bf215546Sopenharmony_ci long *cp_times = NULL; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci if (sysctlbyname("kern.cp_times", NULL, &len, NULL, 0) == -1) 149bf215546Sopenharmony_ci return FALSE; 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (len < (cpu_index + 1) * sizeof(cp_time)) 152bf215546Sopenharmony_ci return FALSE; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci cp_times = malloc(len); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if (sysctlbyname("kern.cp_times", cp_times, &len, NULL, 0) == -1) 157bf215546Sopenharmony_ci return FALSE; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci memcpy(cp_time, cp_times + (cpu_index * CPUSTATES), 160bf215546Sopenharmony_ci sizeof(cp_time)); 161bf215546Sopenharmony_ci free(cp_times); 162bf215546Sopenharmony_ci#endif 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci *busy_time = cp_time[CP_USER] + cp_time[CP_NICE] + 166bf215546Sopenharmony_ci cp_time[CP_SYS] + cp_time[CP_INTR]; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci *total_time = *busy_time + cp_time[CP_IDLE]; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci return TRUE; 171bf215546Sopenharmony_ci} 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci#else 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_cistatic boolean 176bf215546Sopenharmony_ciget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci char cpuname[32]; 179bf215546Sopenharmony_ci char line[1024]; 180bf215546Sopenharmony_ci FILE *f; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci if (cpu_index == ALL_CPUS) 183bf215546Sopenharmony_ci strcpy(cpuname, "cpu"); 184bf215546Sopenharmony_ci else 185bf215546Sopenharmony_ci sprintf(cpuname, "cpu%u", cpu_index); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci f = fopen("/proc/stat", "r"); 188bf215546Sopenharmony_ci if (!f) 189bf215546Sopenharmony_ci return FALSE; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci while (!feof(f) && fgets(line, sizeof(line), f)) { 192bf215546Sopenharmony_ci if (strstr(line, cpuname) == line) { 193bf215546Sopenharmony_ci uint64_t v[12]; 194bf215546Sopenharmony_ci int i, num; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci num = sscanf(line, 197bf215546Sopenharmony_ci "%s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 198bf215546Sopenharmony_ci " %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 199bf215546Sopenharmony_ci " %"PRIu64" %"PRIu64"", 200bf215546Sopenharmony_ci cpuname, &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], 201bf215546Sopenharmony_ci &v[6], &v[7], &v[8], &v[9], &v[10], &v[11]); 202bf215546Sopenharmony_ci if (num < 5) { 203bf215546Sopenharmony_ci fclose(f); 204bf215546Sopenharmony_ci return FALSE; 205bf215546Sopenharmony_ci } 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci /* user + nice + system */ 208bf215546Sopenharmony_ci *busy_time = v[0] + v[1] + v[2]; 209bf215546Sopenharmony_ci *total_time = *busy_time; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci /* ... + idle + iowait + irq + softirq + ... */ 212bf215546Sopenharmony_ci for (i = 3; i < num-1; i++) { 213bf215546Sopenharmony_ci *total_time += v[i]; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci fclose(f); 216bf215546Sopenharmony_ci return TRUE; 217bf215546Sopenharmony_ci } 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci fclose(f); 220bf215546Sopenharmony_ci return FALSE; 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci#endif 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_cistruct cpu_info { 226bf215546Sopenharmony_ci unsigned cpu_index; 227bf215546Sopenharmony_ci uint64_t last_cpu_busy, last_cpu_total, last_time; 228bf215546Sopenharmony_ci}; 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_cistatic void 231bf215546Sopenharmony_ciquery_cpu_load(struct hud_graph *gr, struct pipe_context *pipe) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci struct cpu_info *info = gr->query_data; 234bf215546Sopenharmony_ci uint64_t now = os_time_get(); 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci if (info->last_time) { 237bf215546Sopenharmony_ci if (info->last_time + gr->pane->period <= now) { 238bf215546Sopenharmony_ci uint64_t cpu_busy, cpu_total; 239bf215546Sopenharmony_ci double cpu_load; 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci get_cpu_stats(info->cpu_index, &cpu_busy, &cpu_total); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci cpu_load = (cpu_busy - info->last_cpu_busy) * 100 / 244bf215546Sopenharmony_ci (double)(cpu_total - info->last_cpu_total); 245bf215546Sopenharmony_ci hud_graph_add_value(gr, cpu_load); 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci info->last_cpu_busy = cpu_busy; 248bf215546Sopenharmony_ci info->last_cpu_total = cpu_total; 249bf215546Sopenharmony_ci info->last_time = now; 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci else { 253bf215546Sopenharmony_ci /* initialize */ 254bf215546Sopenharmony_ci info->last_time = now; 255bf215546Sopenharmony_ci get_cpu_stats(info->cpu_index, &info->last_cpu_busy, 256bf215546Sopenharmony_ci &info->last_cpu_total); 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci} 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_cistatic void 261bf215546Sopenharmony_cifree_query_data(void *p, struct pipe_context *pipe) 262bf215546Sopenharmony_ci{ 263bf215546Sopenharmony_ci FREE(p); 264bf215546Sopenharmony_ci} 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_civoid 267bf215546Sopenharmony_cihud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index) 268bf215546Sopenharmony_ci{ 269bf215546Sopenharmony_ci struct hud_graph *gr; 270bf215546Sopenharmony_ci struct cpu_info *info; 271bf215546Sopenharmony_ci uint64_t busy, total; 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci /* see if the cpu exists */ 274bf215546Sopenharmony_ci if (cpu_index != ALL_CPUS && !get_cpu_stats(cpu_index, &busy, &total)) { 275bf215546Sopenharmony_ci return; 276bf215546Sopenharmony_ci } 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci gr = CALLOC_STRUCT(hud_graph); 279bf215546Sopenharmony_ci if (!gr) 280bf215546Sopenharmony_ci return; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci if (cpu_index == ALL_CPUS) 283bf215546Sopenharmony_ci strcpy(gr->name, "cpu"); 284bf215546Sopenharmony_ci else 285bf215546Sopenharmony_ci sprintf(gr->name, "cpu%u", cpu_index); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci gr->query_data = CALLOC_STRUCT(cpu_info); 288bf215546Sopenharmony_ci if (!gr->query_data) { 289bf215546Sopenharmony_ci FREE(gr); 290bf215546Sopenharmony_ci return; 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci gr->query_new_value = query_cpu_load; 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci /* Don't use free() as our callback as that messes up Gallium's 296bf215546Sopenharmony_ci * memory debugger. Use simple free_query_data() wrapper. 297bf215546Sopenharmony_ci */ 298bf215546Sopenharmony_ci gr->free_query_data = free_query_data; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci info = gr->query_data; 301bf215546Sopenharmony_ci info->cpu_index = cpu_index; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci hud_pane_add_graph(pane, gr); 304bf215546Sopenharmony_ci hud_pane_set_max_value(pane, 100); 305bf215546Sopenharmony_ci} 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ciint 308bf215546Sopenharmony_cihud_get_num_cpus(void) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci uint64_t busy, total; 311bf215546Sopenharmony_ci int i = 0; 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci while (get_cpu_stats(i, &busy, &total)) 314bf215546Sopenharmony_ci i++; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci return i; 317bf215546Sopenharmony_ci} 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_cistruct thread_info { 320bf215546Sopenharmony_ci bool main_thread; 321bf215546Sopenharmony_ci int64_t last_time; 322bf215546Sopenharmony_ci int64_t last_thread_time; 323bf215546Sopenharmony_ci}; 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_cistatic void 326bf215546Sopenharmony_ciquery_api_thread_busy_status(struct hud_graph *gr, struct pipe_context *pipe) 327bf215546Sopenharmony_ci{ 328bf215546Sopenharmony_ci struct thread_info *info = gr->query_data; 329bf215546Sopenharmony_ci int64_t now = os_time_get_nano(); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (info->last_time) { 332bf215546Sopenharmony_ci if (info->last_time + gr->pane->period*1000 <= now) { 333bf215546Sopenharmony_ci int64_t thread_now; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci if (info->main_thread) { 336bf215546Sopenharmony_ci thread_now = util_current_thread_get_time_nano(); 337bf215546Sopenharmony_ci } else { 338bf215546Sopenharmony_ci struct util_queue_monitoring *mon = gr->pane->hud->monitored_queue; 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci if (mon && mon->queue) 341bf215546Sopenharmony_ci thread_now = util_queue_get_thread_time_nano(mon->queue, 0); 342bf215546Sopenharmony_ci else 343bf215546Sopenharmony_ci thread_now = 0; 344bf215546Sopenharmony_ci } 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci double percent = (thread_now - info->last_thread_time) * 100.0 / 347bf215546Sopenharmony_ci (now - info->last_time); 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_ci /* Check if the context changed a thread, so that we don't show 350bf215546Sopenharmony_ci * a random value. When a thread is changed, the new thread clock 351bf215546Sopenharmony_ci * is different, which can result in "percent" being very high. 352bf215546Sopenharmony_ci */ 353bf215546Sopenharmony_ci if (percent > 100.0) 354bf215546Sopenharmony_ci percent = 0.0; 355bf215546Sopenharmony_ci hud_graph_add_value(gr, percent); 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci info->last_thread_time = thread_now; 358bf215546Sopenharmony_ci info->last_time = now; 359bf215546Sopenharmony_ci } 360bf215546Sopenharmony_ci } else { 361bf215546Sopenharmony_ci /* initialize */ 362bf215546Sopenharmony_ci info->last_time = now; 363bf215546Sopenharmony_ci info->last_thread_time = util_current_thread_get_time_nano(); 364bf215546Sopenharmony_ci } 365bf215546Sopenharmony_ci} 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_civoid 368bf215546Sopenharmony_cihud_thread_busy_install(struct hud_pane *pane, const char *name, bool main) 369bf215546Sopenharmony_ci{ 370bf215546Sopenharmony_ci struct hud_graph *gr; 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci gr = CALLOC_STRUCT(hud_graph); 373bf215546Sopenharmony_ci if (!gr) 374bf215546Sopenharmony_ci return; 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci strcpy(gr->name, name); 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci gr->query_data = CALLOC_STRUCT(thread_info); 379bf215546Sopenharmony_ci if (!gr->query_data) { 380bf215546Sopenharmony_ci FREE(gr); 381bf215546Sopenharmony_ci return; 382bf215546Sopenharmony_ci } 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci ((struct thread_info*)gr->query_data)->main_thread = main; 385bf215546Sopenharmony_ci gr->query_new_value = query_api_thread_busy_status; 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci /* Don't use free() as our callback as that messes up Gallium's 388bf215546Sopenharmony_ci * memory debugger. Use simple free_query_data() wrapper. 389bf215546Sopenharmony_ci */ 390bf215546Sopenharmony_ci gr->free_query_data = free_query_data; 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci hud_pane_add_graph(pane, gr); 393bf215546Sopenharmony_ci hud_pane_set_max_value(pane, 100); 394bf215546Sopenharmony_ci} 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_cistruct counter_info { 397bf215546Sopenharmony_ci enum hud_counter counter; 398bf215546Sopenharmony_ci unsigned last_value; 399bf215546Sopenharmony_ci int64_t last_time; 400bf215546Sopenharmony_ci}; 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_cistatic unsigned get_counter(struct hud_graph *gr, enum hud_counter counter) 403bf215546Sopenharmony_ci{ 404bf215546Sopenharmony_ci struct util_queue_monitoring *mon = gr->pane->hud->monitored_queue; 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci if (!mon || !mon->queue) 407bf215546Sopenharmony_ci return 0; 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci switch (counter) { 410bf215546Sopenharmony_ci case HUD_COUNTER_OFFLOADED: 411bf215546Sopenharmony_ci return mon->num_offloaded_items; 412bf215546Sopenharmony_ci case HUD_COUNTER_DIRECT: 413bf215546Sopenharmony_ci return mon->num_direct_items; 414bf215546Sopenharmony_ci case HUD_COUNTER_SYNCS: 415bf215546Sopenharmony_ci return mon->num_syncs; 416bf215546Sopenharmony_ci default: 417bf215546Sopenharmony_ci assert(0); 418bf215546Sopenharmony_ci return 0; 419bf215546Sopenharmony_ci } 420bf215546Sopenharmony_ci} 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_cistatic void 423bf215546Sopenharmony_ciquery_thread_counter(struct hud_graph *gr, struct pipe_context *pipe) 424bf215546Sopenharmony_ci{ 425bf215546Sopenharmony_ci struct counter_info *info = gr->query_data; 426bf215546Sopenharmony_ci int64_t now = os_time_get_nano(); 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci if (info->last_time) { 429bf215546Sopenharmony_ci if (info->last_time + gr->pane->period*1000 <= now) { 430bf215546Sopenharmony_ci unsigned current_value = get_counter(gr, info->counter); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci hud_graph_add_value(gr, current_value - info->last_value); 433bf215546Sopenharmony_ci info->last_value = current_value; 434bf215546Sopenharmony_ci info->last_time = now; 435bf215546Sopenharmony_ci } 436bf215546Sopenharmony_ci } else { 437bf215546Sopenharmony_ci /* initialize */ 438bf215546Sopenharmony_ci info->last_value = get_counter(gr, info->counter); 439bf215546Sopenharmony_ci info->last_time = now; 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci} 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_civoid hud_thread_counter_install(struct hud_pane *pane, const char *name, 444bf215546Sopenharmony_ci enum hud_counter counter) 445bf215546Sopenharmony_ci{ 446bf215546Sopenharmony_ci struct hud_graph *gr = CALLOC_STRUCT(hud_graph); 447bf215546Sopenharmony_ci if (!gr) 448bf215546Sopenharmony_ci return; 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci strcpy(gr->name, name); 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci gr->query_data = CALLOC_STRUCT(counter_info); 453bf215546Sopenharmony_ci if (!gr->query_data) { 454bf215546Sopenharmony_ci FREE(gr); 455bf215546Sopenharmony_ci return; 456bf215546Sopenharmony_ci } 457bf215546Sopenharmony_ci 458bf215546Sopenharmony_ci ((struct counter_info*)gr->query_data)->counter = counter; 459bf215546Sopenharmony_ci gr->query_new_value = query_thread_counter; 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_ci /* Don't use free() as our callback as that messes up Gallium's 462bf215546Sopenharmony_ci * memory debugger. Use simple free_query_data() wrapper. 463bf215546Sopenharmony_ci */ 464bf215546Sopenharmony_ci gr->free_query_data = free_query_data; 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci hud_pane_add_graph(pane, gr); 467bf215546Sopenharmony_ci hud_pane_set_max_value(pane, 100); 468bf215546Sopenharmony_ci} 469