mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-09 22:50:54 +00:00
Fake new_process and new_map events when a tracker is created
This commit is contained in:
46
collector.c
46
collector.c
@ -34,6 +34,7 @@
|
|||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "elfparser.h"
|
#include "elfparser.h"
|
||||||
|
#include "tracker.h"
|
||||||
|
|
||||||
#include "perf_counter.h"
|
#include "perf_counter.h"
|
||||||
#include "barrier.h"
|
#include "barrier.h"
|
||||||
@ -45,7 +46,6 @@ typedef struct sample_event_t sample_event_t;
|
|||||||
typedef struct mmap_event_t mmap_event_t;
|
typedef struct mmap_event_t mmap_event_t;
|
||||||
typedef struct comm_event_t comm_event_t;
|
typedef struct comm_event_t comm_event_t;
|
||||||
typedef union counter_event_t counter_event_t;
|
typedef union counter_event_t counter_event_t;
|
||||||
typedef void (* event_callback_t) (counter_event_t *event, gpointer data);
|
|
||||||
|
|
||||||
static void process_event (Collector *collector, counter_event_t *event);
|
static void process_event (Collector *collector, counter_event_t *event);
|
||||||
|
|
||||||
@ -103,6 +103,7 @@ struct Collector
|
|||||||
gpointer data;
|
gpointer data;
|
||||||
|
|
||||||
StackStash * stash;
|
StackStash * stash;
|
||||||
|
tracker_t * tracker;
|
||||||
GTimeVal latest_reset;
|
GTimeVal latest_reset;
|
||||||
|
|
||||||
int n_samples;
|
int n_samples;
|
||||||
@ -240,6 +241,10 @@ map_buffer (counter_t *counter)
|
|||||||
int n_bytes = N_PAGES * process_get_page_size();
|
int n_bytes = N_PAGES * process_get_page_size();
|
||||||
void *address, *a;
|
void *address, *a;
|
||||||
|
|
||||||
|
/* We use the old trick of mapping the ring buffer twice
|
||||||
|
* consecutively, so that we don't need special-case code
|
||||||
|
* to deal with wrapping.
|
||||||
|
*/
|
||||||
address = mmap (NULL, n_bytes * 2 + process_get_page_size(), PROT_NONE,
|
address = mmap (NULL, n_bytes * 2 + process_get_page_size(), PROT_NONE,
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
|
||||||
@ -281,7 +286,7 @@ counter_new (Collector *collector,
|
|||||||
attr.type = PERF_TYPE_HARDWARE;
|
attr.type = PERF_TYPE_HARDWARE;
|
||||||
attr.config = PERF_COUNT_HW_CPU_CYCLES;
|
attr.config = PERF_COUNT_HW_CPU_CYCLES;
|
||||||
attr.sample_period = 1200000 ; /* In number of clock cycles -
|
attr.sample_period = 1200000 ; /* In number of clock cycles -
|
||||||
* use frequency instead FIXME
|
* FIXME: consider using frequency instead
|
||||||
*/
|
*/
|
||||||
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_CALLCHAIN;
|
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_CALLCHAIN;
|
||||||
attr.wakeup_events = 100000;
|
attr.wakeup_events = 100000;
|
||||||
@ -343,15 +348,34 @@ counter_free (counter_t *counter)
|
|||||||
void
|
void
|
||||||
collector_reset (Collector *collector)
|
collector_reset (Collector *collector)
|
||||||
{
|
{
|
||||||
if (collector->stash)
|
gboolean restart = FALSE;
|
||||||
stack_stash_unref (collector->stash);
|
|
||||||
|
|
||||||
|
if (collector->counters)
|
||||||
|
{
|
||||||
|
collector_stop (collector);
|
||||||
|
restart = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collector->stash)
|
||||||
|
{
|
||||||
|
stack_stash_unref (collector->stash);
|
||||||
|
collector->stash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collector->tracker)
|
||||||
|
{
|
||||||
|
tracker_free (collector->tracker);
|
||||||
|
collector->tracker = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
process_flush_caches();
|
process_flush_caches();
|
||||||
|
|
||||||
collector->stash = stack_stash_new (NULL);
|
|
||||||
collector->n_samples = 0;
|
collector->n_samples = 0;
|
||||||
|
|
||||||
g_get_current_time (&collector->latest_reset);
|
g_get_current_time (&collector->latest_reset);
|
||||||
|
|
||||||
|
if (restart)
|
||||||
|
collector_start (collector, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* callback is called whenever a new sample arrives */
|
/* callback is called whenever a new sample arrives */
|
||||||
@ -364,6 +388,7 @@ collector_new (CollectorFunc callback,
|
|||||||
collector->callback = callback;
|
collector->callback = callback;
|
||||||
collector->data = data;
|
collector->data = data;
|
||||||
collector->stash = NULL;
|
collector->stash = NULL;
|
||||||
|
collector->tracker = NULL;
|
||||||
|
|
||||||
collector_reset (collector);
|
collector_reset (collector);
|
||||||
|
|
||||||
@ -507,6 +532,15 @@ collector_start (Collector *collector,
|
|||||||
GList *list;
|
GList *list;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
g_print ("starting\n");
|
||||||
|
|
||||||
|
if (!collector->stash)
|
||||||
|
collector->stash = stack_stash_new (NULL);
|
||||||
|
if (!collector->tracker)
|
||||||
|
collector->tracker = tracker_new ();
|
||||||
|
|
||||||
|
g_assert (collector->stash);
|
||||||
|
|
||||||
for (i = 0; i < n_cpus; ++i)
|
for (i = 0; i < n_cpus; ++i)
|
||||||
{
|
{
|
||||||
counter_t *counter = counter_new (collector, i);
|
counter_t *counter = counter_new (collector, i);
|
||||||
@ -522,6 +556,8 @@ collector_start (Collector *collector,
|
|||||||
|
|
||||||
for (list = collector->counters; list != NULL; list = list->next)
|
for (list = collector->counters; list != NULL; list = list->next)
|
||||||
counter_enable (list->data);
|
counter_enable (list->data);
|
||||||
|
|
||||||
|
g_print ("started\n");
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -374,7 +374,7 @@ on_start_toggled (GtkWidget *widget, gpointer data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sorry (app->main_window, err->message);
|
sorry (app->main_window, err->message);
|
||||||
|
|
||||||
g_error_free (err);
|
g_error_free (err);
|
||||||
}
|
}
|
||||||
|
|||||||
241
tracker.c
241
tracker.c
@ -1,5 +1,7 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "tracker.h"
|
#include "tracker.h"
|
||||||
#include "stackstash.h"
|
#include "stackstash.h"
|
||||||
@ -22,31 +24,31 @@ typedef enum
|
|||||||
NEW_PROCESS,
|
NEW_PROCESS,
|
||||||
NEW_MAP,
|
NEW_MAP,
|
||||||
SAMPLE
|
SAMPLE
|
||||||
} event_type;
|
} event_type_t;
|
||||||
|
|
||||||
struct new_process_t
|
struct new_process_t
|
||||||
{
|
{
|
||||||
event_type type;
|
event_type_t type;
|
||||||
int32_t pid;
|
int32_t pid;
|
||||||
char command_line[256];
|
char command_line[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct new_map_t
|
struct new_map_t
|
||||||
{
|
{
|
||||||
event_type type;
|
event_type_t type;
|
||||||
int32_t pid;
|
int32_t pid;
|
||||||
char file_name[PATH_MAX];
|
char file_name[PATH_MAX];
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
uint64_t end;
|
uint64_t end;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint64_t inode;
|
uint64_t inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sample_t
|
struct sample_t
|
||||||
{
|
{
|
||||||
event_type type;
|
event_type_t type;
|
||||||
int32_t pid;
|
int32_t pid;
|
||||||
StackNode * trace;
|
StackNode * trace;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_SIZE (1024 * 1024 * 4)
|
#define DEFAULT_SIZE (1024 * 1024 * 4)
|
||||||
@ -70,6 +72,136 @@ tracker_append (tracker_t *tracker,
|
|||||||
memcpy (tracker->events + tracker->n_event_bytes, event, n_bytes);
|
memcpy (tracker->events + tracker->n_event_bytes, event, n_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char **
|
||||||
|
get_lines (const char *format, pid_t pid)
|
||||||
|
{
|
||||||
|
char *filename = g_strdup_printf (format, pid);
|
||||||
|
char **result = NULL;
|
||||||
|
char *contents;
|
||||||
|
|
||||||
|
if (g_file_get_contents (filename, &contents, NULL, NULL))
|
||||||
|
{
|
||||||
|
result = g_strsplit (contents, "\n", -1);
|
||||||
|
|
||||||
|
g_free (contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (filename);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fake_new_process (tracker_t *tracker, pid_t pid)
|
||||||
|
{
|
||||||
|
char **lines;
|
||||||
|
|
||||||
|
if ((lines = get_lines ("/proc/%d/status", pid)))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; lines[i] != NULL; ++i)
|
||||||
|
{
|
||||||
|
if (strncmp ("Name:", lines[i], 5) == 0)
|
||||||
|
{
|
||||||
|
tracker_add_process (tracker, pid, g_strstrip (strchr (lines[i], ':')));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fake_new_map (tracker_t *tracker, pid_t pid)
|
||||||
|
{
|
||||||
|
char **lines;
|
||||||
|
|
||||||
|
if ((lines = get_lines ("/proc/%d/maps", pid)))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; lines[i] != NULL; ++i)
|
||||||
|
{
|
||||||
|
char file[256];
|
||||||
|
gulong start;
|
||||||
|
gulong end;
|
||||||
|
gulong offset;
|
||||||
|
gulong inode;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
file[255] = '\0';
|
||||||
|
|
||||||
|
count = sscanf (
|
||||||
|
lines[i], "%lx-%lx %*15s %lx %*x:%*x %lu %255s",
|
||||||
|
&start, &end, &offset, &inode, file);
|
||||||
|
|
||||||
|
if (count == 5)
|
||||||
|
{
|
||||||
|
if (strcmp (file, "[vdso]") == 0)
|
||||||
|
{
|
||||||
|
/* For the vdso, the kernel reports 'offset' as the
|
||||||
|
* the same as the mapping addres. This doesn't make
|
||||||
|
* any sense to me, so we just zero it here. There
|
||||||
|
* is code in binfile.c (read_inode) that returns 0
|
||||||
|
* for [vdso].
|
||||||
|
*/
|
||||||
|
offset = 0;
|
||||||
|
inode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker_add_map (tracker, pid, start, end, offset, inode, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
populate_from_proc (tracker_t *tracker)
|
||||||
|
{
|
||||||
|
GDir *proc = g_dir_open ("/proc", 0, NULL);
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!proc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((name = g_dir_read_name (proc)))
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
pid = strtol (name, &end, 10);
|
||||||
|
|
||||||
|
if (*end == 0)
|
||||||
|
{
|
||||||
|
fake_new_process (tracker, pid);
|
||||||
|
fake_new_map (tracker, pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dir_close (proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static double
|
||||||
|
timeval_to_ms (const GTimeVal *timeval)
|
||||||
|
{
|
||||||
|
return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
time_diff (const GTimeVal *first,
|
||||||
|
const GTimeVal *second)
|
||||||
|
{
|
||||||
|
double first_ms = timeval_to_ms (first);
|
||||||
|
double second_ms = timeval_to_ms (second);
|
||||||
|
|
||||||
|
return first_ms - second_ms;
|
||||||
|
}
|
||||||
|
|
||||||
tracker_t *
|
tracker_t *
|
||||||
tracker_new (void)
|
tracker_new (void)
|
||||||
{
|
{
|
||||||
@ -80,6 +212,16 @@ tracker_new (void)
|
|||||||
tracker->events = g_malloc (DEFAULT_SIZE);
|
tracker->events = g_malloc (DEFAULT_SIZE);
|
||||||
|
|
||||||
tracker->stash = stack_stash_new (NULL);
|
tracker->stash = stack_stash_new (NULL);
|
||||||
|
|
||||||
|
GTimeVal before, after;
|
||||||
|
|
||||||
|
g_get_current_time (&before);
|
||||||
|
|
||||||
|
populate_from_proc (tracker);
|
||||||
|
|
||||||
|
g_get_current_time (&after);
|
||||||
|
|
||||||
|
g_print ("Time to populate %f\n", time_diff (&after, &before));
|
||||||
|
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
@ -87,7 +229,9 @@ tracker_new (void)
|
|||||||
void
|
void
|
||||||
tracker_free (tracker_t *tracker)
|
tracker_free (tracker_t *tracker)
|
||||||
{
|
{
|
||||||
|
stack_stash_unref (tracker->stash);
|
||||||
|
g_free (tracker->events);
|
||||||
|
g_free (tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COPY_STRING(dest, src) \
|
#define COPY_STRING(dest, src) \
|
||||||
@ -111,6 +255,10 @@ tracker_add_process (tracker_t * tracker,
|
|||||||
COPY_STRING (event.command_line, command_line);
|
COPY_STRING (event.command_line, command_line);
|
||||||
|
|
||||||
tracker_append (tracker, &event, sizeof (event));
|
tracker_append (tracker, &event, sizeof (event));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_print ("Added new process: %d (%s)\n", pid, command_line);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -133,6 +281,10 @@ tracker_add_map (tracker_t * tracker,
|
|||||||
event.inode = inode;
|
event.inode = inode;
|
||||||
|
|
||||||
tracker_append (tracker, &event, sizeof (event));
|
tracker_append (tracker, &event, sizeof (event));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_print (" Added new map: %d (%s)\n", pid, filename);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -150,8 +302,63 @@ tracker_add_sample (tracker_t *tracker,
|
|||||||
tracker_append (tracker, &event, sizeof (event));
|
tracker_append (tracker, &event, sizeof (event));
|
||||||
}
|
}
|
||||||
|
|
||||||
Profile *
|
/* */
|
||||||
tracker_create_profile (tracker_t *tracker)
|
typedef struct state_t state_t;
|
||||||
|
|
||||||
|
struct state_t
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
new_process (state_t *tracker, new_process_t *new_process)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
new_map (state_t *tracker, new_map_t *new_map)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sample (state_t *tracker, sample_t *sample)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile *
|
||||||
|
tracker_create_profile (tracker_t *tracker)
|
||||||
|
{
|
||||||
|
uint8_t *end = tracker->events + tracker->n_event_bytes;
|
||||||
|
uint8_t *event;
|
||||||
|
|
||||||
|
event = tracker->events;
|
||||||
|
while (event < end)
|
||||||
|
{
|
||||||
|
event_type_t type = *(event_type_t *)event;
|
||||||
|
new_process_t *new_process;
|
||||||
|
new_map_t *new_map;
|
||||||
|
sample_t *sample;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case NEW_PROCESS:
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NEW_MAP:
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SAMPLE:
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user