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



commit f7527842fbffaf422b0a4b09be6715e833c5762b
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jun 3 14:10:26 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   | 33 +++++++++++++++++++++++++++++----
 gjs/profiler.h     |  2 ++
 test/gjs-tests.cpp |  1 +
 4 files changed, 52 insertions(+), 4 deletions(-)
---
diff --git a/gjs/console.cpp b/gjs/console.cpp
index 4f876153..2f813c7c 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -281,10 +281,21 @@ 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 */
+    const char* env_tracefd = g_getenv("GJS_TRACE_FD");
+    int tracefd = -1;
+    if (env_tracefd) {
+        tracefd = g_ascii_strtoll(env_tracefd, nullptr, 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;
         g_unsetenv("GJS_ENABLE_PROFILER");  /* ignore env var in eval() */
+        g_unsetenv("GJS_TRACE_FD");         /* ignore env var in eval() */
     }
 
     js_context = (GjsContext*) g_object_new(GJS_TYPE_CONTEXT,
@@ -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 a6883aaf..7a1f5e3d 100644
--- a/gjs/profiler.cpp
+++ b/gjs/profiler.cpp
@@ -28,6 +28,7 @@
 #include <memory>
 #include <signal.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include "jsapi-wrapper.h"
 #include <js/ProfilingStack.h>
@@ -101,6 +102,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;
@@ -219,6 +223,7 @@ _gjs_profiler_new(GjsContext *context)
     self->cx = static_cast<JSContext *>(gjs_context_get_native_context(context));
     self->pid = getpid();
 #endif
+    self->fd = -1;
 
     profiling_context = context;
 
@@ -245,6 +250,9 @@ _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, sysprof_capture_writer_unref);
@@ -402,11 +410,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 = sysprof_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 = sysprof_capture_writer_new(path, 0);
+        self->capture = sysprof_capture_writer_new(path, 0);
+    }
 
     if (!self->capture) {
         g_warning("Failed to open profile capture");
@@ -652,3 +665,15 @@ void _gjs_profiler_add_mark(GjsProfiler* self, gint64 time_nsec,
                                         duration_nsec, group, name, message);
     }
 }
+
+void gjs_profiler_set_fd(GjsProfiler* self, int fd) {
+    g_return_if_fail(self);
+    g_return_if_fail(!self->filename);
+    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..95615bd4 100644
--- a/gjs/profiler.h
+++ b/gjs/profiler.h
@@ -40,6 +40,8 @@ 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);
diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp
index d438b615..4ab3f8d6 100644
--- a/test/gjs-tests.cpp
+++ b/test/gjs-tests.cpp
@@ -391,6 +391,7 @@ main(int    argc,
 {
     /* Avoid interference in the tests from stray environment variable */
     g_unsetenv("GJS_ENABLE_PROFILER");
+    g_unsetenv("GJS_TRACE_FD");
 
     g_test_init(&argc, &argv, NULL);
 


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