diff options
author | Philip Chimento <philip.chimento@gmail.com> | 2019-06-07 20:32:56 +0000 |
---|---|---|
committer | Philip Chimento <philip.chimento@gmail.com> | 2019-06-07 20:32:56 +0000 |
commit | 9bdbf2f297ba899a1329cac9b6f7c0e4c79fbfff (patch) | |
tree | c503c0bcd1f7f107bd73cecca7730e474970c295 /gjs | |
parent | 4eb8a82aff41d5ce75d1a22b3041911bf7f0c6b2 (diff) | |
parent | 0218b1232da179adf230b5bd09dcfdc2baf7f1d5 (diff) | |
download | gjs-9bdbf2f297ba899a1329cac9b6f7c0e4c79fbfff.tar.gz |
Merge branch 'wip/chergert/sysprof-3' into 'master'
Add support for GJS_TRACE_FD
See merge request GNOME/gjs!295
Diffstat (limited to 'gjs')
-rw-r--r-- | gjs/console.cpp | 20 | ||||
-rw-r--r-- | gjs/context-private.h | 5 | ||||
-rw-r--r-- | gjs/context.cpp | 20 | ||||
-rw-r--r-- | gjs/profiler-private.h | 4 | ||||
-rw-r--r-- | gjs/profiler.cpp | 89 | ||||
-rw-r--r-- | gjs/profiler.h | 2 |
6 files changed, 120 insertions, 20 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/context-private.h b/gjs/context-private.h index 10dcf688..274352fa 100644 --- a/gjs/context-private.h +++ b/gjs/context-private.h @@ -117,6 +117,8 @@ class GjsContextPrivate { bool m_should_profile : 1; bool m_should_listen_sigusr2 : 1; + int64_t m_sweep_begin_time; + void schedule_gc_internal(bool force_gc); static gboolean trigger_gc_if_needed(void* data); static gboolean drain_job_queue_idle_handler(void* data); @@ -148,7 +150,6 @@ class GjsContextPrivate { GJS_USE const GjsAtoms& atoms(void) const { return m_atoms; } GJS_USE bool destroying(void) const { return m_destroying; } GJS_USE bool sweeping(void) const { return m_in_gc_sweep; } - void set_sweeping(bool value) { m_in_gc_sweep = value; } GJS_USE const char* program_name(void) const { return m_program_name; } void set_program_name(char* value) { m_program_name = value; } void set_search_path(char** value) { m_search_path = value; } @@ -194,6 +195,8 @@ class GjsContextPrivate { void register_unhandled_promise_rejection(uint64_t id, GjsAutoChar&& stack); void unregister_unhandled_promise_rejection(uint64_t id); + void set_sweeping(bool value); + static void trace(JSTracer* trc, void* data); void free_profiler(void); diff --git a/gjs/context.cpp b/gjs/context.cpp index 0ac7fb68..6e2d54af 100644 --- a/gjs/context.cpp +++ b/gjs/context.cpp @@ -609,6 +609,26 @@ void GjsContextPrivate::schedule_gc_if_needed(void) { schedule_gc_internal(false); } +void GjsContextPrivate::set_sweeping(bool value) { + // If we have a profiler enabled, record the duration of GC sweep + if (this->m_profiler != nullptr) { + int64_t now = g_get_monotonic_time() * 1000L; + + if (value) { + m_sweep_begin_time = now; + } else { + if (m_sweep_begin_time != 0) { + _gjs_profiler_add_mark(this->m_profiler, m_sweep_begin_time, + now - m_sweep_begin_time, "GJS", "Sweep", + nullptr); + m_sweep_begin_time = 0; + } + } + } + + m_in_gc_sweep = value; +} + void GjsContextPrivate::exit(uint8_t exit_code) { g_assert(!m_should_exit); m_should_exit = true; diff --git a/gjs/profiler-private.h b/gjs/profiler-private.h index 20cb9f46..0697be25 100644 --- a/gjs/profiler-private.h +++ b/gjs/profiler-private.h @@ -33,6 +33,10 @@ G_BEGIN_DECLS GjsProfiler *_gjs_profiler_new(GjsContext *context); void _gjs_profiler_free(GjsProfiler *self); +void _gjs_profiler_add_mark(GjsProfiler* self, gint64 time, gint64 duration, + const char* group, const char* name, + const char* message); + GJS_USE bool _gjs_profiler_is_running(GjsProfiler *self); diff --git a/gjs/profiler.cpp b/gjs/profiler.cpp index d7ee03b5..55aa8916 100644 --- a/gjs/profiler.cpp +++ b/gjs/profiler.cpp @@ -47,9 +47,11 @@ # ifdef G_OS_UNIX # include <glib-unix.h> # endif -# include "util/sp-capture-writer.h" +# include <sysprof-capture.h> #endif +#define FLUSH_DELAY_SECONDS 3 + /* * This is mostly non-exciting code wrapping the builtin Profiler in * mozjs. In particular, the profiler consumer is required to "bring your @@ -95,12 +97,15 @@ struct _GjsProfiler { JSContext *cx; /* Buffers and writes our sampled stacks */ - SpCaptureWriter *capture; + SysprofCaptureWriter* capture; #endif /* ENABLE_PROFILER */ /* 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; @@ -166,8 +171,8 @@ gjs_profiler_extract_maps(GjsProfiler *self) inode = 0; } - if (!sp_capture_writer_add_map(self->capture, now, -1, self->pid, start, - end, offset, inode, file)) + if (!sysprof_capture_writer_add_map(self->capture, now, -1, self->pid, + start, end, offset, inode, file)) return false; } @@ -219,6 +224,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; @@ -247,7 +253,10 @@ _gjs_profiler_free(GjsProfiler *self) g_clear_pointer(&self->filename, g_free); #ifdef ENABLE_PROFILER - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); + + if (self->fd != -1) + close(self->fd); #endif g_free(self); } @@ -304,7 +313,8 @@ gjs_profiler_sigprof(int signum, * here since we are in a signal handler. */ // cppcheck-suppress allocaCalled - SpCaptureAddress *addrs = static_cast<SpCaptureAddress *>(alloca(sizeof *addrs * depth)); + SysprofCaptureAddress* addrs = + static_cast<SysprofCaptureAddress*>(alloca(sizeof *addrs * depth)); for (uint32_t ix = 0; ix < depth; ix++) { js::ProfileEntry& entry = self->stack.entries[ix]; @@ -360,12 +370,14 @@ gjs_profiler_sigprof(int signum, * everything will show up as [stack] when building callgraphs. */ if (final_string[0] != '\0') - addrs[flipped] = sp_capture_writer_add_jitmap(self->capture, final_string); + addrs[flipped] = + sysprof_capture_writer_add_jitmap(self->capture, final_string); else - addrs[flipped] = SpCaptureAddress(entry.stackAddress()); + addrs[flipped] = SysprofCaptureAddress(entry.stackAddress()); } - if (!sp_capture_writer_add_sample(self->capture, now, -1, self->pid, addrs, depth)) + if (!sysprof_capture_writer_add_sample(self->capture, now, -1, self->pid, + -1, addrs, depth)) gjs_profiler_stop(self); } @@ -402,20 +414,30 @@ 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 = sp_capture_writer_new(path, 0); + self->capture = sysprof_capture_writer_new(path, 0); + } if (!self->capture) { g_warning("Failed to open profile capture"); return; } + /* Automatically flush to be resilient against SIGINT, etc */ + sysprof_capture_writer_set_flush_delay(self->capture, + g_main_context_get_thread_default(), + FLUSH_DELAY_SECONDS); + if (!gjs_profiler_extract_maps(self)) { g_warning("Failed to extract proc maps"); - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); return; } @@ -426,7 +448,7 @@ gjs_profiler_start(GjsProfiler *self) if (sigaction(SIGPROF, &sa, nullptr) == -1) { g_warning("Failed to register sigaction handler: %s", g_strerror(errno)); - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); return; } @@ -446,7 +468,7 @@ gjs_profiler_start(GjsProfiler *self) if (timer_create(CLOCK_MONOTONIC, &sev, &self->timer) == -1) { g_warning("Failed to create profiler timer: %s", g_strerror(errno)); - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); return; } @@ -460,7 +482,7 @@ gjs_profiler_start(GjsProfiler *self) if (timer_settime(self->timer, 0, &its, &old_its) != 0) { g_warning("Failed to enable profiler timer: %s", g_strerror(errno)); timer_delete(self->timer); - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); return; } @@ -515,9 +537,9 @@ gjs_profiler_stop(GjsProfiler *self) js::EnableContextProfilingStack(self->cx, false); js::SetContextProfilingStack(self->cx, nullptr); - sp_capture_writer_flush(self->capture); + sysprof_capture_writer_flush(self->capture); - g_clear_pointer(&self->capture, sp_capture_writer_unref); + g_clear_pointer(&self->capture, sysprof_capture_writer_unref); g_message("Profiler stopped"); @@ -639,3 +661,32 @@ gjs_profiler_set_filename(GjsProfiler *self, g_free(self->filename); self->filename = g_strdup(filename); } + +void _gjs_profiler_add_mark(GjsProfiler* self, gint64 time_nsec, + gint64 duration_nsec, const char* group, + const char* name, const char* message) { + g_return_if_fail(self); + g_return_if_fail(group); + g_return_if_fail(name); + +#ifdef ENABLE_PROFILER + if (self->running && self->capture != nullptr) { + sysprof_capture_writer_add_mark(self->capture, time_nsec, -1, self->pid, + duration_nsec, group, name, message); + } +#endif +} + +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); + +#ifdef ENABLE_PROFILER + if (self->fd != fd) { + if (self->fd != -1) + close(self->fd); + self->fd = fd; + } +#endif +} 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); |