[gnome-talos] Add support for Intel GPU snapshotting



commit 9c73e2ade87817eab6000810dcd9cf816ca36076
Author: Colin Walters <walters verbum org>
Date:   Mon Sep 26 17:13:01 2011 -0400

    Add support for Intel GPU snapshotting

 Makefile-src.am        |    6 +-
 configure.ac           |   13 +++
 src/gnome-talos-gpu.c  |  227 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/gnome-talos-gpu.h  |   29 ++++++
 src/gnome-talos-meta.c |    2 +
 src/gnome-talos.c      |   26 +++++-
 src/util.c             |  128 ++++++++++++++++++++++++++-
 src/util.h             |   40 +++++++++
 8 files changed, 463 insertions(+), 8 deletions(-)
---
diff --git a/Makefile-src.am b/Makefile-src.am
index 9672d63..71dd416 100644
--- a/Makefile-src.am
+++ b/Makefile-src.am
@@ -10,10 +10,14 @@ gnome-talos-session-%.desktop: src/gnome-talos-session.desktop.in
 
 bin_PROGRAMS += gnome-talos
 gnome_talos_SOURCES = src/gnome-talos.c \
+	src/gnome-talos-gpu.c \
+	src/gnome-talos-gpu.h \
 	src/gnome-talos-procinfo.c \
 	src/gnome-talos-procinfo.h \
 	src/gnome-talos-meta.c \
-	src/gnome-talos-meta.h
+	src/gnome-talos-meta.h \
+	src/util.c \
+	src/util.h
 gnome_talos_CPPFLAGS = $(GNOME_TALOS_CFLAGS) -I $(top_srcdir) -I $(top_builddir)
 gnome_talos_LDADD = $(GNOME_TALOS_LIBS)
 
diff --git a/configure.ac b/configure.ac
index 6474c6c..6ac905a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,6 +54,19 @@ AC_DEFINE_UNQUOTED([GIT_VERSION], "$GIT_VERSION", [Output of git describe if ava
 LT_PREREQ([2.2.6])
 LT_INIT([disable-static])
 
+changequote(,)dnl
+if test "x$GCC" = "xyes"; then
+  case " $CFLAGS " in
+  *[\ \	]-Wall[\ \	]*) ;;
+  *) CFLAGS="$CFLAGS -Wall" ;;
+  esac
+  case " $CFLAGS " in
+  *[\ \	]-Wmissing-prototypes[\ \	]*) ;;
+  *) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
+  esac
+fi
+changequote([,])dnl
+
 PKG_PROG_PKG_CONFIG([0.22])
 
 PKG_CHECK_MODULES(GLIB, [glib-2.0])
