Path: blob/21.2-virgl/src/gallium/auxiliary/hud/hud_diskstat.c
4565 views
/**************************************************************************1*2* Copyright (C) 2016 Steven Toth <[email protected]>3* Copyright (C) 2016 Zodiac Inflight Innovations4* All Rights Reserved.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the8* "Software"), to deal in the Software without restriction, including9* without limitation the rights to use, copy, modify, merge, publish,10* distribute, sub license, and/or sell copies of the Software, and to11* permit persons to whom the Software is furnished to do so, subject to12* the following conditions:13*14* The above copyright notice and this permission notice (including the15* next paragraph) shall be included in all copies or substantial portions16* of the Software.17*18* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS19* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF20* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.21* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR22* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,23* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE24* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.25*26**************************************************************************/2728#ifdef HAVE_GALLIUM_EXTRA_HUD2930/* Purpose: Reading /sys/block/<*>/stat MB/s read/write throughput per second,31* displaying on the HUD.32*/3334#include "hud/hud_private.h"35#include "util/list.h"36#include "util/os_time.h"37#include "os/os_thread.h"38#include "util/u_memory.h"39#include "util/u_string.h"40#include <stdio.h>41#include <unistd.h>42#include <dirent.h>43#include <stdlib.h>44#include <unistd.h>45#include <inttypes.h>46#include <sys/types.h>47#include <sys/stat.h>48#include <unistd.h>4950struct stat_s51{52/* Read */53uint64_t r_ios;54uint64_t r_merges;55uint64_t r_sectors;56uint64_t r_ticks;57/* Write */58uint64_t w_ios;59uint64_t w_merges;60uint64_t w_sectors;61uint64_t w_ticks;62/* Misc */63uint64_t in_flight;64uint64_t io_ticks;65uint64_t time_in_queue;66};6768struct diskstat_info69{70struct list_head list;71int mode; /* DISKSTAT_RD, DISKSTAT_WR */72char name[64]; /* EG. sda5 */7374char sysfs_filename[128];75uint64_t last_time;76struct stat_s last_stat;77};7879/* TODO: We don't handle dynamic block device / partition80* arrival or removal.81* Static globals specific to this HUD category.82*/83static int gdiskstat_count = 0;84static struct list_head gdiskstat_list;85static mtx_t gdiskstat_mutex = _MTX_INITIALIZER_NP;8687static struct diskstat_info *88find_dsi_by_name(const char *n, int mode)89{90list_for_each_entry(struct diskstat_info, dsi, &gdiskstat_list, list) {91if (dsi->mode != mode)92continue;93if (strcasecmp(dsi->name, n) == 0)94return dsi;95}96return 0;97}9899static int100get_file_values(const char *fn, struct stat_s *s)101{102int ret = 0;103FILE *fh = fopen(fn, "r");104if (!fh)105return -1;106107ret = fscanf(fh,108"%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64109" %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "",110&s->r_ios, &s->r_merges, &s->r_sectors, &s->r_ticks, &s->w_ios,111&s->w_merges, &s->w_sectors, &s->w_ticks, &s->in_flight, &s->io_ticks,112&s->time_in_queue);113114fclose(fh);115116return ret;117}118119static void120query_dsi_load(struct hud_graph *gr, struct pipe_context *pipe)121{122/* The framework calls us periodically, compensate for the123* calling interval accordingly when reporting per second.124*/125struct diskstat_info *dsi = gr->query_data;126uint64_t now = os_time_get();127128if (dsi->last_time) {129if (dsi->last_time + gr->pane->period <= now) {130struct stat_s stat;131if (get_file_values(dsi->sysfs_filename, &stat) < 0)132return;133float val = 0;134135switch (dsi->mode) {136case DISKSTAT_RD:137val =138((stat.r_sectors -139dsi->last_stat.r_sectors) * 512) /140(((float) gr->pane->period / 1000) / 1000);141break;142case DISKSTAT_WR:143val =144((stat.w_sectors -145dsi->last_stat.w_sectors) * 512) /146(((float) gr->pane->period / 1000) / 1000);147break;148}149150hud_graph_add_value(gr, (uint64_t) val);151dsi->last_stat = stat;152dsi->last_time = now;153}154}155else {156/* initialize */157switch (dsi->mode) {158case DISKSTAT_RD:159case DISKSTAT_WR:160get_file_values(dsi->sysfs_filename, &dsi->last_stat);161break;162}163dsi->last_time = now;164}165}166167/**168* Create and initialize a new object for a specific block I/O device.169* \param pane parent context.170* \param dev_name logical block device name, EG. sda5.171* \param mode query read or write (DISKSTAT_RD/DISKSTAT_WR) statistics.172*/173void174hud_diskstat_graph_install(struct hud_pane *pane, const char *dev_name,175unsigned int mode)176{177struct hud_graph *gr;178struct diskstat_info *dsi;179180int num_devs = hud_get_num_disks(0);181if (num_devs <= 0)182return;183184dsi = find_dsi_by_name(dev_name, mode);185if (!dsi)186return;187188gr = CALLOC_STRUCT(hud_graph);189if (!gr)190return;191192dsi->mode = mode;193if (dsi->mode == DISKSTAT_RD) {194snprintf(gr->name, sizeof(gr->name), "%s-Read-MB/s", dsi->name);195}196else if (dsi->mode == DISKSTAT_WR) {197snprintf(gr->name, sizeof(gr->name), "%s-Write-MB/s", dsi->name);198}199else {200free(gr);201return;202}203204gr->query_data = dsi;205gr->query_new_value = query_dsi_load;206207hud_pane_add_graph(pane, gr);208hud_pane_set_max_value(pane, 100);209}210211static void212add_object_part(const char *basename, const char *name, int objmode)213{214struct diskstat_info *dsi = CALLOC_STRUCT(diskstat_info);215216snprintf(dsi->name, sizeof(dsi->name), "%s", name);217snprintf(dsi->sysfs_filename, sizeof(dsi->sysfs_filename), "%s/%s/stat",218basename, name);219dsi->mode = objmode;220list_addtail(&dsi->list, &gdiskstat_list);221gdiskstat_count++;222}223224static void225add_object(const char *basename, const char *name, int objmode)226{227struct diskstat_info *dsi = CALLOC_STRUCT(diskstat_info);228229snprintf(dsi->name, sizeof(dsi->name), "%s", name);230snprintf(dsi->sysfs_filename, sizeof(dsi->sysfs_filename), "%s/stat",231basename);232dsi->mode = objmode;233list_addtail(&dsi->list, &gdiskstat_list);234gdiskstat_count++;235}236237/**238* Initialize internal object arrays and display block I/O HUD help.239* \param displayhelp true if the list of detected devices should be240displayed on the console.241* \return number of detected block I/O devices.242*/243int244hud_get_num_disks(bool displayhelp)245{246struct dirent *dp;247struct stat stat_buf;248char name[64];249250/* Return the number of block devices and partitions. */251mtx_lock(&gdiskstat_mutex);252if (gdiskstat_count) {253mtx_unlock(&gdiskstat_mutex);254return gdiskstat_count;255}256257/* Scan /sys/block, for every object type we support, create and258* persist an object to represent its different statistics.259*/260list_inithead(&gdiskstat_list);261DIR *dir = opendir("/sys/block/");262if (!dir) {263mtx_unlock(&gdiskstat_mutex);264return 0;265}266267while ((dp = readdir(dir)) != NULL) {268269/* Avoid 'lo' and '..' and '.' */270if (strlen(dp->d_name) <= 2)271continue;272273char basename[256];274snprintf(basename, sizeof(basename), "/sys/block/%s", dp->d_name);275snprintf(name, sizeof(name), "%s/stat", basename);276if (stat(name, &stat_buf) < 0)277continue;278279if (!S_ISREG(stat_buf.st_mode))280continue; /* Not a regular file */281282/* Add a physical block device with R/W stats */283add_object(basename, dp->d_name, DISKSTAT_RD);284add_object(basename, dp->d_name, DISKSTAT_WR);285286/* Add any partitions */287struct dirent *dpart;288DIR *pdir = opendir(basename);289if (!pdir) {290mtx_unlock(&gdiskstat_mutex);291closedir(dir);292return 0;293}294295while ((dpart = readdir(pdir)) != NULL) {296/* Avoid 'lo' and '..' and '.' */297if (strlen(dpart->d_name) <= 2)298continue;299300char p[64];301snprintf(p, sizeof(p), "%s/%s/stat", basename, dpart->d_name);302if (stat(p, &stat_buf) < 0)303continue;304305if (!S_ISREG(stat_buf.st_mode))306continue; /* Not a regular file */307308/* Add a partition with R/W stats */309add_object_part(basename, dpart->d_name, DISKSTAT_RD);310add_object_part(basename, dpart->d_name, DISKSTAT_WR);311}312}313closedir(dir);314315if (displayhelp) {316list_for_each_entry(struct diskstat_info, dsi, &gdiskstat_list, list) {317char line[32];318snprintf(line, sizeof(line), " diskstat-%s-%s",319dsi->mode == DISKSTAT_RD ? "rd" :320dsi->mode == DISKSTAT_WR ? "wr" : "undefined", dsi->name);321322puts(line);323}324}325mtx_unlock(&gdiskstat_mutex);326327return gdiskstat_count;328}329330#endif /* HAVE_GALLIUM_EXTRA_HUD */331332333