1 /**************************************************************************
3 * Copyright (C) 2016 Steven Toth <stoth@kernellabs.com>
4 * Copyright (C) 2016 Zodiac Inflight Innovations
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:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
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.
27 **************************************************************************/
29 #ifdef HAVE_GALLIUM_EXTRA_HUD
31 /* Purpose: Reading /sys/block/<*>/stat MB/s read/write throughput per second,
32 * displaying on the HUD.
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"
47 #include <sys/types.h>
66 uint64_t time_in_queue
;
71 struct list_head list
;
72 int mode
; /* DISKSTAT_RD, DISKSTAT_WR */
73 char name
[64]; /* EG. sda5 */
75 char sysfs_filename
[128];
77 struct stat_s last_stat
;
80 /* TODO: We don't handle dynamic block device / partition
82 * Static globals specific to this HUD category.
84 static int gdiskstat_count
= 0;
85 static struct list_head gdiskstat_list
;
86 static mtx_t gdiskstat_mutex
= _MTX_INITIALIZER_NP
;
88 static struct diskstat_info
*
89 find_dsi_by_name(const char *n
, int mode
)
91 list_for_each_entry(struct diskstat_info
, dsi
, &gdiskstat_list
, list
) {
92 if (dsi
->mode
!= mode
)
94 if (strcasecmp(dsi
->name
, n
) == 0)
101 get_file_values(const char *fn
, struct stat_s
*s
)
104 FILE *fh
= fopen(fn
, "r");
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
,
121 query_dsi_load(struct hud_graph
*gr
, struct pipe_context
*pipe
)
123 /* The framework calls us periodically, compensate for the
124 * calling interval accordingly when reporting per second.
126 struct diskstat_info
*dsi
= gr
->query_data
;
127 uint64_t now
= os_time_get();
129 if (dsi
->last_time
) {
130 if (dsi
->last_time
+ gr
->pane
->period
<= now
) {
132 if (get_file_values(dsi
->sysfs_filename
, &stat
) < 0)
140 dsi
->last_stat
.r_sectors
) * 512) /
141 (((float) gr
->pane
->period
/ 1000) / 1000);
146 dsi
->last_stat
.w_sectors
) * 512) /
147 (((float) gr
->pane
->period
/ 1000) / 1000);
151 hud_graph_add_value(gr
, (uint64_t) val
);
152 dsi
->last_stat
= stat
;
153 dsi
->last_time
= now
;
161 get_file_values(dsi
->sysfs_filename
, &dsi
->last_stat
);
164 dsi
->last_time
= now
;
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.
175 hud_diskstat_graph_install(struct hud_pane
*pane
, const char *dev_name
,
178 struct hud_graph
*gr
;
179 struct diskstat_info
*dsi
;
181 int num_devs
= hud_get_num_disks(0);
185 dsi
= find_dsi_by_name(dev_name
, mode
);
189 gr
= CALLOC_STRUCT(hud_graph
);
194 if (dsi
->mode
== DISKSTAT_RD
) {
195 snprintf(gr
->name
, sizeof(gr
->name
), "%s-Read-MB/s", dsi
->name
);
197 else if (dsi
->mode
== DISKSTAT_WR
) {
198 snprintf(gr
->name
, sizeof(gr
->name
), "%s-Write-MB/s", dsi
->name
);
205 gr
->query_data
= dsi
;
206 gr
->query_new_value
= query_dsi_load
;
208 hud_pane_add_graph(pane
, gr
);
209 hud_pane_set_max_value(pane
, 100);
213 add_object_part(const char *basename
, const char *name
, int objmode
)
215 struct diskstat_info
*dsi
= CALLOC_STRUCT(diskstat_info
);
217 snprintf(dsi
->name
, sizeof(dsi
->name
), "%s", name
);
218 snprintf(dsi
->sysfs_filename
, sizeof(dsi
->sysfs_filename
), "%s/%s/stat",
221 list_addtail(&dsi
->list
, &gdiskstat_list
);
226 add_object(const char *basename
, const char *name
, int objmode
)
228 struct diskstat_info
*dsi
= CALLOC_STRUCT(diskstat_info
);
230 snprintf(dsi
->name
, sizeof(dsi
->name
), "%s", name
);
231 snprintf(dsi
->sysfs_filename
, sizeof(dsi
->sysfs_filename
), "%s/stat",
234 list_addtail(&dsi
->list
, &gdiskstat_list
);
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.
245 hud_get_num_disks(bool displayhelp
)
248 struct stat stat_buf
;
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
;
258 /* Scan /sys/block, for every object type we support, create and
259 * persist an object to represent its different statistics.
261 list_inithead(&gdiskstat_list
);
262 DIR *dir
= opendir("/sys/block/");
264 mtx_unlock(&gdiskstat_mutex
);
268 while ((dp
= readdir(dir
)) != NULL
) {
270 /* Avoid 'lo' and '..' and '.' */
271 if (strlen(dp
->d_name
) <= 2)
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)
280 if (!S_ISREG(stat_buf
.st_mode
))
281 continue; /* Not a regular file */
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
);
287 /* Add any partitions */
288 struct dirent
*dpart
;
289 DIR *pdir
= opendir(basename
);
291 mtx_unlock(&gdiskstat_mutex
);
296 while ((dpart
= readdir(pdir
)) != NULL
) {
297 /* Avoid 'lo' and '..' and '.' */
298 if (strlen(dpart
->d_name
) <= 2)
302 snprintf(p
, sizeof(p
), "%s/%s/stat", basename
, dpart
->d_name
);
303 if (stat(p
, &stat_buf
) < 0)
306 if (!S_ISREG(stat_buf
.st_mode
))
307 continue; /* Not a regular file */
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
);
317 list_for_each_entry(struct diskstat_info
, dsi
, &gdiskstat_list
, list
) {
319 snprintf(line
, sizeof(line
), " diskstat-%s-%s",
320 dsi
->mode
== DISKSTAT_RD
? "rd" :
321 dsi
->mode
== DISKSTAT_WR
? "wr" : "undefined", dsi
->name
);
326 mtx_unlock(&gdiskstat_mutex
);
328 return gdiskstat_count
;
331 #endif /* HAVE_GALLIUM_EXTRA_HUD */