diff --git a/src/gnome-talos-gpu.c b/src/gnome-talos-gpu.c
new file mode 100644
index 0000000..768970c
--- /dev/null
+++ b/src/gnome-talos-gpu.c
@@ -0,0 +1,227 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include "gnome-talos-gpu.h"
+#include "util.h"
+
+#define GPU_BASE_PATH "/sys/kernel/debug/dri"
+
+static char *gpudir;
+static gboolean is_i915;
+static GRegex *i915_gem_objects_regex;
+
+static void
+init_gpu_dir_unlocked (void)
+{
+  const char *filename;
+  GDir *dir;
+  GSList *names = NULL;
+  GSList *iter;
+
+  dir = g_dir_open (GPU_BASE_PATH, 0, NULL);
+  if (!dir)
+    {
+      gpudir = NULL;
+      return;
+    }
+
+  while ((filename = g_dir_read_name (dir)) != NULL)
+    {
+      names = g_slist_prepend (names, g_strdup (filename));
+    }
+  g_dir_close (dir);
+
+  for (iter = names; iter; iter = iter->next)
+    {
+      gboolean name_exists;
+      char *name;
+      char *contents;
+
+      name = g_build_filename (GPU_BASE_PATH, iter->data, "name", NULL);
+      if (g_file_test (name, G_FILE_TEST_EXISTS)
+          && g_file_get_contents (name, &contents, NULL, NULL))
+        {
+          name_exists = strlen (contents) > 0;
+          g_free (contents);
+        }
+      else
+        name_exists = FALSE;
+      g_free (name);
+
+      if (name_exists)
+        {
+          gpudir = g_build_filename (GPU_BASE_PATH, iter->data, NULL);
+          break;
+        }
+    }
+
+  for (iter = names->next; iter; iter = iter->next)
+    {
+      if (iter->data != gpudir)
+        g_free (iter->data);
+    }
+}
+
+
+static void
+init_gpu_static (void)
+{
+  static gsize statics_initialized = 0;
+  char *filename;
+
+  if (!g_once_init_enter (&statics_initialized))
+    return;
+
+  init_gpu_dir_unlocked ();
+
+  filename = g_build_filename (gpudir, "i915_capabilities", NULL);
+  is_i915 = g_file_test (filename, G_FILE_TEST_EXISTS);
+  g_free (filename);
+
+  i915_gem_objects_regex = g_regex_new ("([0-9]+) objects, ([0-9]+) bytes", 0, 0, NULL);
+  
+  g_once_init_leave (&statics_initialized, 1); 
+}
+
+
+GVariant *
+gnome_talos_acquire_gpu_meta (GError **error)
+{
+  char *name;
+  GVariantBuilder builder;
+
+  init_gpu_static ();
+
+  if (gpudir == NULL)
+    return NULL;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+  
+  name = talos_util_build_filename_get_utf8_contents_sync (error,
+                                                           gpudir,
+                                                           "name",
+                                                           NULL);
+  if (!name)
+    goto failed;
+
+  g_variant_builder_add (&builder, "{sv}",
+			 "name",
+			 g_variant_new_string (name));
+  g_free (name);
+
+  if (is_i915)
+    {
+      GVariantBuilder i915_builder;
+      GVariant *i915_capabilities;
+      char *filename;
+
+      filename = g_build_filename (gpudir, "i915_capabilities", NULL);
+      i915_capabilities = talos_util_rfc822_file_to_variant (filename, error);
+      g_free (filename);
+      if (!i915_capabilities)
+        goto failed;
+
+      g_variant_builder_init (&i915_builder, G_VARIANT_TYPE ("a{sv}"));
+
+      g_variant_builder_add (&i915_builder, "{sv}",
+                             "capabilities",
+                             g_variant_new_variant (i915_capabilities));
+
+      g_variant_builder_add (&builder, "{sv}",
+                             "i915",
+                             g_variant_new_variant (g_variant_builder_end (&i915_builder)));
+    }
+
+  return g_variant_builder_end (&builder);
+
+ failed:
+  g_variant_builder_clear (&builder);
+  return NULL;
+}
+
+static gboolean
+i915_gpu_snapshot (GVariantBuilder *builder,
+                   GError         **error)
+{
+  char *contents;
+  GMatchInfo *match;
+
+  contents = talos_util_build_filename_get_utf8_contents_sync (error, gpudir, "i915_gem_objects", NULL);
+  if (!contents)
+    return FALSE;
+  
+  if (g_regex_match (i915_gem_objects_regex, contents, 0, &match))
+    {
+      char *count;
+      
+      count = g_match_info_fetch (match, 1);
+      g_variant_builder_add (builder, "{sv}",
+                             "gem-object-count",
+                             g_variant_new_int64 (g_ascii_strtoll (count, NULL, 10)));
+      g_free (count);
+      count = g_match_info_fetch (match, 2);
+      g_variant_builder_add (builder, "{sv}",
+                             "gem-object-bytes",
+                             g_variant_new_int64 (g_ascii_strtoll (count, NULL, 10)));
+      g_free (count);
+      g_match_info_free (match);
+    }
+
+  return TRUE;
+}
+
+GVariant *
+gnome_talos_acquire_gpu_snapshot (GError **error)
+{
+  GVariantBuilder builder;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+  if (is_i915)
+    {
+      GVariantBuilder i915_builder;
+
+      g_variant_builder_init (&i915_builder, G_VARIANT_TYPE ("a{sv}"));
+
+      if (!i915_gpu_snapshot (&i915_builder, error))
+        {
+          g_variant_builder_clear (&i915_builder);
+          goto failed;
+        }
+
+      g_variant_builder_add (&builder, "{sv}",
+                             "i915",
+                             g_variant_new_variant (g_variant_builder_end (&i915_builder)));
+    }
+
+  return g_variant_builder_end (&builder);
+  
+ failed:
+  g_variant_builder_clear (&builder);
+  return NULL;
+}
diff --git a/src/gnome-talos-gpu.h b/src/gnome-talos-gpu.h
new file mode 100644
index 0000000..8ebf9c5
--- /dev/null
+++ b/src/gnome-talos-gpu.h
@@ -0,0 +1,29 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#ifndef __GNOME_TALOS_GPU__
+#define __GNOME_TALOS_GPU__ 1
+
+GVariant * gnome_talos_acquire_gpu_meta (GError **error);
+
+GVariant * gnome_talos_acquire_gpu_snapshot (GError **error);
+
+#endif
diff --git a/src/gnome-talos-meta.c b/src/gnome-talos-meta.c
index 37b1ab9..ed003cc 100644
--- a/src/gnome-talos-meta.c
+++ b/src/gnome-talos-meta.c
@@ -23,6 +23,8 @@
 
 #include <gio/gio.h>
 
