[gjs/wip/chergert/sysprof-3: 2/2] profiler: add support for GJS_TRACE_FD



commit 3ddb6bc6b36233794b1636f40225853e3e0409ea
Author: Christian Hergert <chergert redhat com>
Date:   Fri May 24 16:31:47 2019 -0700

    profiler: add support for GJS_TRACE_FD
    
    This commit adds support for a special environment variable GJS_TRACE_FD.
    The console will, in response to this environment variable, enable
    tracing of the GJS context and deliver the output to the provided file-
    descriptor.
    
    In the upcoming Sysprof-3 branch, this can be used to automatically sample
    some GJS-based applications. Applications that use libgjs from a C-based
    main() will need to implement the g_getenv() GJS_TRACE_FD manually.

 gjs/console.cpp  | 20 ++++++++++++++++++++
 gjs/profiler.cpp | 32 ++++++++++++++++++++++++++++----
 gjs/profiler.h   |  3 +++
 3 files changed, 51 insertions(+), 4 deletions(-)
---
diff --git a/gjs/console.cpp b/gjs/console.cpp
index 4f876153..d3e7f392 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -194,7 +194,9 @@ main(int argc, char **argv)
     char * const *script_argv;
     const char *env_coverage_output_path;
     const char *env_coverage_prefixes;
+    const char *env_tracefd;
     bool interactive_mode = false;
+    int tracefd = -1;
 
     setlocale(LC_ALL, "");
 
@@ -281,6 +283,15 @@ main(int argc, char **argv)
     /* This should be removed after a suitable time has passed */
     check_script_args_for_stray_gjs_args(script_argc, script_argv);
 
+    /* Check for GJS_TRACE_FD for sysprof profiling */
+    env_tracefd = g_getenv("GJS_TRACE_FD");
+    if (env_tracefd != NULL) {
+        tracefd = g_ascii_strtoll(env_tracefd, NULL, 10);
+        g_setenv("GJS_TRACE_FD", "", TRUE);
+        if (tracefd > 0)
+            enable_profiler = true;
+    }
+
     if (interactive_mode && enable_profiler) {
         g_message("Profiler disabled in interactive mode.");
         enable_profiler = false;
@@ -318,6 +329,15 @@ main(int argc, char **argv)
     if (enable_profiler && profile_output_path) {
         GjsProfiler *profiler = gjs_context_get_profiler(js_context);
         gjs_profiler_set_filename(profiler, profile_output_path);
+    } else if (enable_profiler && tracefd > -1) {
+        GjsProfiler *profiler = gjs_context_get_profiler(js_context);
+        gjs_profiler_set_fd(profiler, tracefd);
+        tracefd = -1;
+    }
+
+    if (tracefd != -1) {
+        close(tracefd);
+        tracefd = -1;
     }
 
     /* prepare command line arguments */
diff --git a/gjs/profiler.cpp b/gjs/profiler.cpp
index 6f37eaca..5f66df77 100644
--- a/gjs/profiler.cpp
+++ b/gjs/profiler.cpp
@@ -101,6 +101,9 @@ struct _GjsProfiler {
     /* The filename to write to */
     char *filename;
 
+    /* An FD to capture to */
+    int fd;
+
 #ifdef ENABLE_PROFILER
     /* Our POSIX timer to wakeup SIGPROF */
     timer_t timer;
@@ -245,6 +248,8 @@ _gjs_profiler_free(GjsProfiler *self)
 
     profiling_context = nullptr;
 
+    if (self->fd != -1)
+        close(self->fd);
     g_clear_pointer(&self->filename, g_free);
 #ifdef ENABLE_PROFILER
     g_clear_pointer(&self->capture, sp_capture_writer_unref);
@@ -399,11 +404,16 @@ gjs_profiler_start(GjsProfiler *self)
     struct itimerspec its = { 0 };
     struct itimerspec old_its;
 
-    GjsAutoChar path = g_strdup(self->filename);
-    if (!path)
-        path = g_strdup_printf("gjs-%jd.syscap", intmax_t(self->pid));
+    if (self->fd != -1) {
+        self->capture = sp_capture_writer_new_from_fd(self->fd, 0);
+        self->fd = -1;
+    } else {
+        GjsAutoChar path = g_strdup(self->filename);
+        if (!path)
+            path = g_strdup_printf("gjs-%jd.syscap", intmax_t(self->pid));
 
-    self->capture = sp_capture_writer_new(path, 0);
+        self->capture = sp_capture_writer_new(path, 0);
+    }
 
     if (!self->capture) {
         g_warning("Failed to open profile capture");
@@ -636,3 +646,17 @@ gjs_profiler_set_filename(GjsProfiler *self,
     g_free(self->filename);
     self->filename = g_strdup(filename);
 }
+
+void
+gjs_profiler_set_fd(GjsProfiler *self,
+                    int          fd)
+{
+    g_return_if_fail(self);
+    g_return_if_fail(!self->running);
+
+    if (self->fd != fd) {
+        if (self->fd != -1)
+            close(self->fd);
+        self->fd = fd;
+    }
+}
diff --git a/gjs/profiler.h b/gjs/profiler.h
index 8bebed25..c1a37def 100644
--- a/gjs/profiler.h
+++ b/gjs/profiler.h
@@ -40,6 +40,9 @@ GType gjs_profiler_get_type(void);
 GJS_EXPORT
 void gjs_profiler_set_filename(GjsProfiler *self,
                                const char  *filename);
+GJS_EXPORT
+void gjs_profiler_set_fd(GjsProfiler *self,
+                         int          fd);
 
 GJS_EXPORT
 void gjs_profiler_start(GjsProfiler *self);


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