summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.am18
-rw-r--r--test/benchmark-common.c193
-rw-r--r--test/benchmark-gvfs-big-files.c170
-rw-r--r--test/benchmark-gvfs-small-files.c170
-rw-r--r--test/benchmark-posix-big-files.c176
-rw-r--r--test/benchmark-posix-small-files.c176
6 files changed, 903 insertions, 0 deletions
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 00000000..143d50ee
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,18 @@
+NULL =
+
+AM_CFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS) \
+ -DG_DISABLE_DEPRECATED
+
+AM_LDFLAGS = \
+ $(top_builddir)/gio/libgio.la \
+ $(GLIB_LIBS)
+
+noinst_PROGRAMS = \
+ benchmark-gvfs-small-files \
+ benchmark-gvfs-big-files \
+ benchmark-posix-small-files \
+ benchmark-posix-big-files \
+ $(NULL)
diff --git a/test/benchmark-common.c b/test/benchmark-common.c
new file mode 100644
index 00000000..46d6f7b1
--- /dev/null
+++ b/test/benchmark-common.c
@@ -0,0 +1,193 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* This file should be included directly in each benchmark program */
+
+#define __USE_GNU 1
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <glib/gprintf.h>
+
+static GMainLoop *main_loop;
+
+typedef struct
+{
+ gdouble x;
+ gdouble y;
+}
+BenchmarkDataPoint;
+
+typedef struct
+{
+ /* Array of BenchmarkDataPoints */
+ GArray *points;
+}
+BenchmarkDataSet;
+
+typedef struct
+{
+ gchar *name;
+ gchar *x_unit;
+ gchar *y_unit;
+
+ GList *data_sets;
+}
+BenchmarkDataPlot;
+
+static gint benchmark_run (gint argc, gchar *argv []);
+
+GList *benchmark_data_plots = NULL;
+gboolean benchmark_is_running = FALSE;
+
+static void
+benchmark_begin_data_plot (const gchar *name, const gchar *x_unit, const gchar *y_unit)
+{
+ BenchmarkDataPlot *data_plot;
+
+ data_plot = g_new0 (BenchmarkDataPlot, 1);
+
+ data_plot->name = g_strdup (name);
+ data_plot->x_unit = g_strdup (x_unit);
+ data_plot->y_unit = g_strdup (y_unit);
+
+ data_plot->data_sets = NULL;
+
+ benchmark_data_plots = g_list_prepend (benchmark_data_plots, data_plot);
+}
+
+static void
+benchmark_begin_data_set (void)
+{
+ BenchmarkDataPlot *data_plot;
+ BenchmarkDataSet *data_set;
+
+ if (!benchmark_data_plots)
+ g_error ("Must begin a data plot before adding data sets!");
+
+ data_plot = benchmark_data_plots->data;
+
+ data_set = g_new0 (BenchmarkDataSet, 1);
+ data_set->points = g_array_new (FALSE, FALSE, sizeof (BenchmarkDataPoint));
+
+ data_plot->data_sets = g_list_prepend (data_plot->data_sets, data_set);
+}
+
+static void
+benchmark_add_data_point (gdouble x, gdouble y)
+{
+ BenchmarkDataPlot *data_plot;
+ BenchmarkDataSet *data_set;
+ BenchmarkDataPoint data_point;
+
+ if (!benchmark_data_plots)
+ g_error ("Must begin a data plot before adding data sets!");
+
+ data_plot = benchmark_data_plots->data;
+
+ if (!data_plot->data_sets)
+ g_error ("Must begin a data set before adding data points!");
+
+ data_set = data_plot->data_sets->data;
+
+ data_point.x = x;
+ data_point.y = y;
+
+ g_array_append_val (data_set->points, data_point);
+}
+
+static void
+benchmark_end (void)
+{
+ BenchmarkDataPlot *plot;
+ GList *l;
+
+ /* Dump plots */
+
+ if (!benchmark_data_plots)
+ exit (1);
+
+ plot = benchmark_data_plots->data;
+ if (!plot)
+ exit (1);
+
+ for (l = plot->data_sets; l; l = g_list_next (l))
+ {
+ BenchmarkDataSet *set = l->data;
+ guint i;
+
+ for (i = 0; i < set->points->len; i++)
+ {
+ BenchmarkDataPoint *point = &g_array_index (set->points, BenchmarkDataPoint, i);
+
+ g_print ("%20lf %20lf\n", point->x, point->y);
+ }
+ }
+
+ exit (0);
+}
+
+static void
+benchmark_begin (const gchar *name)
+{
+ g_type_init ();
+ g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR);
+ main_loop = g_main_loop_new (NULL, FALSE);
+}
+
+G_GNUC_UNUSED static void
+benchmark_run_main_loop (void)
+{
+ g_main_loop_run (main_loop);
+}
+
+G_GNUC_UNUSED static void
+benchmark_quit_main_loop (void)
+{
+ g_main_loop_quit (main_loop);
+}
+
+static void
+benchmark_timeout (void)
+{
+ benchmark_is_running = FALSE;
+}
+
+G_GNUC_UNUSED static void
+benchmark_start_wallclock_timer (gint n_seconds)
+{
+ benchmark_is_running = TRUE;
+ signal (SIGALRM, (sig_t) benchmark_timeout);
+ alarm (n_seconds);
+}
+
+G_GNUC_UNUSED static void
+benchmark_start_cpu_timer (gint n_seconds)
+{
+ struct itimerval itv;
+
+ benchmark_is_running = TRUE;
+
+ memset (&itv, 0, sizeof (itv));
+ itv.it_value.tv_sec = n_seconds;
+
+ signal (SIGPROF, (sig_t) benchmark_timeout);
+ setitimer (ITIMER_PROF, &itv, NULL);
+}
+
+gint
+main (gint argc, gchar *argv [])
+{
+ gint result;
+
+ benchmark_begin (BENCHMARK_UNIT_NAME);
+ result = benchmark_run (argc, argv);
+ benchmark_end ();
+
+ return result;
+}
diff --git a/test/benchmark-gvfs-big-files.c b/test/benchmark-gvfs-big-files.c
new file mode 100644
index 00000000..3fcc1fc1
--- /dev/null
+++ b/test/benchmark-gvfs-big-files.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gfile.h>
+
+#define BENCHMARK_UNIT_NAME "gvfs-big-file"
+
+#include "benchmark-common.c"
+
+#define FILE_SIZE (1024 * 1024 * 50) /* 50 MiB */
+#define BUFFER_SIZE 4096
+#define ITERATIONS_NUM 1
+
+static gboolean
+is_dir (GFile *file)
+{
+ GFileInfo *info;
+ gboolean res;
+
+ info = g_file_get_info (file, G_FILE_ATTRIBUTE_STD_TYPE, 0, NULL, NULL);
+ res = info && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
+ if (info)
+ g_object_unref (info);
+ return res;
+}
+
+static GFile *
+create_file (GFile *base_dir)
+{
+ GFile *scratch_file;
+ gchar *scratch_name;
+ GOutputStream *output_stream;
+ gint pid;
+ GError *error = NULL;
+ gchar buffer [BUFFER_SIZE];
+ gint i;
+
+ pid = getpid ();
+ scratch_name = g_strdup_printf ("gvfs-benchmark-scratch-%d", pid);
+ scratch_file = g_file_resolve_relative (base_dir, scratch_name);
+ g_free (scratch_name);
+
+ if (!scratch_file)
+ return NULL;
+
+ output_stream = G_OUTPUT_STREAM (g_file_replace (scratch_file, 0, FALSE, NULL, &error));
+ if (!output_stream)
+ {
+ g_printerr ("Failed to create scratch file: %s\n", error->message);
+ g_object_unref (scratch_file);
+ return NULL;
+ }
+
+ memset (buffer, 0xaa, BUFFER_SIZE);
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ if (g_output_stream_write (output_stream, buffer, BUFFER_SIZE, NULL, &error) < BUFFER_SIZE)
+ {
+ g_printerr ("Failed to populate scratch file: %s\n", error->message);
+ g_output_stream_close (output_stream, NULL, NULL);
+ g_object_unref (output_stream);
+ g_object_unref (scratch_file);
+ return NULL;
+ }
+ }
+
+ g_output_stream_close (output_stream, NULL, NULL);
+ g_object_unref (output_stream);
+ return scratch_file;
+}
+
+static void
+read_file (GFile *scratch_file)
+{
+ GInputStream *input_stream;
+ GError *error = NULL;
+ gint i;
+
+ input_stream = (GInputStream *) g_file_read (scratch_file, NULL, &error);
+ if (!input_stream)
+ {
+ g_printerr ("Failed to open scratch file: %s\n", error->message);
+ return;
+ }
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gchar buffer [BUFFER_SIZE];
+ gsize bytes_read;
+
+ if (!g_input_stream_read_all (input_stream, buffer, BUFFER_SIZE, &bytes_read, NULL, &error) ||
+ bytes_read < BUFFER_SIZE)
+ {
+ g_printerr ("Failed to read back scratch file: %s\n", error->message);
+ g_input_stream_close (input_stream, NULL, NULL);
+ g_object_unref (input_stream);
+ }
+ }
+
+ g_object_unref (input_stream);
+}
+
+static void
+delete_file (GFile *scratch_file)
+{
+ GError *error = NULL;
+
+#if 0
+ /* Enable when GDaemonFile supports delete */
+
+ if (!g_file_delete (scratch_file, NULL, &error))
+ {
+ g_printerr ("Failed to delete scratch file: %s\n", error->message);
+ }
+#endif
+}
+
+static gint
+benchmark_run (gint argc, gchar *argv [])
+{
+ GFile *base_dir;
+ GFile *scratch_file;
+ gint i;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ if (argc < 2)
+ {
+ g_printerr ("Usage: %s <scratch URI>\n", argv [0]);
+ return 1;
+ }
+
+ base_dir = g_file_get_for_commandline_arg (argv [1]);
+
+ if (!is_dir (base_dir))
+ {
+ g_printerr ("Scratch URI %s is not a directory\n", argv [1]);
+ g_object_unref (base_dir);
+ return 1;
+ }
+
+ for (i = 0; i < ITERATIONS_NUM; i++)
+ {
+ scratch_file = create_file (base_dir);
+ if (!scratch_file)
+ {
+ g_object_unref (base_dir);
+ return 1;
+ }
+
+ read_file (scratch_file);
+ delete_file (scratch_file);
+
+ g_object_unref (scratch_file);
+ }
+
+ g_object_unref (base_dir);
+ return 0;
+}
diff --git a/test/benchmark-gvfs-small-files.c b/test/benchmark-gvfs-small-files.c
new file mode 100644
index 00000000..f0b0adcd
--- /dev/null
+++ b/test/benchmark-gvfs-small-files.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gfile.h>
+
+#define BENCHMARK_UNIT_NAME "gvfs-big-file"
+
+#include "benchmark-common.c"
+
+#define FILE_SIZE 4096
+#define BUFFER_SIZE 4096
+#define ITERATIONS_NUM 65536
+
+static gboolean
+is_dir (GFile *file)
+{
+ GFileInfo *info;
+ gboolean res;
+
+ info = g_file_get_info (file, G_FILE_ATTRIBUTE_STD_TYPE, 0, NULL, NULL);
+ res = info && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
+ if (info)
+ g_object_unref (info);
+ return res;
+}
+
+static GFile *
+create_file (GFile *base_dir)
+{
+ GFile *scratch_file;
+ gchar *scratch_name;
+ GOutputStream *output_stream;
+ gint pid;
+ GError *error = NULL;
+ gchar buffer [BUFFER_SIZE];
+ gint i;
+
+ pid = getpid ();
+ scratch_name = g_strdup_printf ("gvfs-benchmark-scratch-%d", pid);
+ scratch_file = g_file_resolve_relative (base_dir, scratch_name);
+ g_free (scratch_name);
+
+ if (!scratch_file)
+ return NULL;
+
+ output_stream = G_OUTPUT_STREAM (g_file_replace (scratch_file, 0, FALSE, NULL, &error));
+ if (!output_stream)
+ {
+ g_printerr ("Failed to create scratch file: %s\n", error->message);
+ g_object_unref (scratch_file);
+ return NULL;
+ }
+
+ memset (buffer, 0xaa, BUFFER_SIZE);
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ if (g_output_stream_write (output_stream, buffer, BUFFER_SIZE, NULL, &error) < BUFFER_SIZE)
+ {
+ g_printerr ("Failed to populate scratch file: %s\n", error->message);
+ g_output_stream_close (output_stream, NULL, NULL);
+ g_object_unref (output_stream);
+ g_object_unref (scratch_file);
+ return NULL;
+ }
+ }
+
+ g_output_stream_close (output_stream, NULL, NULL);
+ g_object_unref (output_stream);
+ return scratch_file;
+}
+
+static void
+read_file (GFile *scratch_file)
+{
+ GInputStream *input_stream;
+ GError *error = NULL;
+ gint i;
+
+ input_stream = (GInputStream *) g_file_read (scratch_file, NULL, &error);
+ if (!input_stream)
+ {
+ g_printerr ("Failed to open scratch file: %s\n", error->message);
+ return;
+ }
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gchar buffer [BUFFER_SIZE];
+ gsize bytes_read;
+
+ if (!g_input_stream_read_all (input_stream, buffer, BUFFER_SIZE, &bytes_read, NULL, &error) ||
+ bytes_read < BUFFER_SIZE)
+ {
+ g_printerr ("Failed to read back scratch file: %s\n", error->message);
+ g_input_stream_close (input_stream, NULL, NULL);
+ g_object_unref (input_stream);
+ }
+ }
+
+ g_object_unref (input_stream);
+}
+
+static void
+delete_file (GFile *scratch_file)
+{
+ GError *error = NULL;
+
+#if 0
+ /* Enable when GDaemonFile supports delete */
+
+ if (!g_file_delete (scratch_file, NULL, &error))
+ {
+ g_printerr ("Failed to delete scratch file: %s\n", error->message);
+ }
+#endif
+}
+
+static gint
+benchmark_run (gint argc, gchar *argv [])
+{
+ GFile *base_dir;
+ GFile *scratch_file;
+ gint i;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ if (argc < 2)
+ {
+ g_printerr ("Usage: %s <scratch URI>\n", argv [0]);
+ return 1;
+ }
+
+ base_dir = g_file_get_for_commandline_arg (argv [1]);
+
+ if (!is_dir (base_dir))
+ {
+ g_printerr ("Scratch URI %s is not a directory\n", argv [1]);
+ g_object_unref (base_dir);
+ return 1;
+ }
+
+ for (i = 0; i < ITERATIONS_NUM; i++)
+ {
+ scratch_file = create_file (base_dir);
+ if (!scratch_file)
+ {
+ g_object_unref (base_dir);
+ return 1;
+ }
+
+ read_file (scratch_file);
+ delete_file (scratch_file);
+
+ g_object_unref (scratch_file);
+ }
+
+ g_object_unref (base_dir);
+ return 0;
+}
diff --git a/test/benchmark-posix-big-files.c b/test/benchmark-posix-big-files.c
new file mode 100644
index 00000000..3c4dbfbf
--- /dev/null
+++ b/test/benchmark-posix-big-files.c
@@ -0,0 +1,176 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <gio/gfile.h>
+
+#define BENCHMARK_UNIT_NAME "posix-big-file"
+
+#include "benchmark-common.c"
+
+#define FILE_SIZE (1024 * 1024 * 50) /* 50 MiB */
+#define BUFFER_SIZE 4096
+#define ITERATIONS_NUM 1
+
+static gboolean
+is_dir (const gchar *dir)
+{
+ struct stat sbuf;
+
+ if (stat (dir, &sbuf) < 0)
+ return FALSE;
+
+ if (S_ISDIR (sbuf.st_mode))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gchar *
+create_file (const gchar *base_dir)
+{
+ gchar *scratch_file;
+ gchar *scratch_name;
+ gint output_fd;
+ gint pid;
+ GError *error = NULL;
+ gchar buffer [BUFFER_SIZE];
+ gint i;
+
+ pid = getpid ();
+ scratch_file = g_strdup_printf ("%s/posix-benchmark-scratch-%d", base_dir, pid);
+
+ output_fd = open (scratch_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if (output_fd < 0)
+ {
+ g_printerr ("Failed to create scratch file: %s\n", strerror (errno));
+ g_free (scratch_file);
+ return NULL;
+ }
+
+ memset (buffer, 0xaa, BUFFER_SIZE);
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gint bytes_written;
+
+ bytes_written = write (output_fd, buffer, BUFFER_SIZE);
+ if (bytes_written < BUFFER_SIZE)
+ {
+ if (errno == EINTR)
+ {
+ i -= BUFFER_SIZE - bytes_written;
+ continue;
+ }
+
+ g_printerr ("Failed to populate scratch file: %s\n", strerror (errno));
+ close (output_fd);
+ g_free (scratch_file);
+ return NULL;
+ }
+ }
+
+ close (output_fd);
+ return scratch_file;
+}
+
+static void
+read_file (const gchar *scratch_file)
+{
+ gint input_fd;
+ GError *error = NULL;
+ gint i;
+
+ input_fd = open (scratch_file, O_RDONLY);
+ if (input_fd < 0)
+ {
+ g_printerr ("Failed to read back scratch file: %s\n", strerror (errno));
+ return;
+ }
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gchar buffer [BUFFER_SIZE];
+ gsize bytes_read;
+
+ bytes_read = read (input_fd, buffer, BUFFER_SIZE);
+ if (bytes_read < BUFFER_SIZE)
+ {
+ if (errno == EINTR)
+ {
+ i -= BUFFER_SIZE - bytes_read;
+ continue;
+ }
+
+ g_printerr ("Failed to read back scratch file: %s\n", strerror (errno));
+ close (input_fd);
+ return;
+ }
+ }
+
+ close (input_fd);
+}
+
+static void
+delete_file (const gchar *scratch_file)
+{
+ GError *error = NULL;
+
+ if (unlink (scratch_file) < 0)
+ {
+ g_printerr ("Failed to delete scratch file: %s\n", strerror (errno));
+ }
+}
+
+static gint
+benchmark_run (gint argc, gchar *argv [])
+{
+ gchar *base_dir;
+ gchar *scratch_file;
+ gint i;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ if (argc < 2)
+ {
+ g_printerr ("Usage: %s <scratch path>\n", argv [0]);
+ return 1;
+ }
+
+ base_dir = argv [1];
+
+ if (!is_dir (base_dir))
+ {
+ g_printerr ("Scratch path %s is not a directory\n", argv [1]);
+ return 1;
+ }
+
+ for (i = 0; i < ITERATIONS_NUM; i++)
+ {
+ scratch_file = create_file (base_dir);
+ if (!scratch_file)
+ {
+ g_free (base_dir);
+ return 1;
+ }
+
+ read_file (scratch_file);
+ delete_file (scratch_file);
+
+ g_free (scratch_file);
+ }
+
+ return 0;
+}
diff --git a/test/benchmark-posix-small-files.c b/test/benchmark-posix-small-files.c
new file mode 100644
index 00000000..01d801ae
--- /dev/null
+++ b/test/benchmark-posix-small-files.c
@@ -0,0 +1,176 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <gio/gfile.h>
+
+#define BENCHMARK_UNIT_NAME "posix-big-file"
+
+#include "benchmark-common.c"
+
+#define FILE_SIZE 4096
+#define BUFFER_SIZE 4096
+#define ITERATIONS_NUM 65536
+
+static gboolean
+is_dir (const gchar *dir)
+{
+ struct stat sbuf;
+
+ if (stat (dir, &sbuf) < 0)
+ return FALSE;
+
+ if (S_ISDIR (sbuf.st_mode))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gchar *
+create_file (const gchar *base_dir)
+{
+ gchar *scratch_file;
+ gchar *scratch_name;
+ gint output_fd;
+ gint pid;
+ GError *error = NULL;
+ gchar buffer [BUFFER_SIZE];
+ gint i;
+
+ pid = getpid ();
+ scratch_file = g_strdup_printf ("%s/posix-benchmark-scratch-%d", base_dir, pid);
+
+ output_fd = open (scratch_file, O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if (output_fd < 0)
+ {
+ g_printerr ("Failed to create scratch file: %s\n", strerror (errno));
+ g_free (scratch_file);
+ return NULL;
+ }
+
+ memset (buffer, 0xaa, BUFFER_SIZE);
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gint bytes_written;
+
+ bytes_written = write (output_fd, buffer, BUFFER_SIZE);
+ if (bytes_written < BUFFER_SIZE)
+ {
+ if (errno == EINTR)
+ {
+ i -= BUFFER_SIZE - bytes_written;
+ continue;
+ }
+
+ g_printerr ("Failed to populate scratch file: %s\n", strerror (errno));
+ close (output_fd);
+ g_free (scratch_file);
+ return NULL;
+ }
+ }
+
+ close (output_fd);
+ return scratch_file;
+}
+
+static void
+read_file (const gchar *scratch_file)
+{
+ gint input_fd;
+ GError *error = NULL;
+ gint i;
+
+ input_fd = open (scratch_file, O_RDONLY);
+ if (input_fd < 0)
+ {
+ g_printerr ("Failed to read back scratch file: %s\n", strerror (errno));
+ return;
+ }
+
+ for (i = 0; i < FILE_SIZE; i += BUFFER_SIZE)
+ {
+ gchar buffer [BUFFER_SIZE];
+ gsize bytes_read;
+
+ bytes_read = read (input_fd, buffer, BUFFER_SIZE);
+ if (bytes_read < BUFFER_SIZE)
+ {
+ if (errno == EINTR)
+ {
+ i -= BUFFER_SIZE - bytes_read;
+ continue;
+ }
+
+ g_printerr ("Failed to read back scratch file: %s\n", strerror (errno));
+ close (input_fd);
+ return;
+ }
+ }
+
+ close (input_fd);
+}
+
+static void
+delete_file (const gchar *scratch_file)
+{
+ GError *error = NULL;
+
+ if (unlink (scratch_file) < 0)
+ {
+ g_printerr ("Failed to delete scratch file: %s\n", strerror (errno));
+ }
+}
+
+static gint
+benchmark_run (gint argc, gchar *argv [])
+{
+ gchar *base_dir;
+ gchar *scratch_file;
+ gint i;
+
+ setlocale (LC_ALL, "");
+
+ g_type_init ();
+
+ if (argc < 2)
+ {
+ g_printerr ("Usage: %s <scratch path>\n", argv [0]);
+ return 1;
+ }
+
+ base_dir = argv [1];
+
+ if (!is_dir (base_dir))
+ {
+ g_printerr ("Scratch path %s is not a directory\n", argv [1]);
+ return 1;
+ }
+
+ for (i = 0; i < ITERATIONS_NUM; i++)
+ {
+ scratch_file = create_file (base_dir);
+ if (!scratch_file)
+ {
+ g_free (base_dir);
+ return 1;
+ }
+
+ read_file (scratch_file);
+ delete_file (scratch_file);
+
+ g_free (scratch_file);
+ }
+
+ return 0;
+}