1af69d88dSmrg/************************************************************************** 2af69d88dSmrg * 3af69d88dSmrg * Copyright 2013 Marek Olšák <maraeo@gmail.com> 4af69d88dSmrg * All Rights Reserved. 5af69d88dSmrg * 6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7af69d88dSmrg * copy of this software and associated documentation files (the 8af69d88dSmrg * "Software"), to deal in the Software without restriction, including 9af69d88dSmrg * without limitation the rights to use, copy, modify, merge, publish, 10af69d88dSmrg * distribute, sub license, and/or sell copies of the Software, and to 11af69d88dSmrg * permit persons to whom the Software is furnished to do so, subject to 12af69d88dSmrg * the following conditions: 13af69d88dSmrg * 14af69d88dSmrg * The above copyright notice and this permission notice (including the 15af69d88dSmrg * next paragraph) shall be included in all copies or substantial portions 16af69d88dSmrg * of the Software. 17af69d88dSmrg * 18af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20af69d88dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21af69d88dSmrg * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 22af69d88dSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23af69d88dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24af69d88dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25af69d88dSmrg * 26af69d88dSmrg **************************************************************************/ 27af69d88dSmrg 28af69d88dSmrg/* This file contains code for reading CPU load for displaying on the HUD. 29af69d88dSmrg */ 30af69d88dSmrg 31af69d88dSmrg#include "hud/hud_private.h" 3201e04c3fSmrg#include "util/os_time.h" 3301e04c3fSmrg#include "os/os_thread.h" 34af69d88dSmrg#include "util/u_memory.h" 3501e04c3fSmrg#include "util/u_queue.h" 36af69d88dSmrg#include <stdio.h> 37af69d88dSmrg#include <inttypes.h> 3801e04c3fSmrg#ifdef PIPE_OS_WINDOWS 3901e04c3fSmrg#include <windows.h> 4001e04c3fSmrg#endif 417ec681f3Smrg#if defined(PIPE_OS_BSD) 42361fc4cbSmaya#include <sys/types.h> 43361fc4cbSmaya#include <sys/sysctl.h> 447ec681f3Smrg#if defined(PIPE_OS_NETBSD) || defined(PIPE_OS_OPENBSD) 457ec681f3Smrg#include <sys/sched.h> 467ec681f3Smrg#else 47361fc4cbSmaya#include <sys/resource.h> 48361fc4cbSmaya#endif 497ec681f3Smrg#endif 5001e04c3fSmrg 5101e04c3fSmrg 5201e04c3fSmrg#ifdef PIPE_OS_WINDOWS 5301e04c3fSmrg 5401e04c3fSmrgstatic inline uint64_t 5501e04c3fSmrgfiletime_to_scalar(FILETIME ft) 5601e04c3fSmrg{ 5701e04c3fSmrg ULARGE_INTEGER uli; 5801e04c3fSmrg uli.LowPart = ft.dwLowDateTime; 5901e04c3fSmrg uli.HighPart = ft.dwHighDateTime; 6001e04c3fSmrg return uli.QuadPart; 6101e04c3fSmrg} 6201e04c3fSmrg 6301e04c3fSmrgstatic boolean 6401e04c3fSmrgget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 6501e04c3fSmrg{ 6601e04c3fSmrg SYSTEM_INFO sysInfo; 6701e04c3fSmrg FILETIME ftNow, ftCreation, ftExit, ftKernel, ftUser; 6801e04c3fSmrg 6901e04c3fSmrg GetSystemInfo(&sysInfo); 7001e04c3fSmrg assert(sysInfo.dwNumberOfProcessors >= 1); 7101e04c3fSmrg if (cpu_index != ALL_CPUS && cpu_index >= sysInfo.dwNumberOfProcessors) { 7201e04c3fSmrg /* Tell hud_get_num_cpus there are only this many CPUs. */ 7301e04c3fSmrg return FALSE; 7401e04c3fSmrg } 7501e04c3fSmrg 7601e04c3fSmrg /* Get accumulated user and sys time for all threads */ 7701e04c3fSmrg if (!GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, 7801e04c3fSmrg &ftKernel, &ftUser)) 7901e04c3fSmrg return FALSE; 8001e04c3fSmrg 8101e04c3fSmrg GetSystemTimeAsFileTime(&ftNow); 8201e04c3fSmrg 8301e04c3fSmrg *busy_time = filetime_to_scalar(ftUser) + filetime_to_scalar(ftKernel); 8401e04c3fSmrg *total_time = filetime_to_scalar(ftNow) - filetime_to_scalar(ftCreation); 8501e04c3fSmrg 8601e04c3fSmrg /* busy_time already has the time accross all cpus. 8701e04c3fSmrg * XXX: if we want 100% to mean one CPU, 200% two cpus, eliminate the 8801e04c3fSmrg * following line. 8901e04c3fSmrg */ 9001e04c3fSmrg *total_time *= sysInfo.dwNumberOfProcessors; 9101e04c3fSmrg 9201e04c3fSmrg /* XXX: we ignore cpu_index, i.e, we assume that the individual CPU usage 9301e04c3fSmrg * and the system usage are one and the same. 9401e04c3fSmrg */ 9501e04c3fSmrg return TRUE; 9601e04c3fSmrg} 9701e04c3fSmrg 987ec681f3Smrg#elif defined(PIPE_OS_BSD) 99361fc4cbSmaya 100361fc4cbSmayastatic boolean 101361fc4cbSmayaget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 102361fc4cbSmaya{ 1037ec681f3Smrg#if defined(PIPE_OS_NETBSD) || defined(PIPE_OS_OPENBSD) 1047ec681f3Smrg uint64_t cp_time[CPUSTATES]; 1057ec681f3Smrg#else 106361fc4cbSmaya long cp_time[CPUSTATES]; 1077ec681f3Smrg#endif 108361fc4cbSmaya size_t len; 109361fc4cbSmaya 110361fc4cbSmaya if (cpu_index == ALL_CPUS) { 111361fc4cbSmaya len = sizeof(cp_time); 112361fc4cbSmaya 1137ec681f3Smrg#if defined(PIPE_OS_NETBSD) 1147ec681f3Smrg int mib[] = { CTL_KERN, KERN_CP_TIME }; 1157ec681f3Smrg 1167ec681f3Smrg if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 1177ec681f3Smrg return FALSE; 1187ec681f3Smrg#elif defined(PIPE_OS_OPENBSD) 1197ec681f3Smrg int mib[] = { CTL_KERN, KERN_CPTIME }; 1207ec681f3Smrg long sum_cp_time[CPUSTATES]; 1217ec681f3Smrg 1227ec681f3Smrg len = sizeof(sum_cp_time); 1237ec681f3Smrg if (sysctl(mib, ARRAY_SIZE(mib), sum_cp_time, &len, NULL, 0) == -1) 1247ec681f3Smrg return FALSE; 1257ec681f3Smrg 1267ec681f3Smrg for (int state = 0; state < CPUSTATES; state++) 1277ec681f3Smrg cp_time[state] = sum_cp_time[state]; 1287ec681f3Smrg#else 129361fc4cbSmaya if (sysctlbyname("kern.cp_time", cp_time, &len, NULL, 0) == -1) 130361fc4cbSmaya return FALSE; 1317ec681f3Smrg#endif 132361fc4cbSmaya } else { 1337ec681f3Smrg#if defined(PIPE_OS_NETBSD) 1347ec681f3Smrg int mib[] = { CTL_KERN, KERN_CP_TIME, cpu_index }; 1357ec681f3Smrg 1367ec681f3Smrg len = sizeof(cp_time); 1377ec681f3Smrg if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 1387ec681f3Smrg return FALSE; 1397ec681f3Smrg#elif defined(PIPE_OS_OPENBSD) 1407ec681f3Smrg int mib[] = { CTL_KERN, KERN_CPTIME2, cpu_index }; 1417ec681f3Smrg 1427ec681f3Smrg len = sizeof(cp_time); 1437ec681f3Smrg if (sysctl(mib, ARRAY_SIZE(mib), cp_time, &len, NULL, 0) == -1) 1447ec681f3Smrg return FALSE; 1457ec681f3Smrg#else 146361fc4cbSmaya long *cp_times = NULL; 147361fc4cbSmaya 148361fc4cbSmaya if (sysctlbyname("kern.cp_times", NULL, &len, NULL, 0) == -1) 149361fc4cbSmaya return FALSE; 150361fc4cbSmaya 151361fc4cbSmaya if (len < (cpu_index + 1) * sizeof(cp_time)) 152361fc4cbSmaya return FALSE; 153361fc4cbSmaya 154361fc4cbSmaya cp_times = malloc(len); 155361fc4cbSmaya 156361fc4cbSmaya if (sysctlbyname("kern.cp_times", cp_times, &len, NULL, 0) == -1) 157361fc4cbSmaya return FALSE; 158361fc4cbSmaya 159361fc4cbSmaya memcpy(cp_time, cp_times + (cpu_index * CPUSTATES), 160361fc4cbSmaya sizeof(cp_time)); 161361fc4cbSmaya free(cp_times); 1627ec681f3Smrg#endif 163361fc4cbSmaya } 164361fc4cbSmaya 165361fc4cbSmaya *busy_time = cp_time[CP_USER] + cp_time[CP_NICE] + 166361fc4cbSmaya cp_time[CP_SYS] + cp_time[CP_INTR]; 167361fc4cbSmaya 168361fc4cbSmaya *total_time = *busy_time + cp_time[CP_IDLE]; 169361fc4cbSmaya 170361fc4cbSmaya return TRUE; 171361fc4cbSmaya} 172361fc4cbSmaya 17301e04c3fSmrg#else 174af69d88dSmrg 175af69d88dSmrgstatic boolean 176af69d88dSmrgget_cpu_stats(unsigned cpu_index, uint64_t *busy_time, uint64_t *total_time) 177af69d88dSmrg{ 178af69d88dSmrg char cpuname[32]; 179af69d88dSmrg char line[1024]; 180af69d88dSmrg FILE *f; 181af69d88dSmrg 182af69d88dSmrg if (cpu_index == ALL_CPUS) 183af69d88dSmrg strcpy(cpuname, "cpu"); 184af69d88dSmrg else 185af69d88dSmrg sprintf(cpuname, "cpu%u", cpu_index); 186af69d88dSmrg 187af69d88dSmrg f = fopen("/proc/stat", "r"); 188af69d88dSmrg if (!f) 189af69d88dSmrg return FALSE; 190af69d88dSmrg 191af69d88dSmrg while (!feof(f) && fgets(line, sizeof(line), f)) { 192af69d88dSmrg if (strstr(line, cpuname) == line) { 193af69d88dSmrg uint64_t v[12]; 194af69d88dSmrg int i, num; 195af69d88dSmrg 196af69d88dSmrg num = sscanf(line, 197af69d88dSmrg "%s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 198af69d88dSmrg " %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64 199af69d88dSmrg " %"PRIu64" %"PRIu64"", 200af69d88dSmrg cpuname, &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], 201af69d88dSmrg &v[6], &v[7], &v[8], &v[9], &v[10], &v[11]); 202af69d88dSmrg if (num < 5) { 203af69d88dSmrg fclose(f); 204af69d88dSmrg return FALSE; 205af69d88dSmrg } 206af69d88dSmrg 207af69d88dSmrg /* user + nice + system */ 208af69d88dSmrg *busy_time = v[0] + v[1] + v[2]; 209af69d88dSmrg *total_time = *busy_time; 210af69d88dSmrg 211af69d88dSmrg /* ... + idle + iowait + irq + softirq + ... */ 212af69d88dSmrg for (i = 3; i < num-1; i++) { 213af69d88dSmrg *total_time += v[i]; 214af69d88dSmrg } 215af69d88dSmrg fclose(f); 216af69d88dSmrg return TRUE; 217af69d88dSmrg } 218af69d88dSmrg } 219af69d88dSmrg fclose(f); 220af69d88dSmrg return FALSE; 221af69d88dSmrg} 22201e04c3fSmrg#endif 22301e04c3fSmrg 224af69d88dSmrg 225af69d88dSmrgstruct cpu_info { 226af69d88dSmrg unsigned cpu_index; 227af69d88dSmrg uint64_t last_cpu_busy, last_cpu_total, last_time; 228af69d88dSmrg}; 229af69d88dSmrg 230af69d88dSmrgstatic void 23101e04c3fSmrgquery_cpu_load(struct hud_graph *gr, struct pipe_context *pipe) 232af69d88dSmrg{ 233af69d88dSmrg struct cpu_info *info = gr->query_data; 234af69d88dSmrg uint64_t now = os_time_get(); 235af69d88dSmrg 236af69d88dSmrg if (info->last_time) { 237af69d88dSmrg if (info->last_time + gr->pane->period <= now) { 23801e04c3fSmrg uint64_t cpu_busy, cpu_total; 23901e04c3fSmrg double cpu_load; 240af69d88dSmrg 241af69d88dSmrg get_cpu_stats(info->cpu_index, &cpu_busy, &cpu_total); 242af69d88dSmrg 243af69d88dSmrg cpu_load = (cpu_busy - info->last_cpu_busy) * 100 / 244af69d88dSmrg (double)(cpu_total - info->last_cpu_total); 245af69d88dSmrg hud_graph_add_value(gr, cpu_load); 246af69d88dSmrg 247af69d88dSmrg info->last_cpu_busy = cpu_busy; 248af69d88dSmrg info->last_cpu_total = cpu_total; 249af69d88dSmrg info->last_time = now; 250af69d88dSmrg } 251af69d88dSmrg } 252af69d88dSmrg else { 253af69d88dSmrg /* initialize */ 254af69d88dSmrg info->last_time = now; 255af69d88dSmrg get_cpu_stats(info->cpu_index, &info->last_cpu_busy, 256af69d88dSmrg &info->last_cpu_total); 257af69d88dSmrg } 258af69d88dSmrg} 259af69d88dSmrg 260af69d88dSmrgstatic void 26101e04c3fSmrgfree_query_data(void *p, struct pipe_context *pipe) 262af69d88dSmrg{ 263af69d88dSmrg FREE(p); 264af69d88dSmrg} 265af69d88dSmrg 266af69d88dSmrgvoid 267af69d88dSmrghud_cpu_graph_install(struct hud_pane *pane, unsigned cpu_index) 268af69d88dSmrg{ 269af69d88dSmrg struct hud_graph *gr; 270af69d88dSmrg struct cpu_info *info; 271af69d88dSmrg uint64_t busy, total; 272af69d88dSmrg 273af69d88dSmrg /* see if the cpu exists */ 274af69d88dSmrg if (cpu_index != ALL_CPUS && !get_cpu_stats(cpu_index, &busy, &total)) { 275af69d88dSmrg return; 276af69d88dSmrg } 277af69d88dSmrg 278af69d88dSmrg gr = CALLOC_STRUCT(hud_graph); 279af69d88dSmrg if (!gr) 280af69d88dSmrg return; 281af69d88dSmrg 282af69d88dSmrg if (cpu_index == ALL_CPUS) 283af69d88dSmrg strcpy(gr->name, "cpu"); 284af69d88dSmrg else 285af69d88dSmrg sprintf(gr->name, "cpu%u", cpu_index); 286af69d88dSmrg 287af69d88dSmrg gr->query_data = CALLOC_STRUCT(cpu_info); 288af69d88dSmrg if (!gr->query_data) { 289af69d88dSmrg FREE(gr); 290af69d88dSmrg return; 291af69d88dSmrg } 292af69d88dSmrg 293af69d88dSmrg gr->query_new_value = query_cpu_load; 294af69d88dSmrg 295af69d88dSmrg /* Don't use free() as our callback as that messes up Gallium's 296af69d88dSmrg * memory debugger. Use simple free_query_data() wrapper. 297af69d88dSmrg */ 298af69d88dSmrg gr->free_query_data = free_query_data; 299af69d88dSmrg 300af69d88dSmrg info = gr->query_data; 301af69d88dSmrg info->cpu_index = cpu_index; 302af69d88dSmrg 303af69d88dSmrg hud_pane_add_graph(pane, gr); 304af69d88dSmrg hud_pane_set_max_value(pane, 100); 305af69d88dSmrg} 306af69d88dSmrg 307af69d88dSmrgint 308af69d88dSmrghud_get_num_cpus(void) 309af69d88dSmrg{ 310af69d88dSmrg uint64_t busy, total; 311af69d88dSmrg int i = 0; 312af69d88dSmrg 313af69d88dSmrg while (get_cpu_stats(i, &busy, &total)) 314af69d88dSmrg i++; 315af69d88dSmrg 316af69d88dSmrg return i; 317af69d88dSmrg} 31801e04c3fSmrg 31901e04c3fSmrgstruct thread_info { 32001e04c3fSmrg bool main_thread; 32101e04c3fSmrg int64_t last_time; 32201e04c3fSmrg int64_t last_thread_time; 32301e04c3fSmrg}; 32401e04c3fSmrg 32501e04c3fSmrgstatic void 32601e04c3fSmrgquery_api_thread_busy_status(struct hud_graph *gr, struct pipe_context *pipe) 32701e04c3fSmrg{ 32801e04c3fSmrg struct thread_info *info = gr->query_data; 32901e04c3fSmrg int64_t now = os_time_get_nano(); 33001e04c3fSmrg 33101e04c3fSmrg if (info->last_time) { 33201e04c3fSmrg if (info->last_time + gr->pane->period*1000 <= now) { 33301e04c3fSmrg int64_t thread_now; 33401e04c3fSmrg 33501e04c3fSmrg if (info->main_thread) { 3367ec681f3Smrg thread_now = util_current_thread_get_time_nano(); 33701e04c3fSmrg } else { 33801e04c3fSmrg struct util_queue_monitoring *mon = gr->pane->hud->monitored_queue; 33901e04c3fSmrg 34001e04c3fSmrg if (mon && mon->queue) 34101e04c3fSmrg thread_now = util_queue_get_thread_time_nano(mon->queue, 0); 34201e04c3fSmrg else 34301e04c3fSmrg thread_now = 0; 34401e04c3fSmrg } 34501e04c3fSmrg 34601e04c3fSmrg double percent = (thread_now - info->last_thread_time) * 100.0 / 34701e04c3fSmrg (now - info->last_time); 34801e04c3fSmrg 34901e04c3fSmrg /* Check if the context changed a thread, so that we don't show 35001e04c3fSmrg * a random value. When a thread is changed, the new thread clock 35101e04c3fSmrg * is different, which can result in "percent" being very high. 35201e04c3fSmrg */ 35301e04c3fSmrg if (percent > 100.0) 35401e04c3fSmrg percent = 0.0; 35501e04c3fSmrg hud_graph_add_value(gr, percent); 35601e04c3fSmrg 35701e04c3fSmrg info->last_thread_time = thread_now; 35801e04c3fSmrg info->last_time = now; 35901e04c3fSmrg } 36001e04c3fSmrg } else { 36101e04c3fSmrg /* initialize */ 36201e04c3fSmrg info->last_time = now; 3637ec681f3Smrg info->last_thread_time = util_current_thread_get_time_nano(); 36401e04c3fSmrg } 36501e04c3fSmrg} 36601e04c3fSmrg 36701e04c3fSmrgvoid 36801e04c3fSmrghud_thread_busy_install(struct hud_pane *pane, const char *name, bool main) 36901e04c3fSmrg{ 37001e04c3fSmrg struct hud_graph *gr; 37101e04c3fSmrg 37201e04c3fSmrg gr = CALLOC_STRUCT(hud_graph); 37301e04c3fSmrg if (!gr) 37401e04c3fSmrg return; 37501e04c3fSmrg 37601e04c3fSmrg strcpy(gr->name, name); 37701e04c3fSmrg 37801e04c3fSmrg gr->query_data = CALLOC_STRUCT(thread_info); 37901e04c3fSmrg if (!gr->query_data) { 38001e04c3fSmrg FREE(gr); 38101e04c3fSmrg return; 38201e04c3fSmrg } 38301e04c3fSmrg 38401e04c3fSmrg ((struct thread_info*)gr->query_data)->main_thread = main; 38501e04c3fSmrg gr->query_new_value = query_api_thread_busy_status; 38601e04c3fSmrg 38701e04c3fSmrg /* Don't use free() as our callback as that messes up Gallium's 38801e04c3fSmrg * memory debugger. Use simple free_query_data() wrapper. 38901e04c3fSmrg */ 39001e04c3fSmrg gr->free_query_data = free_query_data; 39101e04c3fSmrg 39201e04c3fSmrg hud_pane_add_graph(pane, gr); 39301e04c3fSmrg hud_pane_set_max_value(pane, 100); 39401e04c3fSmrg} 39501e04c3fSmrg 39601e04c3fSmrgstruct counter_info { 39701e04c3fSmrg enum hud_counter counter; 39801e04c3fSmrg unsigned last_value; 39901e04c3fSmrg int64_t last_time; 40001e04c3fSmrg}; 40101e04c3fSmrg 40201e04c3fSmrgstatic unsigned get_counter(struct hud_graph *gr, enum hud_counter counter) 40301e04c3fSmrg{ 40401e04c3fSmrg struct util_queue_monitoring *mon = gr->pane->hud->monitored_queue; 40501e04c3fSmrg 40601e04c3fSmrg if (!mon || !mon->queue) 40701e04c3fSmrg return 0; 40801e04c3fSmrg 40901e04c3fSmrg switch (counter) { 41001e04c3fSmrg case HUD_COUNTER_OFFLOADED: 41101e04c3fSmrg return mon->num_offloaded_items; 41201e04c3fSmrg case HUD_COUNTER_DIRECT: 41301e04c3fSmrg return mon->num_direct_items; 41401e04c3fSmrg case HUD_COUNTER_SYNCS: 41501e04c3fSmrg return mon->num_syncs; 41601e04c3fSmrg default: 41701e04c3fSmrg assert(0); 41801e04c3fSmrg return 0; 41901e04c3fSmrg } 42001e04c3fSmrg} 42101e04c3fSmrg 42201e04c3fSmrgstatic void 42301e04c3fSmrgquery_thread_counter(struct hud_graph *gr, struct pipe_context *pipe) 42401e04c3fSmrg{ 42501e04c3fSmrg struct counter_info *info = gr->query_data; 42601e04c3fSmrg int64_t now = os_time_get_nano(); 42701e04c3fSmrg 42801e04c3fSmrg if (info->last_time) { 42901e04c3fSmrg if (info->last_time + gr->pane->period*1000 <= now) { 43001e04c3fSmrg unsigned current_value = get_counter(gr, info->counter); 43101e04c3fSmrg 43201e04c3fSmrg hud_graph_add_value(gr, current_value - info->last_value); 43301e04c3fSmrg info->last_value = current_value; 43401e04c3fSmrg info->last_time = now; 43501e04c3fSmrg } 43601e04c3fSmrg } else { 43701e04c3fSmrg /* initialize */ 43801e04c3fSmrg info->last_value = get_counter(gr, info->counter); 43901e04c3fSmrg info->last_time = now; 44001e04c3fSmrg } 44101e04c3fSmrg} 44201e04c3fSmrg 44301e04c3fSmrgvoid hud_thread_counter_install(struct hud_pane *pane, const char *name, 44401e04c3fSmrg enum hud_counter counter) 44501e04c3fSmrg{ 44601e04c3fSmrg struct hud_graph *gr = CALLOC_STRUCT(hud_graph); 44701e04c3fSmrg if (!gr) 44801e04c3fSmrg return; 44901e04c3fSmrg 45001e04c3fSmrg strcpy(gr->name, name); 45101e04c3fSmrg 45201e04c3fSmrg gr->query_data = CALLOC_STRUCT(counter_info); 45301e04c3fSmrg if (!gr->query_data) { 45401e04c3fSmrg FREE(gr); 45501e04c3fSmrg return; 45601e04c3fSmrg } 45701e04c3fSmrg 45801e04c3fSmrg ((struct counter_info*)gr->query_data)->counter = counter; 45901e04c3fSmrg gr->query_new_value = query_thread_counter; 46001e04c3fSmrg 46101e04c3fSmrg /* Don't use free() as our callback as that messes up Gallium's 46201e04c3fSmrg * memory debugger. Use simple free_query_data() wrapper. 46301e04c3fSmrg */ 46401e04c3fSmrg gr->free_query_data = free_query_data; 46501e04c3fSmrg 46601e04c3fSmrg hud_pane_add_graph(pane, gr); 46701e04c3fSmrg hud_pane_set_max_value(pane, 100); 46801e04c3fSmrg} 469