"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/auxiliary/hud/hud_diskstat.c" (16 Sep 2020, 9350 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "hud_diskstat.c" see the Fossies "Dox" file reference documentation.

    1 /**************************************************************************
    2  *
    3  * Copyright (C) 2016 Steven Toth <stoth@kernellabs.com>
    4  * Copyright (C) 2016 Zodiac Inflight Innovations
    5  * All Rights Reserved.
    6  *
    7  * Permission is hereby granted, free of charge, to any person obtaining a
    8  * copy of this software and associated documentation files (the
    9  * "Software"), to deal in the Software without restriction, including
   10  * without limitation the rights to use, copy, modify, merge, publish,
   11  * distribute, sub license, and/or sell copies of the Software, and to
   12  * permit persons to whom the Software is furnished to do so, subject to
   13  * the following conditions:
   14  *
   15  * The above copyright notice and this permission notice (including the
   16  * next paragraph) shall be included in all copies or substantial portions
   17  * of the Software.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
   22  * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
   23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26  *
   27  **************************************************************************/
   28 
   29 #ifdef HAVE_GALLIUM_EXTRA_HUD
   30 
   31 /* Purpose: Reading /sys/block/<*>/stat MB/s read/write throughput per second,
   32  * displaying on the HUD.
   33  */
   34 
   35 #include "hud/hud_private.h"
   36 #include "util/list.h"
   37 #include "util/os_time.h"
   38 #include "os/os_thread.h"
   39 #include "util/u_memory.h"
   40 #include "util/u_string.h"
   41 #include <stdio.h>
   42 #include <unistd.h>
   43 #include <dirent.h>
   44 #include <stdlib.h>
   45 #include <unistd.h>
   46 #include <inttypes.h>
   47 #include <sys/types.h>
   48 #include <sys/stat.h>
   49 #include <unistd.h>
   50 
   51 struct stat_s
   52 {
   53    /* Read */
   54    uint64_t r_ios;
   55    uint64_t r_merges;
   56    uint64_t r_sectors;
   57    uint64_t r_ticks;
   58    /* Write */
   59    uint64_t w_ios;
   60    uint64_t w_merges;
   61    uint64_t w_sectors;
   62    uint64_t w_ticks;
   63    /* Misc */
   64    uint64_t in_flight;
   65    uint64_t io_ticks;
   66    uint64_t time_in_queue;
   67 };
   68 
   69 struct diskstat_info
   70 {
   71    struct list_head list;
   72    int mode; /* DISKSTAT_RD, DISKSTAT_WR */
   73    char name[64]; /* EG. sda5 */
   74 
   75    char sysfs_filename[128];
   76    uint64_t last_time;
   77    struct stat_s last_stat;
   78 };
   79 
   80 /* TODO: We don't handle dynamic block device / partition
   81  * arrival or removal.
   82  * Static globals specific to this HUD category.
   83  */
   84 static int gdiskstat_count = 0;
   85 static struct list_head gdiskstat_list;
   86 static mtx_t gdiskstat_mutex = _MTX_INITIALIZER_NP;
   87 
   88 static struct diskstat_info *
   89 find_dsi_by_name(const char *n, int mode)
   90 {
   91    list_for_each_entry(struct diskstat_info, dsi, &gdiskstat_list, list) {
   92       if (dsi->mode != mode)
   93          continue;
   94       if (strcasecmp(dsi->name, n) == 0)
   95          return dsi;
   96    }
   97    return 0;
   98 }
   99 
  100 static int
  101 get_file_values(const char *fn, struct stat_s *s)
  102 {
  103    int ret = 0;
  104    FILE *fh = fopen(fn, "r");
  105    if (!fh)
  106       return -1;
  107 
  108    ret = fscanf(fh,
  109         "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
  110         " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "",
  111         &s->r_ios, &s->r_merges, &s->r_sectors, &s->r_ticks, &s->w_ios,
  112         &s->w_merges, &s->w_sectors, &s->w_ticks, &s->in_flight, &s->io_ticks,
  113         &s->time_in_queue);
  114 
  115    fclose(fh);
  116 
  117    return ret;
  118 }
  119 
  120 static void
  121 query_dsi_load(struct hud_graph *gr, struct pipe_context *pipe)
  122 {
  123    /* The framework calls us periodically, compensate for the
  124     * calling interval accordingly when reporting per second.
  125     */
  126    struct diskstat_info *dsi = gr->query_data;
  127    uint64_t now = os_time_get();
  128 
  129    if (dsi->last_time) {
  130       if (dsi->last_time + gr->pane->period <= now) {
  131          struct stat_s stat;
  132          if (get_file_values(dsi->sysfs_filename, &stat) < 0)
  133             return;
  134          float val = 0;
  135 
  136          switch (dsi->mode) {
  137          case DISKSTAT_RD:
  138             val =
  139                ((stat.r_sectors -
  140                  dsi->last_stat.r_sectors) * 512) /
  141                (((float) gr->pane->period / 1000) / 1000);
  142             break;
  143          case DISKSTAT_WR:
  144             val =
  145                ((stat.w_sectors -
  146                  dsi->last_stat.w_sectors) * 512) /
  147                (((float) gr->pane->period / 1000) / 1000);
  148             break;
  149          }
  150 
  151          hud_graph_add_value(gr, (uint64_t) val);
  152          dsi->last_stat = stat;
  153          dsi->last_time = now;
  154       }
  155    }
  156    else {
  157       /* initialize */
  158       switch (dsi->mode) {
  159       case DISKSTAT_RD:
  160       case DISKSTAT_WR:
  161          get_file_values(dsi->sysfs_filename, &dsi->last_stat);
  162          break;
  163       }
  164       dsi->last_time = now;
  165    }
  166 }
  167 
  168 /**
  169   * Create and initialize a new object for a specific block I/O device.
  170   * \param  pane  parent context.
  171   * \param  dev_name  logical block device name, EG. sda5.
  172   * \param  mode  query read or write (DISKSTAT_RD/DISKSTAT_WR) statistics.
  173   */
  174 void
  175 hud_diskstat_graph_install(struct hud_pane *pane, const char *dev_name,
  176                            unsigned int mode)
  177 {
  178    struct hud_graph *gr;
  179    struct diskstat_info *dsi;
  180 
  181    int num_devs = hud_get_num_disks(0);
  182    if (num_devs <= 0)
  183       return;
  184 
  185    dsi = find_dsi_by_name(dev_name, mode);
  186    if (!dsi)
  187       return;
  188 
  189    gr = CALLOC_STRUCT(hud_graph);
  190    if (!gr)
  191       return;
  192 
  193    dsi->mode = mode;
  194    if (dsi->mode == DISKSTAT_RD) {
  195       snprintf(gr->name, sizeof(gr->name), "%s-Read-MB/s", dsi->name);
  196    }
  197    else if (dsi->mode == DISKSTAT_WR) {
  198       snprintf(gr->name, sizeof(gr->name), "%s-Write-MB/s", dsi->name);
  199    }
  200    else {
  201       free(gr);
  202       return;
  203    }
  204 
  205    gr->query_data = dsi;
  206    gr->query_new_value = query_dsi_load;
  207 
  208    hud_pane_add_graph(pane, gr);
  209    hud_pane_set_max_value(pane, 100);
  210 }
  211 
  212 static void
  213 add_object_part(const char *basename, const char *name, int objmode)
  214 {
  215    struct diskstat_info *dsi = CALLOC_STRUCT(diskstat_info);
  216 
  217    snprintf(dsi->name, sizeof(dsi->name), "%s", name);
  218    snprintf(dsi->sysfs_filename, sizeof(dsi->sysfs_filename), "%s/%s/stat",
  219       basename, name);
  220    dsi->mode = objmode;
  221    list_addtail(&dsi->list, &gdiskstat_list);
  222    gdiskstat_count++;
  223 }
  224 
  225 static void
  226 add_object(const char *basename, const char *name, int objmode)
  227 {
  228    struct diskstat_info *dsi = CALLOC_STRUCT(diskstat_info);
  229 
  230    snprintf(dsi->name, sizeof(dsi->name), "%s", name);
  231    snprintf(dsi->sysfs_filename, sizeof(dsi->sysfs_filename), "%s/stat",
  232       basename);
  233    dsi->mode = objmode;
  234    list_addtail(&dsi->list, &gdiskstat_list);
  235    gdiskstat_count++;
  236 }
  237 
  238 /**
  239   * Initialize internal object arrays and display block I/O HUD help.
  240   * \param  displayhelp  true if the list of detected devices should be
  241                          displayed on the console.
  242   * \return  number of detected block I/O devices.
  243   */
  244 int
  245 hud_get_num_disks(bool displayhelp)
  246 {
  247    struct dirent *dp;
  248    struct stat stat_buf;
  249    char name[64];
  250 
  251    /* Return the number of block devices and partitions. */
  252    mtx_lock(&gdiskstat_mutex);
  253    if (gdiskstat_count) {
  254       mtx_unlock(&gdiskstat_mutex);
  255       return gdiskstat_count;
  256    }
  257 
  258    /* Scan /sys/block, for every object type we support, create and
  259     * persist an object to represent its different statistics.
  260     */
  261    list_inithead(&gdiskstat_list);
  262    DIR *dir = opendir("/sys/block/");
  263    if (!dir) {
  264       mtx_unlock(&gdiskstat_mutex);
  265       return 0;
  266    }
  267 
  268    while ((dp = readdir(dir)) != NULL) {
  269 
  270       /* Avoid 'lo' and '..' and '.' */
  271       if (strlen(dp->d_name) <= 2)
  272          continue;
  273 
  274       char basename[256];
  275       snprintf(basename, sizeof(basename), "/sys/block/%s", dp->d_name);
  276       snprintf(name, sizeof(name), "%s/stat", basename);
  277       if (stat(name, &stat_buf) < 0)
  278          continue;
  279 
  280       if (!S_ISREG(stat_buf.st_mode))
  281          continue;              /* Not a regular file */
  282 
  283       /* Add a physical block device with R/W stats */
  284       add_object(basename, dp->d_name, DISKSTAT_RD);
  285       add_object(basename, dp->d_name, DISKSTAT_WR);
  286 
  287       /* Add any partitions */
  288       struct dirent *dpart;
  289       DIR *pdir = opendir(basename);
  290       if (!pdir) {
  291          mtx_unlock(&gdiskstat_mutex);
  292          closedir(dir);
  293          return 0;
  294       }
  295 
  296       while ((dpart = readdir(pdir)) != NULL) {
  297          /* Avoid 'lo' and '..' and '.' */
  298          if (strlen(dpart->d_name) <= 2)
  299             continue;
  300 
  301          char p[64];
  302          snprintf(p, sizeof(p), "%s/%s/stat", basename, dpart->d_name);
  303          if (stat(p, &stat_buf) < 0)
  304             continue;
  305 
  306          if (!S_ISREG(stat_buf.st_mode))
  307             continue;           /* Not a regular file */
  308 
  309          /* Add a partition with R/W stats */
  310          add_object_part(basename, dpart->d_name, DISKSTAT_RD);
  311          add_object_part(basename, dpart->d_name, DISKSTAT_WR);
  312       }
  313    }
  314    closedir(dir);
  315 
  316    if (displayhelp) {
  317       list_for_each_entry(struct diskstat_info, dsi, &gdiskstat_list, list) {
  318          char line[32];
  319          snprintf(line, sizeof(line), "    diskstat-%s-%s",
  320                  dsi->mode == DISKSTAT_RD ? "rd" :
  321                  dsi->mode == DISKSTAT_WR ? "wr" : "undefined", dsi->name);
  322 
  323          puts(line);
  324       }
  325    }
  326    mtx_unlock(&gdiskstat_mutex);
  327 
  328    return gdiskstat_count;
  329 }
  330 
  331 #endif /* HAVE_GALLIUM_EXTRA_HUD */