+#include "gnome-talos-meta.h"
+
 #include <string.h>
 
 GVariant *
diff --git a/src/gnome-talos.c b/src/gnome-talos.c
index d3667a9..656dc2d 100644
--- a/src/gnome-talos.c
+++ b/src/gnome-talos.c
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include "gnome-talos-procinfo.h"
+#include "gnome-talos-gpu.h"
 #include "gnome-talos-meta.h"
 
 #include "report.html.h"
@@ -48,17 +49,22 @@ static gint timeout = 5;
 static char *log_file_path = NULL;
 static char *to_html_file_path = NULL;
 
-GVariant *
+static GVariant *
 gather_snapshot (void)
 {
+  GError *error = NULL;
   gint64 start_timestamp, end_timestamp;
   GVariant *proc_data;
+  GVariant *gpu_data;
   GVariantBuilder builder;
   GVariant *data;
 
   start_timestamp = g_get_monotonic_time ();
 
   proc_data = gnome_talos_acquire_procinfo ();
+  gpu_data = gnome_talos_acquire_gpu_snapshot (&error);
+  if (gpu_data == NULL)
+    fatal_gerror (&error);
 
   end_timestamp = g_get_monotonic_time ();
 
@@ -78,6 +84,7 @@ gather_snapshot (void)
   g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
 
   g_variant_builder_add (&builder, "{sv}", "processes", proc_data);
+  g_variant_builder_add (&builder, "{sv}", "gpu", gpu_data);
 
   g_variant_builder_close (&builder);
 
@@ -149,6 +156,8 @@ on_interrupt_received (gpointer user_data)
     fatal_gerror (&error);
   
   g_main_loop_quit (app->loop);
+
+  return FALSE;
 }
 
 static void
@@ -156,13 +165,14 @@ run_collection (GnomeTalosApp *app)
 {
   GError *error = NULL;
   GVariant *sysinfo;
+  GVariant *gpu_meta;
 
   g_unix_signal_add (SIGINT,
                      on_interrupt_received,
-                     &app);
+                     app);
   g_unix_signal_add (SIGTERM,
                      on_interrupt_received,
-                     &app);
+                     app);
 
   app->out = g_file_replace (app->log_file, NULL, FALSE,
                              G_FILE_CREATE_REPLACE_DESTINATION,
@@ -179,11 +189,18 @@ run_collection (GnomeTalosApp *app)
     fatal_gerror (&error);
   g_variant_unref (sysinfo);
 
+  gpu_meta = gnome_talos_acquire_gpu_meta (&error);
+  if (!gpu_meta)
+    fatal_gerror (&error);
+  if (!write_variant (gpu_meta, NULL, (GOutputStream*)app->out, &error))
+    fatal_gerror (&error);
+  g_variant_unref (gpu_meta);
+
   if (!g_output_stream_write_all ((GOutputStream*)app->out,
                                   ",\n", 2, NULL, NULL, &error))
     fatal_gerror (&error);
 
-  g_idle_add (timeout_gather_data, &app);
+  g_idle_add (timeout_gather_data, app);
 }
 
 static char *
@@ -222,7 +239,6 @@ convert_to_html (GnomeTalosApp *app)
   GFileOutputStream *out;
   char *data_string;
   char *buf;
