mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof-profile: add API to append a file to recording
This commit is contained in:
@ -20,6 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libdex.h>
|
||||
|
||||
#include "sysprof-instrument.h"
|
||||
#include "sysprof-recording.h"
|
||||
#include "sysprof-spawnable.h"
|
||||
@ -32,5 +34,8 @@ SysprofRecording *_sysprof_recording_new (SysprofCaptureWriter *w
|
||||
void _sysprof_recording_start (SysprofRecording *self);
|
||||
SysprofCaptureWriter *_sysprof_recording_writer (SysprofRecording *self);
|
||||
SysprofSpawnable *_sysprof_recording_get_spawnable (SysprofRecording *self);
|
||||
DexFuture *_sysprof_recording_add_file (SysprofRecording *self,
|
||||
const char *path,
|
||||
gboolean compress);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@ -296,3 +296,140 @@ _sysprof_recording_writer (SysprofRecording *self)
|
||||
|
||||
return self->writer;
|
||||
}
|
||||
|
||||
typedef struct _AddFile
|
||||
{
|
||||
SysprofCaptureWriter *writer;
|
||||
char *path;
|
||||
guint compress : 1;
|
||||
} AddFile;
|
||||
|
||||
static void
|
||||
add_file_free (AddFile *add_file)
|
||||
{
|
||||
g_clear_pointer (&add_file->writer, sysprof_capture_writer_unref);
|
||||
g_clear_pointer (&add_file->path, g_free);
|
||||
g_free (add_file);
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
sysprof_recording_add_file_fiber (gpointer user_data)
|
||||
{
|
||||
AddFile *add_file = user_data;
|
||||
g_autoptr(GInputStream) input = NULL;
|
||||
g_autoptr(GOutputStream) memory_stream = NULL;
|
||||
g_autoptr(GOutputStream) zlib_stream = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autoptr(GFile) proc = NULL;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
g_autofree char *dest_path = NULL;
|
||||
const guint8 *data = NULL;
|
||||
GOutputStream *output;
|
||||
gsize len;
|
||||
|
||||
g_assert (add_file != NULL);
|
||||
g_assert (add_file->path != NULL);
|
||||
g_assert (add_file->writer != NULL);
|
||||
|
||||
/* If we are compressing the file, store it as ".gz" in the capture
|
||||
* so that the reader knows to decompress it automatically.
|
||||
*/
|
||||
dest_path = add_file->compress ? g_strdup_printf ("%s.gz", add_file->path)
|
||||
: g_strdup (add_file->path);
|
||||
|
||||
file = g_file_new_for_path (add_file->path);
|
||||
proc = g_file_new_for_path ("/proc");
|
||||
|
||||
/* If the file has a prefix of `/proc/` then we need to request the
|
||||
* file from sysprofd as our user is not guaranteed to be able to
|
||||
* read the file. Even if we can open the file, we may get data that
|
||||
* has been redacted (such as /proc/kallsyms).
|
||||
*
|
||||
* With `/proc/kallsyms` it's even worse in that if we get an FD back
|
||||
* from sysprofd and read it from our process, it *too* will be redacted.
|
||||
* That leaves us with the only option of letting sysprofd read the file
|
||||
* and transfer the contents to our process over D-Bus.
|
||||
*
|
||||
* We use g_file_has_prefix() for this as it will canonicalize the paths
|
||||
* of #GFile rather than us having to be careful here.
|
||||
*/
|
||||
//if (g_file_has_prefix (file, proc))
|
||||
//{
|
||||
//}
|
||||
//else
|
||||
{
|
||||
if (!(input = dex_await_object (dex_file_read (file, 0), &error)))
|
||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||
}
|
||||
|
||||
g_assert (input != NULL);
|
||||
g_assert (G_IS_INPUT_STREAM (input));
|
||||
|
||||
output = memory_stream = g_memory_output_stream_new_resizable ();
|
||||
|
||||
if (add_file->compress)
|
||||
{
|
||||
g_autoptr(GZlibCompressor) compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, 6);
|
||||
output = zlib_stream = g_converter_output_stream_new (memory_stream, G_CONVERTER (compressor));
|
||||
}
|
||||
|
||||
g_assert (output != NULL);
|
||||
g_assert (G_IS_OUTPUT_STREAM (output));
|
||||
g_assert (G_IS_MEMORY_OUTPUT_STREAM (output) || G_IS_CONVERTER_OUTPUT_STREAM (output));
|
||||
g_assert (G_IS_MEMORY_OUTPUT_STREAM (memory_stream));
|
||||
g_assert (!zlib_stream || G_IS_CONVERTER_OUTPUT_STREAM (zlib_stream));
|
||||
|
||||
if (!dex_await (dex_output_stream_splice (output,
|
||||
input,
|
||||
(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
|
||||
0),
|
||||
&error))
|
||||
return dex_future_new_for_error (g_steal_pointer (&error));
|
||||
|
||||
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (memory_stream));
|
||||
data = g_bytes_get_data (bytes, &len);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
gsize to_write = MIN (len, 4096*8);
|
||||
|
||||
if (!sysprof_capture_writer_add_file (add_file->writer,
|
||||
SYSPROF_CAPTURE_CURRENT_TIME,
|
||||
-1,
|
||||
-1,
|
||||
dest_path,
|
||||
to_write == len,
|
||||
data,
|
||||
to_write))
|
||||
break;
|
||||
|
||||
len -= to_write;
|
||||
data += to_write;
|
||||
}
|
||||
|
||||
return dex_future_new_for_boolean (TRUE);
|
||||
}
|
||||
|
||||
DexFuture *
|
||||
_sysprof_recording_add_file (SysprofRecording *self,
|
||||
const char *path,
|
||||
gboolean compress)
|
||||
{
|
||||
g_autoptr(GFile) file = NULL;
|
||||
AddFile *add_file;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_RECORDING (self), NULL);
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
|
||||
add_file = g_new0 (AddFile, 1);
|
||||
add_file->writer = sysprof_capture_writer_ref (self->writer);
|
||||
add_file->path = g_strdup (path);
|
||||
add_file->compress = !!compress;
|
||||
|
||||
return dex_scheduler_spawn (NULL, 0,
|
||||
sysprof_recording_add_file_fiber,
|
||||
g_steal_pointer (&add_file),
|
||||
(GDestroyNotify)add_file_free);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user