mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-11 15:40:53 +00:00
libsysprof: implement follow fork instead of tracking spawnable
This commit is contained in:
@ -22,18 +22,70 @@
|
|||||||
|
|
||||||
#include <libdex.h>
|
#include <libdex.h>
|
||||||
|
|
||||||
#include "sysprof-instrument.h"
|
#include "sysprof-diagnostic-private.h"
|
||||||
|
#include "sysprof-instrument-private.h"
|
||||||
#include "sysprof-recording.h"
|
#include "sysprof-recording.h"
|
||||||
#include "sysprof-spawnable.h"
|
#include "sysprof-spawnable.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef enum _SysprofRecordingCommand
|
||||||
|
{
|
||||||
|
SYSPROF_RECORDING_COMMAND_STOP = 1,
|
||||||
|
} SysprofRecordingCommand;
|
||||||
|
|
||||||
|
struct _SysprofRecording
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
/* Used to calculate the duration of the recording */
|
||||||
|
gint64 start_time;
|
||||||
|
gint64 end_time;
|
||||||
|
|
||||||
|
/* Used to calculate event count */
|
||||||
|
SysprofCaptureStat stat;
|
||||||
|
|
||||||
|
/* Diagnostics that may be added by instruments during the recording.
|
||||||
|
* Some may be fatal, meaning that they stop the recording when the
|
||||||
|
* diagnostic is submitted. That can happen in situations like
|
||||||
|
* miss-configuration or failed authorization.
|
||||||
|
*/
|
||||||
|
GListStore *diagnostics;
|
||||||
|
|
||||||
|
/* If we are spawning a process as part of this recording, this
|
||||||
|
* is the SysprofSpawnable used to spawn the process.
|
||||||
|
*/
|
||||||
|
SysprofSpawnable *spawnable;
|
||||||
|
|
||||||
|
/* This is where all of the instruments will write to. They are
|
||||||
|
* expected to do this from the main-thread only. To work from
|
||||||
|
* additional threads they need to proxy that state to the
|
||||||
|
* main thread for writing.
|
||||||
|
*/
|
||||||
|
SysprofCaptureWriter *writer;
|
||||||
|
|
||||||
|
/* An array of SysprofInstrument that are part of this recording */
|
||||||
|
GPtrArray *instruments;
|
||||||
|
|
||||||
|
/* A DexFiber that will complete when the recording has finished,
|
||||||
|
* been stopped, or failed.
|
||||||
|
*/
|
||||||
|
DexFuture *fiber;
|
||||||
|
|
||||||
|
/* The channel is used ot send state change messages to the fiber
|
||||||
|
* from outside of the fiber.
|
||||||
|
*/
|
||||||
|
DexChannel *channel;
|
||||||
|
|
||||||
|
/* The process we have spawned, if any */
|
||||||
|
GSubprocess *subprocess;
|
||||||
|
};
|
||||||
|
|
||||||
SysprofRecording *_sysprof_recording_new (SysprofCaptureWriter *writer,
|
SysprofRecording *_sysprof_recording_new (SysprofCaptureWriter *writer,
|
||||||
SysprofSpawnable *spawnable,
|
SysprofSpawnable *spawnable,
|
||||||
SysprofInstrument **instruments,
|
SysprofInstrument **instruments,
|
||||||
guint n_instruments);
|
guint n_instruments);
|
||||||
void _sysprof_recording_start (SysprofRecording *self);
|
void _sysprof_recording_start (SysprofRecording *self);
|
||||||
SysprofCaptureWriter *_sysprof_recording_writer (SysprofRecording *self);
|
|
||||||
SysprofSpawnable *_sysprof_recording_get_spawnable (SysprofRecording *self);
|
SysprofSpawnable *_sysprof_recording_get_spawnable (SysprofRecording *self);
|
||||||
DexFuture *_sysprof_recording_add_file (SysprofRecording *self,
|
DexFuture *_sysprof_recording_add_file (SysprofRecording *self,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -43,6 +95,8 @@ void _sysprof_recording_add_file_data (SysprofRecording *s
|
|||||||
const char *contents,
|
const char *contents,
|
||||||
gssize length,
|
gssize length,
|
||||||
gboolean compress);
|
gboolean compress);
|
||||||
|
void _sysprof_recording_follow_fork (SysprofRecording *self,
|
||||||
|
int pid);
|
||||||
void _sysprof_recording_diagnostic (SysprofRecording *self,
|
void _sysprof_recording_diagnostic (SysprofRecording *self,
|
||||||
const char *domain,
|
const char *domain,
|
||||||
const char *format,
|
const char *format,
|
||||||
@ -52,4 +106,10 @@ void _sysprof_recording_error (SysprofRecording *s
|
|||||||
const char *format,
|
const char *format,
|
||||||
...) G_GNUC_PRINTF (3, 4);
|
...) G_GNUC_PRINTF (3, 4);
|
||||||
|
|
||||||
|
static inline SysprofCaptureWriter *
|
||||||
|
_sysprof_recording_writer (const SysprofRecording *self)
|
||||||
|
{
|
||||||
|
return self->writer;
|
||||||
|
}
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|||||||
@ -26,62 +26,8 @@
|
|||||||
|
|
||||||
#include <libdex.h>
|
#include <libdex.h>
|
||||||
|
|
||||||
#include "sysprof-diagnostic-private.h"
|
|
||||||
#include "sysprof-instrument-private.h"
|
|
||||||
#include "sysprof-recording-private.h"
|
#include "sysprof-recording-private.h"
|
||||||
|
|
||||||
typedef enum _SysprofRecordingCommand
|
|
||||||
{
|
|
||||||
SYSPROF_RECORDING_COMMAND_STOP = 1,
|
|
||||||
} SysprofRecordingCommand;
|
|
||||||
|
|
||||||
struct _SysprofRecording
|
|
||||||
{
|
|
||||||
GObject parent_instance;
|
|
||||||
|
|
||||||
/* Used to calculate the duration of the recording */
|
|
||||||
gint64 start_time;
|
|
||||||
gint64 end_time;
|
|
||||||
|
|
||||||
/* Used to calculate event count */
|
|
||||||
SysprofCaptureStat stat;
|
|
||||||
|
|
||||||
/* Diagnostics that may be added by instruments during the recording.
|
|
||||||
* Some may be fatal, meaning that they stop the recording when the
|
|
||||||
* diagnostic is submitted. That can happen in situations like
|
|
||||||
* miss-configuration or failed authorization.
|
|
||||||
*/
|
|
||||||
GListStore *diagnostics;
|
|
||||||
|
|
||||||
/* If we are spawning a process as part of this recording, this
|
|
||||||
* is the SysprofSpawnable used to spawn the process.
|
|
||||||
*/
|
|
||||||
SysprofSpawnable *spawnable;
|
|
||||||
|
|
||||||
/* This is where all of the instruments will write to. They are
|
|
||||||
* expected to do this from the main-thread only. To work from
|
|
||||||
* additional threads they need to proxy that state to the
|
|
||||||
* main thread for writing.
|
|
||||||
*/
|
|
||||||
SysprofCaptureWriter *writer;
|
|
||||||
|
|
||||||
/* An array of SysprofInstrument that are part of this recording */
|
|
||||||
GPtrArray *instruments;
|
|
||||||
|
|
||||||
/* A DexFiber that will complete when the recording has finished,
|
|
||||||
* been stopped, or failed.
|
|
||||||
*/
|
|
||||||
DexFuture *fiber;
|
|
||||||
|
|
||||||
/* The channel is used ot send state change messages to the fiber
|
|
||||||
* from outside of the fiber.
|
|
||||||
*/
|
|
||||||
DexChannel *channel;
|
|
||||||
|
|
||||||
/* The process we have spawned, if any */
|
|
||||||
GSubprocess *subprocess;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_DURATION,
|
PROP_DURATION,
|
||||||
@ -94,12 +40,10 @@ G_DEFINE_FINAL_TYPE (SysprofRecording, sysprof_recording, G_TYPE_OBJECT)
|
|||||||
static GParamSpec *properties[N_PROPS];
|
static GParamSpec *properties[N_PROPS];
|
||||||
|
|
||||||
static DexFuture *
|
static DexFuture *
|
||||||
_sysprof_recording_spawn (SysprofRecording *self,
|
_sysprof_recording_spawn (SysprofSpawnable *spawnable,
|
||||||
SysprofSpawnable *spawnable,
|
|
||||||
GSubprocess **subprocess)
|
GSubprocess **subprocess)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
const char *identifier;
|
|
||||||
DexFuture *ret;
|
DexFuture *ret;
|
||||||
|
|
||||||
g_assert (SYSPROF_IS_SPAWNABLE (spawnable));
|
g_assert (SYSPROF_IS_SPAWNABLE (spawnable));
|
||||||
@ -109,12 +53,6 @@ _sysprof_recording_spawn (SysprofRecording *self,
|
|||||||
if (!(*subprocess = sysprof_spawnable_spawn (spawnable, &error)))
|
if (!(*subprocess = sysprof_spawnable_spawn (spawnable, &error)))
|
||||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||||
|
|
||||||
if ((identifier = g_subprocess_get_identifier (*subprocess)))
|
|
||||||
{
|
|
||||||
int pid = atoi (identifier);
|
|
||||||
dex_await (_sysprof_instruments_process_started (self->instruments, self, pid), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dex_subprocess_wait_check (*subprocess);
|
ret = dex_subprocess_wait_check (*subprocess);
|
||||||
dex_async_pair_set_cancel_on_discard (DEX_ASYNC_PAIR (ret), FALSE);
|
dex_async_pair_set_cancel_on_discard (DEX_ASYNC_PAIR (ret), FALSE);
|
||||||
return ret;
|
return ret;
|
||||||
@ -197,7 +135,7 @@ sysprof_recording_fiber (gpointer user_data)
|
|||||||
|
|
||||||
/* If we need to spawn a subprocess, do it now */
|
/* If we need to spawn a subprocess, do it now */
|
||||||
if (self->spawnable != NULL)
|
if (self->spawnable != NULL)
|
||||||
monitor = _sysprof_recording_spawn (self, self->spawnable, &self->subprocess);
|
monitor = _sysprof_recording_spawn (self->spawnable, &self->subprocess);
|
||||||
else
|
else
|
||||||
monitor = dex_future_new_infinite ();
|
monitor = dex_future_new_infinite ();
|
||||||
|
|
||||||
@ -564,14 +502,6 @@ _sysprof_recording_get_spawnable (SysprofRecording *self)
|
|||||||
return self->spawnable;
|
return self->spawnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
SysprofCaptureWriter *
|
|
||||||
_sysprof_recording_writer (SysprofRecording *self)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (self), NULL);
|
|
||||||
|
|
||||||
return self->writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _AddFile
|
typedef struct _AddFile
|
||||||
{
|
{
|
||||||
SysprofCaptureWriter *writer;
|
SysprofCaptureWriter *writer;
|
||||||
@ -966,3 +896,13 @@ sysprof_recording_get_subprocess (SysprofRecording *self)
|
|||||||
|
|
||||||
return self->subprocess;
|
return self->subprocess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_sysprof_recording_follow_fork (SysprofRecording *self,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
g_return_if_fail (SYSPROF_IS_RECORDING (self));
|
||||||
|
g_return_if_fail (pid > 0);
|
||||||
|
|
||||||
|
dex_future_disown (_sysprof_instruments_process_started (self->instruments, self, pid));
|
||||||
|
}
|
||||||
|
|||||||
@ -105,7 +105,8 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event,
|
|||||||
guint cpu,
|
guint cpu,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
SysprofCaptureWriter *writer = user_data;
|
SysprofRecording *recording = user_data;
|
||||||
|
SysprofCaptureWriter *writer = _sysprof_recording_writer (recording);
|
||||||
gsize offset;
|
gsize offset;
|
||||||
gint64 time;
|
gint64 time;
|
||||||
|
|
||||||
@ -148,10 +149,7 @@ sysprof_sampler_perf_event_stream_cb (const SysprofPerfEvent *event,
|
|||||||
event->fork.ptid,
|
event->fork.ptid,
|
||||||
event->fork.tid);
|
event->fork.tid);
|
||||||
|
|
||||||
/*
|
_sysprof_recording_follow_fork (recording, event->fork.tid);
|
||||||
* TODO: We should add support for "follow fork" of the GPid if we are
|
|
||||||
* targetting it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -248,7 +246,6 @@ static DexFuture *
|
|||||||
sysprof_sampler_prepare_fiber (gpointer user_data)
|
sysprof_sampler_prepare_fiber (gpointer user_data)
|
||||||
{
|
{
|
||||||
Prepare *prepare = user_data;
|
Prepare *prepare = user_data;
|
||||||
SysprofCaptureWriter *writer;
|
|
||||||
g_autoptr(GDBusConnection) connection = NULL;
|
g_autoptr(GDBusConnection) connection = NULL;
|
||||||
g_autoptr(GPtrArray) futures = NULL;
|
g_autoptr(GPtrArray) futures = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
@ -290,7 +287,6 @@ sysprof_sampler_prepare_fiber (gpointer user_data)
|
|||||||
*/
|
*/
|
||||||
n_cpu = g_get_num_processors ();
|
n_cpu = g_get_num_processors ();
|
||||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||||
writer = _sysprof_recording_writer (prepare->recording);
|
|
||||||
|
|
||||||
try_again:
|
try_again:
|
||||||
attr.sample_type = PERF_SAMPLE_IP
|
attr.sample_type = PERF_SAMPLE_IP
|
||||||
@ -332,8 +328,8 @@ try_again:
|
|||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
sysprof_sampler_perf_event_stream_cb,
|
sysprof_sampler_perf_event_stream_cb,
|
||||||
sysprof_capture_writer_ref (writer),
|
g_object_ref (prepare->recording),
|
||||||
(GDestroyNotify)sysprof_capture_writer_unref));
|
g_object_unref));
|
||||||
|
|
||||||
if (!dex_await (dex_future_allv ((DexFuture **)futures->pdata, futures->len), &error))
|
if (!dex_await (dex_future_allv ((DexFuture **)futures->pdata, futures->len), &error))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user