-  GRegex *regex;
 
   parser = json_parser_new ();
 
diff --git a/src/util.c b/src/util.c
index a37c10f..c61894a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -19,10 +19,134 @@
  * Author: Colin Walters <walters verbum org>
  */
 
+#include "config.h"
+
+#include "util.h"
+
+#include <gio/gio.h>
+
+#include <string.h>
+
 char *
-gnome_talos_util_build_filenamea (const char *name,
-				  ...)
+talos_util_build_filename_get_utf8_contents_sync (GError **error,
+                                                  const char *filename,
+                                                  ...)
 {
+  GPtrArray *filenames;
+  va_list args;
+  char *full_filename;
+  char *content;
+
+  va_start (args, filename);
+
+  filenames = g_ptr_array_new ();
+  g_ptr_array_add (filenames, (char*)filename);
+
+  while ((filename = va_arg (args, const char*)) != NULL)
+    g_ptr_array_add (filenames, (char*)filename);
   
+  g_ptr_array_add (filenames, NULL);
+  full_filename = g_build_filenamev ((char**)filenames->pdata);
+
+  g_ptr_array_free (filenames, TRUE);
 
+  va_end (args);
+  
+  content = talos_util_get_file_contents_utf8_sync (full_filename, error);
+
+  g_free (full_filename);
+  
+  return content;
 }
+
+/**
+ * talos_util_get_file_contents_utf8_sync:
+ * @path: UTF-8 encoded filename path
+ * @error: a #GError
+ *
+ * Synchronously load the contents of a file as a NUL terminated
+ * string, validating it as UTF-8.  Embedded NUL characters count as
+ * invalid content.
+ *
+ * Returns: (transfer full): File contents
+ */
+char *
+talos_util_get_file_contents_utf8_sync (const char *path,
+                                        GError    **error)
+{
+  char *contents;
+  gsize len;
+  if (!g_file_get_contents (path, &contents, &len, error))
+    return NULL;
+  if (!g_utf8_validate (contents, len, NULL))
+    {
+      g_free (contents);
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "File %s contains invalid UTF-8",
+                   path);
+      return NULL;
+    }
+  return contents;
+}
+
+GVariant *
+talos_util_rfc822_file_to_variant (const char *path,
+                                   GError    **error)
+{
+  GVariantBuilder builder;
+  GVariant *res = NULL;
+  GFile *file;
+  GFileInputStream *in = NULL;
+  GDataInputStream *datain = NULL;
+  char *line = NULL;
+  GError *temp_error = NULL;
+
+  file = g_file_new_for_path (path);
+  in = g_file_read (file, NULL, error);
+  g_object_unref (file);
+  if (!in)
+    return NULL;
+  datain = g_data_input_stream_new ((GInputStream*)in);
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+  while ((line = g_data_input_stream_read_line_utf8 (datain, NULL, NULL, &temp_error)) != NULL)
+    {
+      char *colon;
+      colon = strchr (line, ':');
+      if (colon)
+        {
+          char *key;
+          char *value;
+
+          key = line;
+          *colon = '\0';
+          value = colon + 1;
+          g_strstrip (key);
+          g_strstrip (value);
+
+          g_variant_builder_add (&builder, "{sv}",
+                                 key, g_variant_new_string (value));
+        }
+      g_free (line);
+      line = NULL;
+    }
+
+  if (temp_error != NULL)
+    {
+      g_free (line);
+      g_variant_builder_clear (&builder);
+      g_propagate_error (error, temp_error);
+      goto out;
+    }
+  else
+    res = g_variant_builder_end (&builder);
+
+ out:
+  g_object_unref (in);
+  g_object_unref (datain);
+  return res;
+}
+
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..befd426
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,40 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#ifndef __GNOME_TALOS_UTIL__
+#define __GNOME_TALOS_UTIL__ 1
+
+#include <glib.h>
+
+char *
+talos_util_build_filename_get_utf8_contents_sync (GError **error,
+						  const char *arg0,
+						  ...) G_GNUC_NULL_TERMINATED;
+
+char *
+talos_util_get_file_contents_utf8_sync (const char *path,
+                                        GError    **error);
+
+GVariant *
+talos_util_rfc822_file_to_variant (const char *path,
+                                   GError    **error);
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]