[gnome-disk-utility/new-ui] Add a benchmark dialog a show WWN, Write-Cache and Rotational Rate
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/new-ui] Add a benchmark dialog a show WWN, Write-Cache and Rotational Rate
- Date: Wed, 25 Nov 2009 18:03:19 +0000 (UTC)
commit 721d363455dbbcc730256f8600a33d333b143c69
Author: David Zeuthen <davidz redhat com>
Date: Wed Nov 25 13:02:28 2009 -0500
Add a benchmark dialog a show WWN, Write-Cache and Rotational Rate
src/gdu-gtk/Makefile.am | 2 +
src/gdu-gtk/gdu-drive-benchmark-dialog.c | 1337 +++++++++++++++++++++++++++
src/gdu-gtk/gdu-drive-benchmark-dialog.h | 63 ++
src/gdu-gtk/gdu-gtk-types.h | 1 +
src/gdu-gtk/gdu-gtk.h | 1 +
src/gdu/gdu-callbacks.h | 7 +
src/gdu/gdu-device.c | 82 ++
src/gdu/gdu-device.h | 11 +
src/gdu/gdu-util.c | 8 +-
src/palimpsest/gdu-section-drive.c | 87 ++-
src/palimpsest/gdu-section-drive.h | 7 +-
src/palimpsest/gdu-section-linux-md-drive.c | 15 +
12 files changed, 1612 insertions(+), 9 deletions(-)
---
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 19c9403..bdff6a7 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -53,6 +53,7 @@ libgdu_gtkinclude_HEADERS = \
gdu-disk-selection-widget.h \
gdu-add-component-linux-md-dialog.h \
gdu-edit-linux-md-dialog.h \
+ gdu-drive-benchmark-dialog.h \
$(NULL)
libgdu_gtk_la_SOURCES = \
@@ -83,6 +84,7 @@ libgdu_gtk_la_SOURCES = \
gdu-disk-selection-widget.h gdu-disk-selection-widget.c \
gdu-add-component-linux-md-dialog.h gdu-add-component-linux-md-dialog.c \
gdu-edit-linux-md-dialog.h gdu-edit-linux-md-dialog.c \
+ gdu-drive-benchmark-dialog.h gdu-drive-benchmark-dialog.c \
$(NULL)
libgdu_gtk_la_CPPFLAGS = \
diff --git a/src/gdu-gtk/gdu-drive-benchmark-dialog.c b/src/gdu-gtk/gdu-drive-benchmark-dialog.c
new file mode 100644
index 0000000..8080814
--- /dev/null
+++ b/src/gdu-gtk/gdu-drive-benchmark-dialog.c
@@ -0,0 +1,1337 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-drive-benchmark-dialog.c
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library 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 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <dbus/dbus-glib.h>
+
+#include "gdu-time-label.h"
+#include "gdu-drive-benchmark-dialog.h"
+#include "gdu-spinner.h"
+#include "gdu-details-table.h"
+#include "gdu-details-element.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* gah, omgwtf, dbus-glib - this will be much nicer when we switch to GVariant */
+
+/* For now we store the benchmark data in $HOME/.cache - once DKD
+ * grows a message subsystem (e.g. a database storing time-stamped
+ * messages/events on a per device basis) we can switch to using
+ * that.
+ */
+
+typedef struct {
+ guint64 offset;
+ gdouble value;
+} BenchmarkPoint;
+
+typedef struct {
+ guint64 time_collected;
+ guint64 disk_size;
+
+ GArray *read_transfer_rate_samples;
+ GArray *write_transfer_rate_samples;
+ GArray *access_time_samples;
+} BenchmarkData;
+
+static void
+benchmark_get_max_min_avg (GArray *array,
+ gdouble *out_max,
+ gdouble *out_min,
+ gdouble *out_avg)
+{
+ guint n;
+ gdouble max;
+ gdouble min;
+ gdouble avg;
+ gdouble sum;
+
+ if (array->len == 0) {
+ max = 0;
+ min = 0;
+ avg = 0;
+ goto out;
+ }
+ max = -G_MAXDOUBLE;
+ min = G_MAXDOUBLE;
+ sum = 0;
+
+ for (n = 0; n < array->len; n++) {
+ BenchmarkPoint *point = &g_array_index (array, BenchmarkPoint, n);
+ if (point->value > max)
+ max = point->value;
+ if (point->value < min)
+ min = point->value;
+ sum += point->value;
+ }
+ avg = sum / array->len;
+
+ out:
+ if (out_max != NULL)
+ *out_max = max;
+ if (out_min != NULL)
+ *out_min = min;
+ if (out_avg != NULL)
+ *out_avg = avg;
+}
+
+static void
+benchmark_data_free (BenchmarkData *data)
+{
+ g_array_unref (data->read_transfer_rate_samples);
+ g_array_unref (data->write_transfer_rate_samples);
+ g_array_unref (data->access_time_samples);
+ g_free (data);
+}
+
+G_GNUC_UNUSED static void
+benchmark_data_print (BenchmarkData *data)
+{
+ gchar time_buf[256];
+ struct tm *time_tm;
+ time_t t;
+ gchar *s;
+ guint n;
+
+ t = data->time_collected;
+ time_tm = localtime (&t);
+ strftime (time_buf, sizeof time_buf, "%c", time_tm);
+
+ g_print ("Collected at: %s\n", time_buf);
+ s = gdu_util_get_size_for_display (data->disk_size, FALSE, TRUE);
+ g_print ("Disk size: %s\n", s);
+ g_free (s);
+ g_print ("Read transfer rate:\n");
+ for (n = 0; n < data->read_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->read_transfer_rate_samples, BenchmarkPoint, n);
+ g_print (" Position %3d%% -> %3.2f MB/s\n",
+ (gint) (100.0 * point->offset / data->disk_size),
+ point->value / (1000.0 * 1000.0));
+ }
+ g_print ("Write transfer rate:\n");
+ for (n = 0; n < data->write_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->write_transfer_rate_samples, BenchmarkPoint, n);
+ g_print (" Position %3d%% -> %3.2f MB/s\n",
+ (gint) (100.0 * point->offset / data->disk_size),
+ point->value / (1000.0 * 1000.0));
+ }
+ g_print ("Access times:\n");
+ for (n = 0; n < data->access_time_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->access_time_samples, BenchmarkPoint, n);
+ g_print (" Position %3d%% -> %3.2f ms\n",
+ (gint) (100.0 * point->offset / data->disk_size),
+ point->value * 1000.0);
+ }
+}
+
+static void
+benchmark_convert (GPtrArray *in,
+ GArray *out)
+{
+ guint n;
+
+ GType pair_type;
+
+ pair_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT64, G_TYPE_DOUBLE, G_TYPE_INVALID);
+
+ for (n = 0; n < in->len; n++) {
+ GValue elem = {0};
+ BenchmarkPoint point;
+
+ g_value_init (&elem, pair_type);
+ g_value_set_static_boxed (&elem, in->pdata[n]);
+
+ dbus_g_type_struct_get (&elem,
+ 0, &(point.offset),
+ 1, &(point.value),
+ G_MAXUINT);
+ g_array_append_val (out, point);
+ }
+}
+
+static BenchmarkData *
+benchmark_data_from_dbus (GduDevice *device,
+ GPtrArray *read_transfer_rate_results,
+ GPtrArray *write_transfer_rate_results,
+ GPtrArray *access_time_results)
+{
+ BenchmarkData *data;
+
+ data = g_new0 (BenchmarkData, 1);
+ data->time_collected = time (NULL);
+ data->disk_size = gdu_device_get_size (device);
+ data->read_transfer_rate_samples = g_array_sized_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint),
+ read_transfer_rate_results->len);
+ data->write_transfer_rate_samples = g_array_sized_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint),
+ write_transfer_rate_results->len);
+ data->access_time_samples = g_array_sized_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint),
+ access_time_results->len);
+
+ benchmark_convert (read_transfer_rate_results,
+ data->read_transfer_rate_samples);
+ benchmark_convert (write_transfer_rate_results,
+ data->write_transfer_rate_samples);
+ benchmark_convert (access_time_results,
+ data->access_time_samples);
+
+ return data;
+}
+
+static BenchmarkData *
+benchmark_data_load (GduDevice *device,
+ GError **error)
+{
+ BenchmarkData *data;
+ gchar *filename;
+ gchar *s;
+ gchar *s2;
+ gchar *contents;
+ gchar **lines;
+ guint n;
+
+ contents = NULL;
+ lines = NULL;
+
+ data = g_new0 (BenchmarkData, 1);
+ data->time_collected = time (NULL);
+ data->disk_size = gdu_device_get_size (device);
+ data->read_transfer_rate_samples = g_array_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint));
+ data->write_transfer_rate_samples = g_array_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint));
+ data->access_time_samples = g_array_new (FALSE,
+ FALSE,
+ sizeof (BenchmarkPoint));
+
+
+ s = g_strdup_printf ("%s/gnome-disk-utility/drive-benchmark",
+ g_get_user_cache_dir ());
+ s2 = g_strdup_printf ("%s-%s-%s-%s",
+ gdu_device_drive_get_vendor (device),
+ gdu_device_drive_get_model (device),
+ gdu_device_drive_get_revision (device),
+ gdu_device_drive_get_serial (device));
+ filename = g_strdup_printf ("%s/%s",
+ s, s2);
+ g_free (s);
+ g_free (s2);
+
+ if (!g_file_get_contents (filename,
+ &contents,
+ NULL,
+ error)) {
+ benchmark_data_free (data);
+ data = NULL;
+ goto out;
+ }
+
+ lines = g_strsplit (contents, "\n", 0);
+ for (n = 0; lines != NULL && lines[n] != NULL; n++) {
+ const gchar *line = lines[n];
+ gchar **samples;
+ guint m;
+
+ if (sscanf (line, "time_collected=%" G_GUINT64_FORMAT,
+ &(data->time_collected)) == 1) {
+ ;
+ } else if (sscanf (line, "disk_size=%" G_GUINT64_FORMAT,
+ &(data->disk_size)) == 1) {
+ ;
+ } else if (g_str_has_prefix (line, "read_transfer_rate_samples=")) {
+ samples = g_strsplit (line + sizeof "read_transfer_rate_samples=" - 1, ":", 0);
+ for (m = 0; samples != NULL && samples[m] != NULL; m++) {
+ const gchar *sample = samples[m];
+ BenchmarkPoint point;
+
+ if (sscanf (sample, "%" G_GUINT64_FORMAT ";%lf",
+ &(point.offset),
+ &(point.value)) != 2) {
+ g_set_error (error,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Bogus read_transfer_rate sample %d `%s'",
+ m,
+ sample);
+ benchmark_data_free (data);
+ data = NULL;
+ goto out;
+ }
+ g_array_append_val (data->read_transfer_rate_samples, point);
+ }
+ g_strfreev (samples);
+
+ } else if (g_str_has_prefix (line, "write_transfer_rate_samples=")) {
+ samples = g_strsplit (line + sizeof "write_transfer_rate_samples=" - 1, ":", 0);
+ for (m = 0; samples != NULL && samples[m] != NULL; m++) {
+ const gchar *sample = samples[m];
+ BenchmarkPoint point;
+
+ if (sscanf (sample, "%" G_GUINT64_FORMAT ";%lf",
+ &(point.offset),
+ &(point.value)) != 2) {
+ g_set_error (error,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Bogus write_transfer_rate sample %d `%s'",
+ m,
+ sample);
+ benchmark_data_free (data);
+ data = NULL;
+ goto out;
+ }
+ g_array_append_val (data->write_transfer_rate_samples, point);
+ }
+ g_strfreev (samples);
+
+ } else if (g_str_has_prefix (line, "access_time_samples=")) {
+ samples = g_strsplit (line + sizeof "access_time_samples=" - 1, ":", 0);
+ for (m = 0; samples != NULL && samples[m] != NULL; m++) {
+ const gchar *sample = samples[m];
+ BenchmarkPoint point;
+
+ if (sscanf (sample, "%" G_GUINT64_FORMAT ";%lf",
+ &(point.offset),
+ &(point.value)) != 2) {
+ g_set_error (error,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Bogus access_time sample %d `%s'",
+ m,
+ sample);
+ benchmark_data_free (data);
+ data = NULL;
+ goto out;
+ }
+ g_array_append_val (data->access_time_samples, point);
+ }
+ g_strfreev (samples);
+ } else if (strlen (line) > 0) {
+ g_set_error (error,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Unable to parse line `%s'", line);
+ benchmark_data_free (data);
+ data = NULL;
+ goto out;
+ }
+ }
+
+ out:
+ g_free (filename);
+ g_free (contents);
+ g_strfreev (lines);
+ return data;
+}
+
+static gboolean
+benchmark_data_save (BenchmarkData *data,
+ GduDevice *device,
+ GError **error)
+{
+ gboolean ret;
+ gchar *filename;
+ GString *str;
+ gchar *s;
+ gchar *s2;
+ guint n;
+
+ str = NULL;
+ filename = NULL;
+ ret = FALSE;
+
+ s = g_strdup_printf ("%s/gnome-disk-utility/drive-benchmark",
+ g_get_user_cache_dir ());
+ if (g_mkdir_with_parents (s, 0755) != 0) {
+ g_set_error (error,
+ GDU_ERROR,
+ GDU_ERROR_FAILED,
+ "Error creating directory %s: %m",
+ s);
+ g_free (s);
+ goto out;
+ }
+
+ s2 = g_strdup_printf ("%s-%s-%s-%s",
+ gdu_device_drive_get_vendor (device),
+ gdu_device_drive_get_model (device),
+ gdu_device_drive_get_revision (device),
+ gdu_device_drive_get_serial (device));
+ filename = g_strdup_printf ("%s/%s",
+ s, s2);
+ g_free (s);
+ g_free (s2);
+
+ str = g_string_new (NULL);
+ g_string_append_printf (str, "time_collected=%" G_GUINT64_FORMAT "\n", data->time_collected);
+ g_string_append_printf (str, "disk_size=%" G_GUINT64_FORMAT "\n", data->disk_size);
+
+ g_string_append (str, "read_transfer_rate_samples=");
+ for (n = 0; n < data->read_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->read_transfer_rate_samples, BenchmarkPoint, n);
+ if (n > 0)
+ g_string_append_c (str, ':');
+ g_string_append_printf (str,
+ "%" G_GUINT64_FORMAT ";%f",
+ point->offset,
+ point->value);
+ }
+ g_string_append_c (str, '\n');
+
+ g_string_append (str, "write_transfer_rate_samples=");
+ for (n = 0; n < data->write_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->write_transfer_rate_samples, BenchmarkPoint, n);
+ if (n > 0)
+ g_string_append_c (str, ':');
+ g_string_append_printf (str,
+ "%" G_GUINT64_FORMAT ";%f",
+ point->offset,
+ point->value);
+ }
+ g_string_append_c (str, '\n');
+
+ g_string_append (str, "access_time_samples=");
+ for (n = 0; n < data->access_time_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->access_time_samples, BenchmarkPoint, n);
+ if (n > 0)
+ g_string_append_c (str, ':');
+ g_string_append_printf (str,
+ "%" G_GUINT64_FORMAT ";%f",
+ point->offset,
+ point->value);
+ }
+ g_string_append_c (str, '\n');
+
+ if (!g_file_set_contents (filename,
+ str->str,
+ -1,
+ error))
+ goto out;
+
+ ret = TRUE;
+
+ out:
+ g_free (filename);
+ if (str != NULL)
+ g_string_free (str, TRUE);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct GduDriveBenchmarkDialogPrivate
+{
+ gulong device_changed_signal_handler_id;
+ gulong device_job_changed_signal_handler_id;
+
+ gboolean deleted;
+
+ GtkWidget *drawing_area;
+
+ BenchmarkData *benchmark_data;
+
+ /* elements for benchmark results */
+ GduDetailsElement *read_min_element;
+ GduDetailsElement *write_min_element;
+ GduDetailsElement *read_max_element;
+ GduDetailsElement *write_max_element;
+ GduDetailsElement *read_avg_element;
+ GduDetailsElement *write_avg_element;
+ GduDetailsElement *updated_element;
+ GduDetailsElement *access_avg_element;
+};
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+G_DEFINE_TYPE (GduDriveBenchmarkDialog, gdu_drive_benchmark_dialog, GDU_TYPE_DIALOG)
+
+static gdouble is_benchmarking (GduDriveBenchmarkDialog *dialog,
+ gdouble *out_progress);
+
+static gboolean on_drawing_area_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data);
+
+static void update_dialog (GduDriveBenchmarkDialog *dialog);
+static void on_device_changed (GduDevice *device, gpointer user_data);
+static void on_device_job_changed (GduDevice *device, gpointer user_data);
+
+static void
+gdu_drive_benchmark_dialog_finalize (GObject *object)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (object);
+
+ g_signal_handler_disconnect (gdu_dialog_get_device (GDU_DIALOG (dialog)), dialog->priv->device_changed_signal_handler_id);
+ g_signal_handler_disconnect (gdu_dialog_get_device (GDU_DIALOG (dialog)), dialog->priv->device_job_changed_signal_handler_id);
+
+ if (dialog->priv->benchmark_data != NULL) {
+ benchmark_data_free (dialog->priv->benchmark_data);
+ }
+
+ if (G_OBJECT_CLASS (gdu_drive_benchmark_dialog_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_drive_benchmark_dialog_parent_class)->finalize (object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+benchmark_cb (GduDevice *device,
+ GPtrArray *read_transfer_rate_results,
+ GPtrArray *write_transfer_rate_results,
+ GPtrArray *access_time_results,
+ GError *error,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+ GError *local_error;
+
+ if (error != NULL) {
+ if (!(error->domain == GDU_ERROR && error->code == GDU_ERROR_CANCELLED)) {
+ GtkWidget *error_dialog;
+ error_dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (dialog),
+ device,
+ _("Error benchmarking drive"),
+ error);
+ gtk_widget_show_all (error_dialog);
+ gtk_window_present (GTK_WINDOW (error_dialog));
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+ gtk_widget_destroy (error_dialog);
+ }
+ g_error_free (error);
+ goto out;
+ }
+
+ if (dialog->priv->benchmark_data != NULL) {
+ benchmark_data_free (dialog->priv->benchmark_data);
+ }
+ dialog->priv->benchmark_data = benchmark_data_from_dbus (device,
+ read_transfer_rate_results,
+ write_transfer_rate_results,
+ access_time_results);
+ g_ptr_array_unref (read_transfer_rate_results);
+ g_ptr_array_unref (write_transfer_rate_results);
+ g_ptr_array_unref (access_time_results);
+
+ /*benchmark_data_print (dialog->priv->benchmark_data);*/
+
+ local_error = NULL;
+ if (!benchmark_data_save (dialog->priv->benchmark_data, device, &local_error)) {
+ g_warning ("Error saving benchmark data: %s", local_error->message);
+ g_error_free (local_error);
+ }
+
+ out:
+ if (!dialog->priv->deleted) {
+ update_dialog (dialog);
+ gtk_widget_queue_draw_area (dialog->priv->drawing_area,
+ 0,
+ 0,
+ dialog->priv->drawing_area->allocation.width,
+ dialog->priv->drawing_area->allocation.height);
+ }
+ g_object_unref (dialog);
+}
+
+static void
+on_run_benchmark_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+ const gchar *options[1] = {NULL};
+
+ gdu_device_op_drive_benchmark (gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ FALSE,
+ options,
+ benchmark_cb,
+ g_object_ref (dialog));
+}
+
+static void
+on_run_write_benchmark_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+ const gchar *options[1] = {NULL};
+ GtkWidget *confirmation_dialog;
+ gint response;
+
+ confirmation_dialog = gdu_confirmation_dialog_new_for_drive (GTK_WINDOW (dialog),
+ gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ _("Are you sure you want to start a read/write benchmark?"),
+ _("_Benchmark"));
+ gtk_widget_show_all (confirmation_dialog);
+ response = gtk_dialog_run (GTK_DIALOG (confirmation_dialog));
+ gtk_widget_hide (confirmation_dialog);
+ if (response != GTK_RESPONSE_OK)
+ goto out;
+
+ gdu_device_op_drive_benchmark (gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ TRUE,
+ options,
+ benchmark_cb,
+ g_object_ref (dialog));
+
+ out:
+ gtk_widget_destroy (confirmation_dialog);
+}
+
+static gboolean
+on_delete_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+
+ dialog->priv->deleted = TRUE;
+ return FALSE; /* propagate further */
+}
+
+static void
+cancel_job_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ /* TODO: maybe show error dialog */
+ if (error != NULL)
+ g_error_free (error);
+}
+
+static void
+on_updated_element_activated (GduDetailsElement *element,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+
+ if (is_benchmarking (dialog, NULL)) {
+ gdu_device_op_cancel_job (gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ cancel_job_cb,
+ dialog);
+ }
+}
+
+static void
+gdu_drive_benchmark_dialog_constructed (GObject *object)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (object);
+ GtkWidget *content_area;
+ GtkWidget *align;
+ GtkWidget *vbox;
+ GtkWidget *vbox2;
+ GtkWidget *table;
+ GError *error;
+ GtkWidget *drawing_area;
+ GPtrArray *elements;
+ GduButtonElement *button_element;
+ GduDetailsElement *element;
+ gchar *s;
+ gchar *name;
+ gchar *vpd_name;
+
+ dialog->priv->device_changed_signal_handler_id = g_signal_connect (gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ "changed",
+ G_CALLBACK (on_device_changed),
+ dialog);
+ dialog->priv->device_job_changed_signal_handler_id = g_signal_connect (gdu_dialog_get_device (GDU_DIALOG (dialog)),
+ "job-changed",
+ G_CALLBACK (on_device_job_changed),
+ dialog);
+
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (on_delete_event),
+ dialog);
+
+ name = gdu_presentable_get_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+ vpd_name = gdu_presentable_get_vpd_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+ /* Translators: The title of the benchmark dialog.
+ * First %s is the name for the drive (e.g. "Fedora" or "1.0 TB Hard Disk")
+ * Second %s is the VPD name for the array (e.g. "158 GB RAID-0 Array" or "ATA WDC WD1001FALS-00J7B1").
+ */
+ s = g_strdup_printf ("%s (%s) â?? Benchmark", name, vpd_name);
+ gtk_window_set_title (GTK_WINDOW (dialog), s);
+ g_free (s);
+ g_free (vpd_name);
+ g_free (name);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 12, 12, 12, 12);
+ gtk_box_pack_start (GTK_BOX (content_area), align, TRUE, TRUE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_add (GTK_CONTAINER (align), vbox);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ drawing_area = gtk_drawing_area_new ();
+ dialog->priv->drawing_area = drawing_area;
+ gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+ g_signal_connect (drawing_area,
+ "expose-event",
+ G_CALLBACK (on_drawing_area_expose_event),
+ dialog);
+
+ /* set minimum size for the graph */
+ gtk_widget_set_size_request (drawing_area,
+ 400,
+ 300);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 36, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+ vbox2 = gtk_vbox_new (FALSE, 12);
+ gtk_container_add (GTK_CONTAINER (align), vbox2);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+ /* benchmark results */
+
+ element = gdu_details_element_new (_("Minimum Read Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->read_min_element = element;
+
+ element = gdu_details_element_new (_("Minimum Write Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->write_min_element = element;
+
+ element = gdu_details_element_new (_("Maximum Read Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->read_max_element = element;
+
+ element = gdu_details_element_new (_("Maximum Write Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->write_max_element = element;
+
+ element = gdu_details_element_new (_("Average Read Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->read_avg_element = element;
+
+ element = gdu_details_element_new (_("Average Write Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->write_avg_element = element;
+
+ element = gdu_details_element_new (_("Last Benchmark:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->updated_element = element;
+ g_signal_connect (element,
+ "activated",
+ G_CALLBACK (on_updated_element_activated),
+ dialog);
+
+ element = gdu_details_element_new (_("Average Access Time:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ dialog->priv->access_avg_element = element;
+
+ table = gdu_details_table_new (2, elements);
+ g_ptr_array_unref (elements);
+ gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+ button_element = gdu_button_element_new ("gtk-execute",
+ _("Start _Read-Only Benchmark"),
+ _("Measure read rate and access time"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_run_benchmark_clicked),
+ dialog);
+ g_ptr_array_add (elements, button_element);
+
+ button_element = gdu_button_element_new ("gtk-execute", /* TODO: better icon */
+ _("Start Read/_Write Benchmark"),
+ _("Measure read rate, write rate and access time"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_run_write_benchmark_clicked),
+ dialog);
+ g_ptr_array_add (elements, button_element);
+
+ table = gdu_button_table_new (2, elements);
+ g_ptr_array_unref (elements);
+ gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ /* load data from cache, if available */
+ error = NULL;
+ dialog->priv->benchmark_data = benchmark_data_load (gdu_dialog_get_device (GDU_DIALOG (dialog)), &error);
+ if (dialog->priv->benchmark_data == NULL) {
+ if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)) {
+ g_warning ("Unable to load existing benchmark results: %s", error->message);
+ }
+ g_error_free (error);
+ } else {
+ /*benchmark_data_print (dialog->priv->benchmark_data);*/
+ }
+
+ update_dialog (dialog);
+
+ if (G_OBJECT_CLASS (gdu_drive_benchmark_dialog_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_drive_benchmark_dialog_parent_class)->constructed (object);
+}
+
+static void
+gdu_drive_benchmark_dialog_class_init (GduDriveBenchmarkDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduDriveBenchmarkDialogPrivate));
+
+ object_class->constructed = gdu_drive_benchmark_dialog_constructed;
+ object_class->finalize = gdu_drive_benchmark_dialog_finalize;
+}
+
+static void
+gdu_drive_benchmark_dialog_init (GduDriveBenchmarkDialog *dialog)
+{
+ dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog, GDU_TYPE_DRIVE_BENCHMARK_DIALOG, GduDriveBenchmarkDialogPrivate);
+}
+
+GtkWidget *
+gdu_drive_benchmark_dialog_new (GtkWindow *parent,
+ GduDrive *drive)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_DRIVE_BENCHMARK_DIALOG,
+ "transient-for", parent,
+ "presentable", drive,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gdouble
+measure_width (cairo_t *cr,
+ const gchar *s)
+{
+ cairo_text_extents_t te;
+ cairo_text_extents (cr, s, &te);
+ return te.width;
+}
+
+static gdouble
+measure_height (cairo_t *cr,
+ const gchar *s)
+{
+ cairo_text_extents_t te;
+ cairo_text_extents (cr, s, &te);
+ return te.height;
+}
+
+static gboolean
+on_drawing_area_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+ cairo_t *cr;
+ gdouble width, height;
+ gdouble gx, gy, gw, gh;
+ guint n;
+ gdouble w, h;
+ gdouble x, y;
+ gdouble x_marker_height;
+ guint64 size;
+ gchar *s;
+ gdouble max_speed;
+ gdouble max_visible_speed;
+ gdouble speed_res;
+ gdouble max_time;
+ gdouble time_res;
+ gdouble max_visible_time;
+ gchar **y_left_markers;
+ gchar **y_right_markers;
+ guint num_y_markers;
+ GPtrArray *p;
+ GPtrArray *p2;
+
+ if (dialog->priv->benchmark_data == NULL) {
+ max_speed = 100 * 1000 * 1000;
+ max_time = 50 / 1000.0;
+ } else {
+ gdouble read_transfer_rate_max;
+ gdouble write_transfer_rate_max;
+ gdouble access_time_max;
+
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->read_transfer_rate_samples,
+ &read_transfer_rate_max,
+ NULL,
+ NULL);
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->write_transfer_rate_samples,
+ &write_transfer_rate_max,
+ NULL,
+ NULL);
+
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->access_time_samples,
+ &access_time_max,
+ NULL,
+ NULL);
+
+ max_speed = MAX (read_transfer_rate_max, write_transfer_rate_max);
+
+ max_time = access_time_max;
+ }
+
+ speed_res = (floor (((gdouble) max_speed) / (100 * 1000 * 1000)) + 1) * 1000 * 1000;
+ speed_res *= 10.0;
+ num_y_markers = (max_speed / speed_res) + 1;
+ max_visible_speed = speed_res * num_y_markers;
+
+ time_res = max_time / num_y_markers;
+ if (time_res < 0.0001) {
+ time_res = 0.0001;
+ } else if (time_res < 0.0005) {
+ time_res = 0.0005;
+ } else if (time_res < 0.001) {
+ time_res = 0.001;
+ } else if (time_res < 0.0025) {
+ time_res = 0.0025;
+ } else if (time_res < 0.005) {
+ time_res = 0.005;
+ } else {
+ time_res = ceil (((gdouble) time_res) / 0.005) * 0.005;
+ }
+ max_visible_time = time_res * num_y_markers;
+
+ /*g_debug ("max_visible_speed=%f, max_speed=%f, speed_res=%f", max_visible_speed, max_speed, speed_res);*/
+ /*g_debug ("max_visible_time=%f, max_time=%f, time_res=%f", max_visible_time, max_time, time_res);*/
+
+ p = g_ptr_array_new ();
+ p2 = g_ptr_array_new ();
+ for (n = 0; n <= num_y_markers; n++) {
+ gdouble val;
+
+ val = n * speed_res;
+ s = g_strdup_printf ("%d MB/s", (gint) (val / (1000 * 1000)));
+ g_ptr_array_add (p, s);
+
+ val = n * time_res;
+ s = g_strdup_printf ("%3g ms", val * 1000.0);
+ g_ptr_array_add (p2, s);
+ }
+ g_ptr_array_add (p, NULL);
+ g_ptr_array_add (p2, NULL);
+ y_left_markers = (gchar **) g_ptr_array_free (p, FALSE);
+ y_right_markers = (gchar **) g_ptr_array_free (p2, FALSE);
+
+ size = gdu_device_get_size (gdu_dialog_get_device (GDU_DIALOG (dialog)));
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ cr = gdk_cairo_create (widget->window);
+
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 8.0);
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);
+
+#if 0
+ cairo_set_source_rgb (cr, 0.25, 0.25, 0.25);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_set_line_width (cr, 0.0);
+ cairo_fill (cr);
+#endif
+
+ gx = 0;
+ gy = 0;
+ gw = width;
+ gh = height;
+
+ /* make horizontal and vertical room for x markers ("%d%%") */
+ w = ceil (measure_width (cr, "0%") / 2.0);
+ gx += w;
+ gw -= w;
+ w = ceil (measure_width (cr, "100%") / 2.0);
+ x_marker_height = ceil (measure_height (cr, "100%")) + 10;
+ gw -= w;
+ gh -= x_marker_height;
+
+ /* make horizontal room for left y markers ("%d MB/s") */
+ for (n = 0; n <= num_y_markers; n++) {
+ w = ceil (measure_width (cr, y_left_markers[n])) + 2 * 3;
+ if (w > gx) {
+ gdouble needed = w - gx;
+ gx += needed;
+ gw -= needed;
+ }
+ }
+ /* make vertical room for top-left y marker */
+ h = ceil (measure_height (cr, y_left_markers[num_y_markers]) / 2.0);
+ if (h > gy) {
+ gdouble needed = h - gy;
+ gy += needed;
+ gh -= needed;
+ }
+
+ /* make horizontal room for right y markers ("%d ms") */
+ for (n = 0; n <= num_y_markers; n++) {
+ w = ceil (measure_width (cr, y_right_markers[n])) + 2 * 3;
+ if (w > width - (gx + gw)) {
+ gdouble needed = w - (width - (gx + gw));
+ gw -= needed;
+ }
+ }
+ /* make vertical room for top-right y marker */
+ h = ceil (measure_height (cr, y_right_markers[num_y_markers]) / 2.0);
+ if (h > gy) {
+ gdouble needed = h - gy;
+ gy += needed;
+ gh -= needed;
+ }
+
+ /* draw x markers ("%d%%") + vertical grid */
+ for (n = 0; n <= 10; n++) {
+ cairo_text_extents_t te;
+
+ x = gx + ceil (n * gw / 10.0);
+ y = gy + gh + x_marker_height/2.0;
+
+ s = g_strdup_printf ("%d%%", n * 10);
+
+ cairo_text_extents (cr, s, &te);
+
+ cairo_move_to (cr,
+ x - te.x_bearing - te.width/2,
+ y - te.y_bearing - te.height/2);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_show_text (cr, s);
+
+ g_free (s);
+ }
+
+ /* draw left y markers ("%d MB/s") */
+ for (n = 0; n <= num_y_markers; n++) {
+ cairo_text_extents_t te;
+
+ x = gx/2.0;
+ y = gy + gh - gh * n / num_y_markers;
+
+ s = y_left_markers[n];
+ cairo_text_extents (cr, s, &te);
+ cairo_move_to (cr,
+ x - te.x_bearing - te.width/2,
+ y - te.y_bearing - te.height/2);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_show_text (cr, s);
+ }
+
+ /* draw right y markers ("%d ms") */
+ for (n = 0; n <= num_y_markers; n++) {
+ cairo_text_extents_t te;
+
+ x = gx + gw + (width - (gx + gw))/2.0;
+ y = gy + gh - gh * n / num_y_markers;
+
+ s = y_right_markers[n];
+ cairo_text_extents (cr, s, &te);
+ cairo_move_to (cr,
+ x - te.x_bearing - te.width/2,
+ y - te.y_bearing - te.height/2);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_show_text (cr, s);
+ }
+
+ /* fill graph area */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, gx + 0.5, gy + 0.5, gw, gh);
+ cairo_fill_preserve (cr);
+ /* grid - first a rect */
+ cairo_set_source_rgba (cr, 0, 0, 0, 0.25);
+ cairo_set_line_width (cr, 1.0);
+ /* rect - also clip to rect for all future drawing operations */
+ cairo_stroke_preserve (cr);
+ cairo_clip (cr);
+ /* vertical lines */
+ for (n = 1; n < 10; n++) {
+ x = gx + ceil (n * gw / 10.0);
+ cairo_move_to (cr, x + 0.5, gy + 0.5);
+ cairo_line_to (cr, x + 0.5, gy + gh + 0.5);
+ cairo_stroke (cr);
+ }
+ /* horizontal lines */
+ for (n = 1; n < num_y_markers; n++) {
+ y = gy + ceil (n * gh / num_y_markers);
+ cairo_move_to (cr, gx + 0.5, y + 0.5);
+ cairo_line_to (cr, gx + gw + 0.5, y + 0.5);
+ cairo_stroke (cr);
+ }
+
+ if (dialog->priv->benchmark_data != NULL) {
+ BenchmarkData *data = dialog->priv->benchmark_data;
+ gdouble prev_x;
+ gdouble prev_y;
+
+ /* draw access time dots + lines */
+ cairo_set_line_width (cr, 0.5);
+ for (n = 0; n < data->access_time_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->access_time_samples, BenchmarkPoint, n);
+
+ x = gx + gw * point->offset / data->disk_size;
+ y = gy + gh - gh * point->value / max_visible_time;
+
+ /*g_debug ("time = %f @ %f", point->value, x);*/
+
+ cairo_set_source_rgba (cr, 0.4, 1.0, 0.4, 0.5);
+ cairo_arc (cr, x, y, 1.5, 0, 2 * M_PI);
+ cairo_fill (cr);
+
+ if (n > 0) {
+ cairo_set_source_rgba (cr, 0.2, 0.5, 0.2, 0.10);
+ cairo_move_to (cr, prev_x, prev_y);
+ cairo_line_to (cr, x, y);
+ cairo_stroke (cr);
+ }
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ /* draw write transfer rate graph */
+ cairo_set_source_rgb (cr, 1.0, 0.5, 0.5);
+ cairo_set_line_width (cr, 2.0);
+ for (n = 0; n < data->write_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->write_transfer_rate_samples, BenchmarkPoint, n);
+
+ x = gx + gw * point->offset / data->disk_size;
+ y = gy + gh - gh * point->value / max_visible_speed;
+
+ if (n == 0)
+ cairo_move_to (cr, x, y);
+ else
+ cairo_line_to (cr, x, y);
+ }
+ cairo_stroke (cr);
+
+ /* draw read transfer rate graph */
+ cairo_set_source_rgb (cr, 0.5, 0.5, 1.0);
+ cairo_set_line_width (cr, 1.5);
+ for (n = 0; n < data->read_transfer_rate_samples->len; n++) {
+ BenchmarkPoint *point = &g_array_index (data->read_transfer_rate_samples, BenchmarkPoint, n);
+
+ x = gx + gw * point->offset / data->disk_size;
+ y = gy + gh - gh * point->value / max_visible_speed;
+
+ if (n == 0)
+ cairo_move_to (cr, x, y);
+ else
+ cairo_line_to (cr, x, y);
+ }
+ cairo_stroke (cr);
+
+ } else {
+ /* TODO: draw some text saying we don't have any data */
+ }
+
+
+
+ cairo_destroy (cr);
+
+ g_strfreev (y_left_markers);
+ g_strfreev (y_right_markers);
+
+ /* propagate event further */
+ return FALSE;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gdouble
+is_benchmarking (GduDriveBenchmarkDialog *dialog,
+ gdouble *out_progress)
+{
+ GduDevice *d;
+ gboolean ret;
+
+ ret = FALSE;
+
+ d = gdu_dialog_get_device (GDU_DIALOG (dialog));
+ if (!gdu_device_job_in_progress (d))
+ goto out;
+
+ if (g_strcmp0 (gdu_device_job_get_id (d), "DriveBenchmark") != 0)
+ goto out;
+
+ if (out_progress != NULL)
+ *out_progress = gdu_device_job_get_percentage (d);
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
+static void
+update_dialog (GduDriveBenchmarkDialog *dialog)
+{
+ gdouble progress;
+
+ if (dialog->priv->deleted)
+ goto out;
+
+ /* benchmark data */
+ if (dialog->priv->benchmark_data == NULL) {
+ gdu_details_element_set_text (dialog->priv->read_min_element, "â??");
+ gdu_details_element_set_text (dialog->priv->read_max_element, "â??");
+ gdu_details_element_set_text (dialog->priv->read_avg_element, "â??");
+ gdu_details_element_set_text (dialog->priv->write_min_element, "â??");
+ gdu_details_element_set_text (dialog->priv->write_max_element, "â??");
+ gdu_details_element_set_text (dialog->priv->write_avg_element, "â??");
+ /* Translators: This is used for the "Last Benchmark" element when we don't have benchmark data */
+ gdu_details_element_set_text (dialog->priv->updated_element, _("Never"));
+ gdu_details_element_set_text (dialog->priv->access_avg_element, "â??");
+ gdu_details_element_set_time (dialog->priv->updated_element, 0);
+ } else {
+ gdouble read_min;
+ gdouble read_max;
+ gdouble read_avg;
+ gdouble write_min;
+ gdouble write_max;
+ gdouble write_avg;
+ gdouble access_avg;
+ gchar *s;
+
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->read_transfer_rate_samples,
+ &read_max,
+ &read_min,
+ &read_avg);
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->write_transfer_rate_samples,
+ &write_max,
+ &write_min,
+ &write_avg);
+
+ benchmark_get_max_min_avg (dialog->priv->benchmark_data->access_time_samples,
+ NULL,
+ NULL,
+ &access_avg);
+
+ s = gdu_util_get_speed_for_display (read_min);
+ gdu_details_element_set_text (dialog->priv->read_min_element, s);
+ g_free (s);
+ s = gdu_util_get_speed_for_display (read_max);
+ gdu_details_element_set_text (dialog->priv->read_max_element, s);
+ g_free (s);
+ s = gdu_util_get_speed_for_display (read_avg);
+ gdu_details_element_set_text (dialog->priv->read_avg_element, s);
+ g_free (s);
+ if (dialog->priv->benchmark_data->write_transfer_rate_samples->len > 0) {
+ s = gdu_util_get_speed_for_display (write_min);
+ gdu_details_element_set_text (dialog->priv->write_min_element, s);
+ g_free (s);
+ s = gdu_util_get_speed_for_display (write_max);
+ gdu_details_element_set_text (dialog->priv->write_max_element, s);
+ g_free (s);
+ s = gdu_util_get_speed_for_display (write_avg);
+ gdu_details_element_set_text (dialog->priv->write_avg_element, s);
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (dialog->priv->write_min_element, "â??");
+ gdu_details_element_set_text (dialog->priv->write_max_element, "â??");
+ gdu_details_element_set_text (dialog->priv->write_avg_element, "â??");
+ }
+ s = g_strdup_printf ("%.1f ms", access_avg * 1000.0);
+ gdu_details_element_set_text (dialog->priv->access_avg_element, s);
+ g_free (s);
+
+ gdu_details_element_set_time (dialog->priv->updated_element,
+ dialog->priv->benchmark_data->time_collected);
+ }
+
+ if (is_benchmarking (dialog, &progress)) {
+ gdouble fraction;
+
+ fraction = progress / 100.0;
+ if (fraction < 0.0)
+ fraction = 0.0;
+ if (fraction > 1.0)
+ fraction = 1.0;
+ gdu_details_element_set_progress (dialog->priv->updated_element, fraction);
+ gdu_details_element_set_time (dialog->priv->updated_element, 0);
+ gdu_details_element_set_text (dialog->priv->updated_element, NULL);
+ gdu_details_element_set_action_text (dialog->priv->updated_element,
+ /* Translators: Text used in the hyperlink in the status
+ * table to cancel a self-test */
+ _("Cancel"));
+ gdu_details_element_set_action_tooltip (dialog->priv->updated_element,
+ /* Translators: Tooptip for the "Cancel" hyperlink */
+ _("Cancels the currently running benchmark"));
+ } else {
+ gdu_details_element_set_progress (dialog->priv->updated_element, -1.0);
+ gdu_details_element_set_text (dialog->priv->updated_element, NULL);
+ gdu_details_element_set_action_text (dialog->priv->updated_element, NULL);
+ gdu_details_element_set_action_tooltip (dialog->priv->updated_element, NULL);
+ }
+
+ out:
+ ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_device_changed (GduDevice *device,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+
+ if (!dialog->priv->deleted)
+ update_dialog (dialog);
+}
+
+static void
+on_device_job_changed (GduDevice *device,
+ gpointer user_data)
+{
+ GduDriveBenchmarkDialog *dialog = GDU_DRIVE_BENCHMARK_DIALOG (user_data);
+
+ if (!dialog->priv->deleted)
+ update_dialog (dialog);
+}
diff --git a/src/gdu-gtk/gdu-drive-benchmark-dialog.h b/src/gdu-gtk/gdu-drive-benchmark-dialog.h
new file mode 100644
index 0000000..27c721a
--- /dev/null
+++ b/src/gdu-gtk/gdu-drive-benchmark-dialog.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-drive-benchmark-dialog.h
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library 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 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GDU_GTK_INSIDE_GDU_GTK_H) && !defined (GDU_GTK_COMPILATION)
+#error "Only <gdu-gtk/gdu-gtk.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __GDU_DRIVE_BENCHMARK_DIALOG_H
+#define __GDU_DRIVE_BENCHMARK_DIALOG_H
+
+#include <gdu-gtk/gdu-gtk-types.h>
+#include <gdu-gtk/gdu-dialog.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_DRIVE_BENCHMARK_DIALOG gdu_drive_benchmark_dialog_get_type()
+#define GDU_DRIVE_BENCHMARK_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_DRIVE_BENCHMARK_DIALOG, GduDriveBenchmarkDialog))
+#define GDU_DRIVE_BENCHMARK_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDU_TYPE_DRIVE_BENCHMARK_DIALOG, GduDriveBenchmarkDialogClass))
+#define GDU_IS_DRIVE_BENCHMARK_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_DRIVE_BENCHMARK_DIALOG))
+#define GDU_IS_DRIVE_BENCHMARK_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDU_TYPE_DRIVE_BENCHMARK_DIALOG))
+#define GDU_DRIVE_BENCHMARK_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_DRIVE_BENCHMARK_DIALOG, GduDriveBenchmarkDialogClass))
+
+typedef struct GduDriveBenchmarkDialogClass GduDriveBenchmarkDialogClass;
+typedef struct GduDriveBenchmarkDialogPrivate GduDriveBenchmarkDialogPrivate;
+
+struct GduDriveBenchmarkDialog
+{
+ GduDialog parent;
+
+ /*< private >*/
+ GduDriveBenchmarkDialogPrivate *priv;
+};
+
+struct GduDriveBenchmarkDialogClass
+{
+ GduDialogClass parent_class;
+};
+
+GType gdu_drive_benchmark_dialog_get_type (void) G_GNUC_CONST;
+GtkWidget* gdu_drive_benchmark_dialog_new (GtkWindow *parent,
+ GduDrive *drive);
+
+G_END_DECLS
+
+#endif /* __GDU_DRIVE_BENCHMARK_DIALOG_H */
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index bb4639d..33e2948 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -60,6 +60,7 @@ typedef struct GduEditFilesystemDialog GduEditFilesystemDialog;
typedef struct GduDiskSelectionWidget GduDiskSelectionWidget;
typedef struct GduAddComponentLinuxMdDialog GduAddComponentLinuxMdDialog;
typedef struct GduEditLinuxMdDialog GduEditLinuxMdDialog;
+typedef struct GduDriveBenchmarkDialog GduDriveBenchmarkDialog;
G_END_DECLS
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index 3326628..0a6b445 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -52,6 +52,7 @@
#include <gdu-gtk/gdu-disk-selection-widget.h>
#include <gdu-gtk/gdu-add-component-linux-md-dialog.h>
#include <gdu-gtk/gdu-edit-linux-md-dialog.h>
+#include <gdu-gtk/gdu-drive-benchmark-dialog.h>
#undef __GDU_GTK_INSIDE_GDU_GTK_H
G_BEGIN_DECLS
diff --git a/src/gdu/gdu-callbacks.h b/src/gdu/gdu-callbacks.h
index 31bc81a..4217806 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -140,6 +140,13 @@ typedef void (*GduDeviceDrivePollMediaCompletedFunc) (GduDevice *device,
GError *error,
gpointer user_data);
+typedef void (*GduDeviceDriveBenchmarkCompletedFunc) (GduDevice *device,
+ GPtrArray *read_transfer_rate_results,
+ GPtrArray *write_transfer_rate_results,
+ GPtrArray *access_time_results,
+ GError *error,
+ gpointer user_data);
+
/* ---------------------------------------------------------------------------------------------------- */
/* GduPool */
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index 67d3698..d41220c 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -112,6 +112,7 @@ typedef struct
char *drive_model;
char *drive_revision;
char *drive_serial;
+ char *drive_wwn;
char *drive_connection_interface;
guint64 drive_connection_speed;
char **drive_media_compatibility;
@@ -120,6 +121,8 @@ typedef struct
gboolean drive_can_detach;
gboolean drive_can_spindown;
gboolean drive_is_rotational;
+ guint drive_rotation_rate;
+ char *drive_write_cache;
gboolean optical_disc_is_blank;
gboolean optical_disc_is_appendable;
@@ -293,6 +296,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
props->drive_revision = g_strdup (g_value_get_string (value));
else if (strcmp (key, "DriveSerial") == 0)
props->drive_serial = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "DriveWwn") == 0)
+ props->drive_wwn = g_strdup (g_value_get_string (value));
else if (strcmp (key, "DriveConnectionInterface") == 0)
props->drive_connection_interface = g_strdup (g_value_get_string (value));
else if (strcmp (key, "DriveConnectionSpeed") == 0)
@@ -309,6 +314,10 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
props->drive_can_spindown = g_value_get_boolean (value);
else if (strcmp (key, "DriveIsRotational") == 0)
props->drive_is_rotational = g_value_get_boolean (value);
+ else if (strcmp (key, "DriveRotationRate") == 0)
+ props->drive_rotation_rate = g_value_get_uint (value);
+ else if (strcmp (key, "DriveWriteCache") == 0)
+ props->drive_write_cache = g_strdup (g_value_get_string (value));
else if (strcmp (key, "OpticalDiscIsBlank") == 0)
props->optical_disc_is_blank = g_value_get_boolean (value);
@@ -424,6 +433,7 @@ device_properties_free (DeviceProperties *props)
g_free (props->drive_vendor);
g_free (props->drive_revision);
g_free (props->drive_serial);
+ g_free (props->drive_wwn);
g_free (props->drive_connection_interface);
g_strfreev (props->drive_media_compatibility);
g_free (props->drive_media);
@@ -1036,6 +1046,12 @@ gdu_device_drive_get_serial (GduDevice *device)
}
const char *
+gdu_device_drive_get_wwn (GduDevice *device)
+{
+ return device->priv->props->drive_wwn;
+}
+
+const char *
gdu_device_drive_get_connection_interface (GduDevice *device)
{
return device->priv->props->drive_connection_interface;
@@ -1059,6 +1075,12 @@ gdu_device_drive_get_media (GduDevice *device)
return device->priv->props->drive_media;
}
+const char *
+gdu_device_drive_get_write_cache (GduDevice *device)
+{
+ return device->priv->props->drive_write_cache;
+}
+
gboolean
gdu_device_drive_get_is_media_ejectable (GduDevice *device)
{
@@ -1090,6 +1112,12 @@ gdu_device_drive_get_is_rotational (GduDevice *device)
return device->priv->props->drive_is_rotational;
}
+guint
+gdu_device_drive_get_rotation_rate (GduDevice *device)
+{
+ return device->priv->props->drive_rotation_rate;
+}
+
gboolean
gdu_device_optical_disc_get_is_blank (GduDevice *device)
{
@@ -2343,3 +2371,57 @@ gdu_device_op_drive_poll_media (GduDevice *device,
op_poll_media_cb,
data);
}
+
+/* -------------------------------------------------------------------------------- */
+
+typedef struct {
+ GduDevice *device;
+ GduDeviceDriveBenchmarkCompletedFunc callback;
+ gpointer user_data;
+} DriveBenchmarkData;
+
+static void
+op_drive_benchmark_cb (DBusGProxy *proxy,
+ GPtrArray *read_transfer_rate_results,
+ GPtrArray *write_transfer_rate_results,
+ GPtrArray *access_time_results,
+ GError *error,
+ gpointer user_data)
+{
+ DriveBenchmarkData *data = user_data;
+ _gdu_error_fixup (error);
+
+ if (data->callback != NULL) {
+ data->callback (data->device,
+ read_transfer_rate_results,
+ write_transfer_rate_results,
+ access_time_results,
+ error,
+ data->user_data);
+ }
+ g_object_unref (data->device);
+ g_free (data);
+}
+
+void gdu_device_op_drive_benchmark (GduDevice *device,
+ gboolean do_write_benchmark,
+ const gchar* const * options,
+ GduDeviceDriveBenchmarkCompletedFunc callback,
+ gpointer user_data)
+{
+ DriveBenchmarkData *data;
+
+ data = g_new0 (DriveBenchmarkData, 1);
+ data->device = g_object_ref (device);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ org_freedesktop_DeviceKit_Disks_Device_drive_benchmark_async (device->priv->proxy,
+ do_write_benchmark,
+ (const gchar **) options,
+ op_drive_benchmark_cb,
+ data);
+}
+
+
+/* -------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index a53190d..6d66902 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -132,6 +132,7 @@ const char *gdu_device_drive_get_vendor (GduDevice *device);
const char *gdu_device_drive_get_model (GduDevice *device);
const char *gdu_device_drive_get_revision (GduDevice *device);
const char *gdu_device_drive_get_serial (GduDevice *device);
+const char *gdu_device_drive_get_wwn (GduDevice *device);
const char *gdu_device_drive_get_connection_interface (GduDevice *device);
guint64 gdu_device_drive_get_connection_speed (GduDevice *device);
char **gdu_device_drive_get_media_compatibility (GduDevice *device);
@@ -141,6 +142,8 @@ gboolean gdu_device_drive_get_requires_eject (GduDevice *device);
gboolean gdu_device_drive_get_can_detach (GduDevice *device);
gboolean gdu_device_drive_get_can_spindown (GduDevice *device);
gboolean gdu_device_drive_get_is_rotational (GduDevice *device);
+guint gdu_device_drive_get_rotation_rate (GduDevice *device);
+const char *gdu_device_drive_get_write_cache (GduDevice *device);
gboolean gdu_device_optical_disc_get_is_blank (GduDevice *device);
gboolean gdu_device_optical_disc_get_is_appendable (GduDevice *device);
@@ -345,6 +348,14 @@ void gdu_device_op_drive_poll_media (GduDevice
GduDeviceDrivePollMediaCompletedFunc callback,
gpointer user_data);
+/* ---------------------------------------------------------------------------------------------------- */
+
+void gdu_device_op_drive_benchmark (GduDevice *device,
+ gboolean do_write_benchmark,
+ const gchar* const * options,
+ GduDeviceDriveBenchmarkCompletedFunc callback,
+ gpointer user_data);
+
G_END_DECLS
#endif /* __GDU_DEVICE_H */
diff --git a/src/gdu/gdu-util.c b/src/gdu/gdu-util.c
index 6e70b2b..73de29e 100644
--- a/src/gdu/gdu-util.c
+++ b/src/gdu/gdu-util.c
@@ -403,7 +403,7 @@ gdu_get_job_description (const char *job_id)
s = g_strdup (_("Forcibly Locking LUKS device"));
} else {
s = g_strdup_printf ("%s", job_id);
- g_warning ("No friendly string for job with id '%s'", job_id);
+ g_debug ("No friendly string for job with id '%s'", job_id);
}
return s;
}
@@ -837,13 +837,13 @@ gdu_util_get_speed_for_display (guint64 speed)
if (speed < 1000 * 1000) {
displayed_speed = (double) speed / 1000.0;
- str = g_strdup_printf (_("%.1f kbit/s"), displayed_speed);
+ str = g_strdup_printf (_("%.1f KB/s"), displayed_speed);
} else if (speed < 1000 * 1000 * 1000) {
displayed_speed = (double) speed / 1000.0 / 1000.0;
- str = g_strdup_printf (_("%.1f Mbit/s"), displayed_speed);
+ str = g_strdup_printf (_("%.1f MB/s"), displayed_speed);
} else {
displayed_speed = (double) speed / 1000.0 / 1000.0 / 1000.0;
- str = g_strdup_printf (_("%.1f Gbit/s"), displayed_speed);
+ str = g_strdup_printf (_("%.1f GB/s"), displayed_speed);
}
return str;
diff --git a/src/palimpsest/gdu-section-drive.c b/src/palimpsest/gdu-section-drive.c
index 10a875f..0587487 100644
--- a/src/palimpsest/gdu-section-drive.c
+++ b/src/palimpsest/gdu-section-drive.c
@@ -36,6 +36,8 @@ struct _GduSectionDrivePrivate
GduDetailsElement *firmware_element;
GduDetailsElement *serial_element;
GduDetailsElement *wwn_element;
+ GduDetailsElement *write_cache_element;
+ GduDetailsElement *rotation_rate_element;
GduDetailsElement *capacity_element;
GduDetailsElement *connection_element;
GduDetailsElement *partitioning_element;
@@ -46,6 +48,7 @@ struct _GduSectionDrivePrivate
GduButtonElement *eject_button;
GduButtonElement *detach_button;
GduButtonElement *smart_button;
+ GduButtonElement *benchmark_button;
};
G_DEFINE_TYPE (GduSectionDrive, gdu_section_drive, GDU_TYPE_SECTION)
@@ -95,20 +98,26 @@ gdu_section_drive_update (GduSection *_section)
const gchar *firmware;
const gchar *serial;
const gchar *wwn;
+ const gchar *write_cache;
+ guint rotation_rate;
+ gboolean is_rotational;
GIcon *icon;
gboolean show_cddvd_button;
gboolean show_format_button;
gboolean show_eject_button;
gboolean show_detach_button;
gboolean show_smart_button;
+ gboolean show_benchmark_button;
show_cddvd_button = FALSE;
show_format_button = FALSE;
show_eject_button = FALSE;
show_detach_button = FALSE;
show_smart_button = FALSE;
+ show_benchmark_button = FALSE;
d = NULL;
+ wwn = NULL;
p = gdu_section_get_presentable (_section);
d = gdu_presentable_get_device (p);
@@ -138,10 +147,41 @@ gdu_section_drive_update (GduSection *_section)
serial = "â??";
gdu_details_element_set_text (section->priv->serial_element, serial);
- wwn = NULL; /*TODO: gdu_device_drive_get_wwn (d)*/
- if (wwn == NULL || strlen (wwn) == 0)
- wwn = "â??";
- gdu_details_element_set_text (section->priv->wwn_element, wwn);
+ wwn = gdu_device_drive_get_wwn (d);
+ if (wwn == NULL || strlen (wwn) == 0) {
+ gdu_details_element_set_text (section->priv->wwn_element, "â??");
+ } else {
+ s = g_strdup_printf ("0x%s", wwn);
+ gdu_details_element_set_text (section->priv->wwn_element, s);
+ g_free (s);
+ }
+
+ write_cache = gdu_device_drive_get_write_cache (d);
+ is_rotational = gdu_device_drive_get_is_rotational (d);
+ rotation_rate = gdu_device_drive_get_rotation_rate (d);
+
+ if (write_cache == NULL || strlen (write_cache) == 0) {
+ gdu_details_element_set_text (section->priv->write_cache_element, "â??");
+ } else if (g_strcmp0 (write_cache, "enabled") == 0) {
+ gdu_details_element_set_text (section->priv->write_cache_element, C_("Write Cache", "Enabled"));
+ } else if (g_strcmp0 (write_cache, "disabled") == 0) {
+ gdu_details_element_set_text (section->priv->write_cache_element, C_("Write Cache", "Disabled"));
+ } else {
+ gdu_details_element_set_text (section->priv->write_cache_element, write_cache);
+ }
+
+ if (is_rotational) {
+ if (rotation_rate > 0) {
+ s = g_strdup_printf (_("%d RPM"), rotation_rate);
+ gdu_details_element_set_text (section->priv->rotation_rate_element, s);
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (section->priv->rotation_rate_element, "â??");
+ }
+ } else {
+ gdu_details_element_set_text (section->priv->rotation_rate_element,
+ C_("Rotation Rate", "Solid-State Disk"));
+ }
if (gdu_device_is_partition_table (d)) {
const gchar *scheme;
@@ -200,6 +240,7 @@ gdu_section_drive_update (GduSection *_section)
TRUE);
gdu_details_element_set_text (section->priv->capacity_element, s);
g_free (s);
+ show_benchmark_button = TRUE;
} else {
gdu_details_element_set_text (section->priv->capacity_element,
_("No Media Detected"));
@@ -237,6 +278,7 @@ gdu_section_drive_update (GduSection *_section)
gdu_button_element_set_visible (section->priv->eject_button, show_eject_button);
gdu_button_element_set_visible (section->priv->detach_button, show_detach_button);
gdu_button_element_set_visible (section->priv->smart_button, show_smart_button);
+ gdu_button_element_set_visible (section->priv->benchmark_button, show_benchmark_button);
if (d != NULL)
@@ -319,6 +361,22 @@ on_smart_button_clicked (GduButtonElement *button_element,
gtk_widget_destroy (dialog);
}
+void
+gdu_section_drive_on_benchmark_button_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduSection *section = GDU_SECTION (user_data);
+ GtkWindow *toplevel;
+ GtkWidget *dialog;
+
+ toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+ dialog = gdu_drive_benchmark_dialog_new (toplevel,
+ GDU_DRIVE (gdu_section_get_presentable (GDU_SECTION (section))));
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
static void
@@ -532,10 +590,19 @@ gdu_section_drive_constructed (GObject *object)
g_ptr_array_add (elements, element);
section->priv->firmware_element = element;
+ /* Translators: if you translate "World Wide Name", please include the abbreviation "WWN" */
element = gdu_details_element_new (_("World Wide Name:"), NULL, NULL);
g_ptr_array_add (elements, element);
section->priv->wwn_element = element;
+ element = gdu_details_element_new (_("Write Cache:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->write_cache_element = element;
+
+ element = gdu_details_element_new (_("Rotation Rate:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->rotation_rate_element = element;
+
element = gdu_details_element_new (_("Capacity:"), NULL, NULL);
g_ptr_array_add (elements, element);
section->priv->capacity_element = element;
@@ -562,6 +629,8 @@ gdu_section_drive_constructed (GObject *object)
gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+ /* -------------------------------------------------------------------------------- */
+
elements = g_ptr_array_new_with_free_func (g_object_unref);
button_element = gdu_button_element_new ("brasero",
@@ -614,6 +683,16 @@ gdu_section_drive_constructed (GObject *object)
g_ptr_array_add (elements, button_element);
section->priv->detach_button = button_element;
+ button_element = gdu_button_element_new ("gtk-execute", /* TODO: better icon */
+ _("_Benchmark"),
+ _("Measure drive performance"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (gdu_section_drive_on_benchmark_button_clicked),
+ section);
+ g_ptr_array_add (elements, button_element);
+ section->priv->benchmark_button = button_element;
+
table = gdu_button_table_new (2, elements);
g_ptr_array_unref (elements);
gtk_container_add (GTK_CONTAINER (align), table);
diff --git a/src/palimpsest/gdu-section-drive.h b/src/palimpsest/gdu-section-drive.h
index 9c21b09..6c728a0 100644
--- a/src/palimpsest/gdu-section-drive.h
+++ b/src/palimpsest/gdu-section-drive.h
@@ -55,10 +55,15 @@ GType gdu_section_drive_get_type (void);
GtkWidget *gdu_section_drive_new (GduShell *shell,
GduPresentable *presentable);
-/* exported for use in GduSectionLinuxMd and others - user_data must be a GduSection instance */
+/* these functions are exported for use in GduSectionLinuxMd and other sections - user_data must
+ * be a GduSection instance
+ */
void
gdu_section_drive_on_format_button_clicked (GduButtonElement *button_element,
gpointer user_data);
+void
+gdu_section_drive_on_benchmark_button_clicked (GduButtonElement *button_element,
+ gpointer user_data);
#endif /* GDU_SECTION_DRIVE_H */
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index ec5633e..c82bd53 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -50,6 +50,7 @@ struct _GduSectionLinuxMdDrivePrivate
GduButtonElement *format_button;
GduButtonElement *edit_components_button;
GduButtonElement *check_button;
+ GduButtonElement *benchmark_button;
};
G_DEFINE_TYPE (GduSectionLinuxMdDrive, gdu_section_linux_md_drive, GDU_TYPE_SECTION)
@@ -296,6 +297,7 @@ gdu_section_linux_md_drive_update (GduSection *_section)
gboolean show_format_button;
gboolean show_edit_components_button;
gboolean show_check_button;
+ gboolean show_benchmark_button;
GList *slaves;
GduDevice *slave;
const gchar *level;
@@ -309,6 +311,7 @@ gdu_section_linux_md_drive_update (GduSection *_section)
show_format_button = FALSE;
show_edit_components_button = FALSE;
show_check_button = FALSE;
+ show_benchmark_button = FALSE;
p = gdu_section_get_presentable (_section);
d = gdu_presentable_get_device (p);
@@ -368,6 +371,7 @@ gdu_section_linux_md_drive_update (GduSection *_section)
show_format_button = TRUE;
show_check_button = TRUE;
+ show_benchmark_button = TRUE;
show_edit_components_button = TRUE;
show_md_stop_button = TRUE;
} else {
@@ -386,6 +390,7 @@ gdu_section_linux_md_drive_update (GduSection *_section)
gdu_button_element_set_visible (section->priv->format_button, show_format_button);
gdu_button_element_set_visible (section->priv->edit_components_button, show_edit_components_button);
gdu_button_element_set_visible (section->priv->check_button, show_check_button);
+ gdu_button_element_set_visible (section->priv->benchmark_button, show_benchmark_button);
if (d != NULL)
g_object_unref (d);
@@ -1178,6 +1183,16 @@ gdu_section_linux_md_drive_constructed (GObject *object)
g_ptr_array_add (elements, button_element);
section->priv->edit_components_button = button_element;
+ button_element = gdu_button_element_new ("gtk-execute", /* TODO: better icon */
+ _("_Benchmark"),
+ _("Measure RAID array performance"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (gdu_section_drive_on_benchmark_button_clicked),
+ section);
+ g_ptr_array_add (elements, button_element);
+ section->priv->benchmark_button = button_element;
+
table = gdu_button_table_new (2, elements);
g_ptr_array_unref (elements);
gtk_container_add (GTK_CONTAINER (align), table);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]