/* * This file is part of Cockpit. * * Copyright (C) 2014 Red Hat, Inc. * * Cockpit is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * Cockpit is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Cockpit; If not, see . */ #include "config.h" #include "cockpitblocksamples.h" #include #include void cockpit_block_samples (CockpitSamples *samples) { gchar *contents = NULL; gsize len; GError *error = NULL; gchar **lines = NULL; guint n; if (!g_file_get_contents ("/proc/diskstats", &contents, &len, &error)) { g_message ("error loading contents /proc/diskstats: %s", error->message); goto out; } lines = g_strsplit (contents, "\n", -1); for (n = 0; lines != NULL && lines[n] != NULL; n++) { const gchar *line = lines[n]; guint num_parsed; gint dev_major, dev_minor; gchar dev_name[128]; guint64 num_reads, num_reads_merged, num_sectors_read, num_msec_reading; guint64 num_writes, num_writes_merged, num_sectors_written, num_msec_writing; guint64 num_io_in_progress, num_msec_doing_io, weighted_num_msec_doing_io; if (strlen (line) == 0) continue; /* From http://www.kernel.org/doc/Documentation/iostats.txt * * Field 1 -- # of reads completed * This is the total number of reads completed successfully. * Field 2 -- # of reads merged, field 6 -- # of writes merged * Reads and writes which are adjacent to each other may be merged for * efficiency. Thus two 4K reads may become one 8K read before it is * ultimately handed to the disk, and so it will be counted (and queued) * as only one I/O. This field lets you know how often this was done. * Field 3 -- # of sectors read * This is the total number of sectors read successfully. * Field 4 -- # of milliseconds spent reading * This is the total number of milliseconds spent by all reads (as * measured from __make_request() to end_that_request_last()). * Field 5 -- # of writes completed * This is the total number of writes completed successfully. * Field 7 -- # of sectors written * This is the total number of sectors written successfully. * Field 8 -- # of milliseconds spent writing * This is the total number of milliseconds spent by all writes (as * measured from __make_request() to end_that_request_last()). * Field 9 -- # of I/Os currently in progress * The only field that should go to zero. Incremented as requests are * given to appropriate struct request_queue and decremented as they finish. * Field 10 -- # of milliseconds spent doing I/Os * This field increases so long as field 9 is nonzero. * Field 11 -- weighted # of milliseconds spent doing I/Os * This field is incremented at each I/O start, I/O completion, I/O * merge, or read of these stats by the number of I/Os in progress * (field 9) times the number of milliseconds spent doing I/O since the * last update of this field. This can provide an easy measure of both * I/O completion time and the backlog that may be accumulating. */ num_parsed = sscanf (line, "%d %d %127s" " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, &dev_major, &dev_minor, dev_name, &num_reads, &num_reads_merged, &num_sectors_read, &num_msec_reading, &num_writes, &num_writes_merged, &num_sectors_written, &num_msec_writing, &num_io_in_progress, &num_msec_doing_io, &weighted_num_msec_doing_io); if (num_parsed != 14) { g_message ("error parsing line %d of file /proc/diskstats (num_parsed = %d): %s", n, num_parsed, line); continue; } cockpit_samples_sample (samples, "block.device.read", dev_name, num_sectors_read * 512); cockpit_samples_sample (samples, "block.device.written", dev_name, num_sectors_written * 512); } out: g_clear_error (&error); g_strfreev (lines); g_free (contents); }