typedef struct sample_event_t sample_event_t;
typedef struct mmap_event_t mmap_event_t;
typedef struct comm_event_t comm_event_t;
+typedef struct exit_event_t exit_event_t;
+typedef struct fork_event_t fork_event_t;
typedef union counter_event_t counter_event_t;
static void process_event (Collector *collector, counter_event_t *event);
char filename[1];
};
+struct fork_event_t
+{
+ struct perf_event_header header;
+
+ uint32_t pid, ppid;
+ uint32_t tid, ptid;
+};
+
+struct exit_event_t
+{
+ struct perf_event_header header;
+
+ uint32_t pid, ppid;
+ uint32_t tid, ptid;
+};
+
union counter_event_t
{
struct perf_event_header header;
mmap_event_t mmap;
comm_event_t comm;
sample_event_t sample;
+ fork_event_t fork;
+ exit_event_t exit;
};
struct Collector
attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_CALLCHAIN;
attr.wakeup_events = 100000;
attr.disabled = TRUE;
- attr.mmap = TRUE;
- attr.comm = TRUE;
+
+ if (cpu == 0)
+ {
+ attr.mmap = 1;
+ attr.comm = 1;
+ attr.task = 1;
+ }
fd = sysprof_perf_counter_open (&attr, -1, cpu, -1, 0);
static void
process_comm (Collector *collector, comm_event_t *comm)
{
+ g_print ("comm: pid: %d\n", comm->pid);
+
tracker_add_process (collector->tracker,
comm->pid,
comm->comm);
}
static void
+process_fork (Collector *collector, fork_event_t *fork)
+{
+ g_print ("fork: ppid: %d pid: %d\n", fork->ppid, fork->pid);
+
+ tracker_add_fork (collector->tracker, fork->ppid, fork->pid);
+}
+
+static void
+process_exit (Collector *collector, exit_event_t *exit)
+{
+ tracker_add_exit (collector->tracker, exit->pid);
+}
+
+static void
process_sample (Collector *collector,
sample_event_t *sample)
{
break;
case PERF_EVENT_EXIT:
+ process_exit (collector, &event->exit);
break;
case PERF_EVENT_THROTTLE:
break;
case PERF_EVENT_FORK:
+ process_fork (collector, &event->fork);
break;
case PERF_EVENT_READ:
typedef struct new_process_t new_process_t;
typedef struct new_map_t new_map_t;
typedef struct sample_t sample_t;
+typedef struct fork_t fork_t;
+typedef struct exit_t exit_t;
struct tracker_t
{
{
NEW_PROCESS,
NEW_MAP,
- SAMPLE
+ SAMPLE,
+ FORK,
+ EXIT
} event_type_t;
struct new_process_t
char command_line[256];
};
+struct fork_t
+{
+ event_type_t type;
+ int32_t pid;
+ int32_t child_pid;
+};
+
+struct exit_t
+{
+ event_type_t type;
+ int32_t pid;
+};
+
struct new_map_t
{
event_type_t type;
tracker_append (tracker, &event, sizeof (event));
-#if 0
g_print ("Added new process: %d (%s)\n", pid, command_line);
-#endif
+}
+
+void
+tracker_add_fork (tracker_t *tracker,
+ pid_t pid,
+ pid_t child_pid)
+{
+ fork_t event;
+
+ event.type = FORK;
+ event.pid = pid;
+ event.child_pid = child_pid;
+
+ tracker_append (tracker, &event, sizeof (event));
+}
+
+void
+tracker_add_exit (tracker_t *tracker,
+ pid_t pid)
+{
+ exit_t event;
+
+ event.type = EXIT;
+ event.pid = pid;
+
+ tracker_append (tracker, &event, sizeof (event));
}
void
state->processes_by_pid, GINT_TO_POINTER (process->pid), process);
}
+static map_t *
+copy_map (map_t *map)
+{
+ map_t *copy = g_new0 (map_t, 1);
+
+ *copy = *map;
+ copy->filename = g_strdup (map->filename);
+
+ return copy;
+}
+
+static void
+process_fork (state_t *state, fork_t *fork)
+{
+ process_t *parent = g_hash_table_lookup (
+ state->processes_by_pid, GINT_TO_POINTER (fork->pid));
+
+ if (parent)
+ {
+ process_t *process = g_new0 (process_t, 1);
+ int i;
+
+ g_print ("new child %d\n", fork->child_pid);
+
+ process->pid = fork->child_pid;
+ process->comm = g_strdup (parent->comm);
+ process->maps = g_ptr_array_new ();
+
+ for (i = 0; i < parent->maps->len; ++i)
+ {
+ map_t *map = copy_map (parent->maps->pdata[i]);
+
+ g_ptr_array_add (process->maps, map);
+ }
+
+ g_hash_table_insert (
+ state->processes_by_pid, GINT_TO_POINTER (process->pid), process);
+ }
+ else
+ g_print ("no parent for %d\n", fork->child_pid);
+}
+
+static void
+process_exit (state_t *state, exit_t *exit)
+{
+ /* ignore for now */
+}
+
static void
free_process (gpointer data)
{
static gboolean warned;
if (!warned || sample->pid != 0)
{
- g_warning ("sample for unknown process %d", sample->pid);
+ g_print ("sample for unknown process %d\n", sample->pid);
warned = TRUE;
}
return;
create_map (state, (new_map_t *)event);
event += sizeof (new_map_t);
break;
+
+ case FORK:
+ process_fork (state, (fork_t *)event);
+ event += sizeof (fork_t);
+ break;
+
+ case EXIT:
+ process_exit (state, (exit_t *)exit);
+ event += sizeof (exit_t);
+ break;
case SAMPLE:
process_sample (state, resolved_stash, (sample_t *)event);