From ac49426ee506384ee66b3ba1ef4349216aad82ea Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Wed, 10 Jul 2019 14:22:51 -0400 Subject: multiload: Use /proc/diskstats for NVMe drives Since glibtop does not support NVMe drives, we rely on /proc/diskstats to tell use load information for NVMe drives. If diskstats is not present it returns to glibtop as a fallback. --- multiload/linux-proc.c | 77 ++++++++++++++++------ .../org.mate.panel.applet.multiload.gschema.xml.in | 4 ++ multiload/properties.c | 45 ++++++++++++- 3 files changed, 106 insertions(+), 20 deletions(-) diff --git a/multiload/linux-proc.c b/multiload/linux-proc.c index c661dd8f..355fe040 100644 --- a/multiload/linux-proc.c +++ b/multiload/linux-proc.c @@ -100,14 +100,14 @@ GetDiskLoad (int Maximum, int data [3], LoadGraph *g) static guint64 lastread = 0, lastwrite = 0; static AutoScaler scaler; - glibtop_mountlist mountlist; - glibtop_mountentry *mountentries; guint i; int max; + gboolean nvme_diskstats; guint64 read, write; guint64 readdiff, writediff; + nvme_diskstats = g_settings_get_boolean (g->multiload->settings, "diskload-nvme-diskstats"); if(first_call) { @@ -116,32 +116,71 @@ GetDiskLoad (int Maximum, int data [3], LoadGraph *g) read = write = 0; - mountentries = glibtop_get_mountlist (&mountlist, FALSE); - - for (i = 0; i < mountlist.number; i++) + if (nvme_diskstats) { - struct statvfs statresult; - glibtop_fsusage fsusage; + FILE *fdr; + char line[255]; + guint64 s_read, s_write; - if (strstr (mountentries[i].devname, "/dev/") == NULL) - continue; + fdr = fopen("/proc/diskstats", "r"); + if (!fdr) + { + g_settings_set_boolean (g->multiload->settings, "diskload-nvme-diskstats", FALSE); + return; + } - if (strstr (mountentries[i].mountdir, "/media/") != NULL) - continue; + while (fgets(line, 255, fdr)) + { + /* Match main device, rather than individual partitions (e.g. nvme0n1) */ + if (!g_regex_match_simple("\\snvme\\d+\\w+\\d+\\s", line, 0, 0)) + { + continue; + } + + /* + 6 - sectors read + 10 - sectors written + */ + if (sscanf(line, "%*d %*d %*s %*d %*d %ld %*d %*d %*d %ld", &s_read, &s_write) == 2) + { + read += 512 * s_read; + write += 512 * s_write; + } + } + fclose(fdr); + } + else + { + glibtop_mountlist mountlist; + glibtop_mountentry *mountentries; + + mountentries = glibtop_get_mountlist (&mountlist, FALSE); - if (statvfs (mountentries[i].mountdir, &statresult) < 0) + for (i = 0; i < mountlist.number; i++) { - g_debug ("Failed to get statistics for mount entry: %s. Reason: %s. Skipping entry.", - mountentries[i].mountdir, strerror(errno)); - continue; + struct statvfs statresult; + glibtop_fsusage fsusage; + + if (strstr (mountentries[i].devname, "/dev/") == NULL) + continue; + + if (strstr (mountentries[i].mountdir, "/media/") != NULL) + continue; + + if (statvfs (mountentries[i].mountdir, &statresult) < 0) + { + g_debug ("Failed to get statistics for mount entry: %s. Reason: %s. Skipping entry.", + mountentries[i].mountdir, strerror(errno)); + continue; + } + + glibtop_get_fsusage(&fsusage, mountentries[i].mountdir); + read += fsusage.read; write += fsusage.write; } - glibtop_get_fsusage(&fsusage, mountentries[i].mountdir); - read += fsusage.read; write += fsusage.write; + g_free(mountentries); } - g_free(mountentries); - readdiff = read - lastread; writediff = write - lastwrite; diff --git a/multiload/org.mate.panel.applet.multiload.gschema.xml.in b/multiload/org.mate.panel.applet.multiload.gschema.xml.in index d0d27a32..53bf8c76 100644 --- a/multiload/org.mate.panel.applet.multiload.gschema.xml.in +++ b/multiload/org.mate.panel.applet.multiload.gschema.xml.in @@ -141,6 +141,10 @@ '#000000' Background color for disk load graph + + false + Uses /proc/diskstats to determine NVMe disk load + 'mate-system-monitor.desktop' The desktop description file to execute as the system monitor diff --git a/multiload/properties.c b/multiload/properties.c index f78c3447..de4c060b 100644 --- a/multiload/properties.c +++ b/multiload/properties.c @@ -324,6 +324,49 @@ add_color_selector(GtkWidget *page, gchar *name, gchar *key, MultiloadApplet *ma return; } +/* save the checkbox option to gsettings and apply it on the applet */ +static void +checkbox_toggled_cb(GtkCheckButton *checkbox, gchar *key) +{ + MultiloadApplet *ma; + gboolean option; + + ma = g_object_get_data (G_OBJECT (checkbox), "MultiloadApplet"); + + option = g_settings_get_boolean(ma->settings, key); + g_settings_set_boolean(ma->settings, key, !option); + + return; +} + +/* adds checkbox option */ +static void +add_checkbox(GtkWidget *page, gchar *name, gchar *key, MultiloadApplet *ma) +{ + GtkWidget *vbox; + GtkWidget *checkbox; + gboolean option; + + option = g_settings_get_boolean (ma->settings, key); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + checkbox = gtk_check_button_new_with_mnemonic (name); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(checkbox), option); + + gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 0); + + gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0); + + g_object_set_data (G_OBJECT (checkbox), "MultiloadApplet", ma); + + g_signal_connect(G_OBJECT(checkbox), "toggled", G_CALLBACK(checkbox_toggled_cb), key); + + if ( ! g_settings_is_writable (ma->settings, key)) + hard_set_sensitive (vbox, FALSE); + + return; +} + /* creates the properties dialog using up-to-the-minute info from gsettings */ static void fill_properties(GtkWidget *dialog, MultiloadApplet *ma) @@ -638,6 +681,7 @@ fill_properties(GtkWidget *dialog, MultiloadApplet *ma) add_color_selector (page, _("_Read"), "diskload-color0", ma); add_color_selector (page, _("_Write"), "diskload-color1", ma); add_color_selector (page, _("_Background"), "diskload-color2", ma); + add_checkbox(page, _("Use diskstats for NVMe"), "diskload-nvme-diskstats", ma); title = g_strconcat ("", _("Network speed thresholds"), "", NULL); label = gtk_label_new (title); @@ -667,7 +711,6 @@ fill_properties(GtkWidget *dialog, MultiloadApplet *ma) label_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - orient = mate_panel_applet_get_orient(ma->applet); label_text = g_strdup(_("Threshold 1: ")); label = gtk_label_new_with_mnemonic(label_text); gtk_label_set_xalign (GTK_LABEL (label), 0.0f); -- cgit v1.2.1