|
@@ -14,6 +14,8 @@
|
|
|
#include "util/parse-events.h"
|
|
#include "util/parse-events.h"
|
|
|
#include "util/string.h"
|
|
#include "util/string.h"
|
|
|
|
|
|
|
|
|
|
+#include "util/header.h"
|
|
|
|
|
+
|
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
#include <sched.h>
|
|
#include <sched.h>
|
|
|
|
|
|
|
@@ -52,7 +54,8 @@ static int nr_poll;
|
|
|
static int nr_cpu;
|
|
static int nr_cpu;
|
|
|
|
|
|
|
|
static int file_new = 1;
|
|
static int file_new = 1;
|
|
|
-static struct perf_file_header file_header;
|
|
|
|
|
|
|
+
|
|
|
|
|
+struct perf_header *header;
|
|
|
|
|
|
|
|
struct mmap_event {
|
|
struct mmap_event {
|
|
|
struct perf_event_header header;
|
|
struct perf_event_header header;
|
|
@@ -328,7 +331,7 @@ static void pid_synthesize_mmap_samples(pid_t pid)
|
|
|
fclose(fp);
|
|
fclose(fp);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void synthesize_samples(void)
|
|
|
|
|
|
|
+static void synthesize_all(void)
|
|
|
{
|
|
{
|
|
|
DIR *proc;
|
|
DIR *proc;
|
|
|
struct dirent dirent, *next;
|
|
struct dirent dirent, *next;
|
|
@@ -352,10 +355,35 @@ static void synthesize_samples(void)
|
|
|
|
|
|
|
|
static int group_fd;
|
|
static int group_fd;
|
|
|
|
|
|
|
|
|
|
+static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct perf_header_attr *h_attr;
|
|
|
|
|
+
|
|
|
|
|
+ if (nr < header->attrs) {
|
|
|
|
|
+ h_attr = header->attr[nr];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ h_attr = perf_header_attr__new(a);
|
|
|
|
|
+ perf_header__add_attr(header, h_attr);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return h_attr;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void create_counter(int counter, int cpu, pid_t pid)
|
|
static void create_counter(int counter, int cpu, pid_t pid)
|
|
|
{
|
|
{
|
|
|
struct perf_counter_attr *attr = attrs + counter;
|
|
struct perf_counter_attr *attr = attrs + counter;
|
|
|
- int track = 1;
|
|
|
|
|
|
|
+ struct perf_header_attr *h_attr;
|
|
|
|
|
+ int track = !counter; /* only the first counter needs these */
|
|
|
|
|
+ struct {
|
|
|
|
|
+ u64 count;
|
|
|
|
|
+ u64 time_enabled;
|
|
|
|
|
+ u64 time_running;
|
|
|
|
|
+ u64 id;
|
|
|
|
|
+ } read_data;
|
|
|
|
|
+
|
|
|
|
|
+ attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
|
|
|
|
|
+ PERF_FORMAT_TOTAL_TIME_RUNNING |
|
|
|
|
|
+ PERF_FORMAT_ID;
|
|
|
|
|
|
|
|
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
|
|
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
|
|
|
|
|
|
|
@@ -368,22 +396,11 @@ static void create_counter(int counter, int cpu, pid_t pid)
|
|
|
if (call_graph)
|
|
if (call_graph)
|
|
|
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
|
|
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
|
|
|
|
|
|
|
|
- if (file_new) {
|
|
|
|
|
- file_header.sample_type = attr->sample_type;
|
|
|
|
|
- } else {
|
|
|
|
|
- if (file_header.sample_type != attr->sample_type) {
|
|
|
|
|
- fprintf(stderr, "incompatible append\n");
|
|
|
|
|
- exit(-1);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
attr->mmap = track;
|
|
attr->mmap = track;
|
|
|
attr->comm = track;
|
|
attr->comm = track;
|
|
|
attr->inherit = (cpu < 0) && inherit;
|
|
attr->inherit = (cpu < 0) && inherit;
|
|
|
attr->disabled = 1;
|
|
attr->disabled = 1;
|
|
|
|
|
|
|
|
- track = 0; /* only the first counter needs these */
|
|
|
|
|
-
|
|
|
|
|
try_again:
|
|
try_again:
|
|
|
fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
|
|
fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0);
|
|
|
|
|
|
|
@@ -414,6 +431,19 @@ try_again:
|
|
|
exit(-1);
|
|
exit(-1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ h_attr = get_header_attr(attr, counter);
|
|
|
|
|
+
|
|
|
|
|
+ if (!file_new) {
|
|
|
|
|
+ if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
|
|
|
|
|
+ fprintf(stderr, "incompatible append\n");
|
|
|
|
|
+ exit(-1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ read(fd[nr_cpu][counter], &read_data, sizeof(read_data));
|
|
|
|
|
+
|
|
|
|
|
+ perf_header_attr__add_id(h_attr, read_data.id);
|
|
|
|
|
+
|
|
|
assert(fd[nr_cpu][counter] >= 0);
|
|
assert(fd[nr_cpu][counter] >= 0);
|
|
|
fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
|
|
fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
|
|
|
|
|
|
|
@@ -444,11 +474,6 @@ static void open_counters(int cpu, pid_t pid)
|
|
|
{
|
|
{
|
|
|
int counter;
|
|
int counter;
|
|
|
|
|
|
|
|
- if (pid > 0) {
|
|
|
|
|
- pid_synthesize_comm_event(pid, 0);
|
|
|
|
|
- pid_synthesize_mmap_samples(pid);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
group_fd = -1;
|
|
group_fd = -1;
|
|
|
for (counter = 0; counter < nr_counters; counter++)
|
|
for (counter = 0; counter < nr_counters; counter++)
|
|
|
create_counter(counter, cpu, pid);
|
|
create_counter(counter, cpu, pid);
|
|
@@ -458,17 +483,16 @@ static void open_counters(int cpu, pid_t pid)
|
|
|
|
|
|
|
|
static void atexit_header(void)
|
|
static void atexit_header(void)
|
|
|
{
|
|
{
|
|
|
- file_header.data_size += bytes_written;
|
|
|
|
|
|
|
+ header->data_size += bytes_written;
|
|
|
|
|
|
|
|
- if (pwrite(output, &file_header, sizeof(file_header), 0) == -1)
|
|
|
|
|
- perror("failed to write on file headers");
|
|
|
|
|
|
|
+ perf_header__write(header, output);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int __cmd_record(int argc, const char **argv)
|
|
static int __cmd_record(int argc, const char **argv)
|
|
|
{
|
|
{
|
|
|
int i, counter;
|
|
int i, counter;
|
|
|
struct stat st;
|
|
struct stat st;
|
|
|
- pid_t pid;
|
|
|
|
|
|
|
+ pid_t pid = 0;
|
|
|
int flags;
|
|
int flags;
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
|
@@ -499,22 +523,31 @@ static int __cmd_record(int argc, const char **argv)
|
|
|
exit(-1);
|
|
exit(-1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!file_new) {
|
|
|
|
|
- if (read(output, &file_header, sizeof(file_header)) == -1) {
|
|
|
|
|
- perror("failed to read file headers");
|
|
|
|
|
- exit(-1);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- lseek(output, file_header.data_size, SEEK_CUR);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!file_new)
|
|
|
|
|
+ header = perf_header__read(output);
|
|
|
|
|
+ else
|
|
|
|
|
+ header = perf_header__new();
|
|
|
|
|
|
|
|
atexit(atexit_header);
|
|
atexit(atexit_header);
|
|
|
|
|
|
|
|
if (!system_wide) {
|
|
if (!system_wide) {
|
|
|
- open_counters(-1, target_pid != -1 ? target_pid : getpid());
|
|
|
|
|
|
|
+ pid = target_pid;
|
|
|
|
|
+ if (pid == -1)
|
|
|
|
|
+ pid = getpid();
|
|
|
|
|
+
|
|
|
|
|
+ open_counters(-1, pid);
|
|
|
} else for (i = 0; i < nr_cpus; i++)
|
|
} else for (i = 0; i < nr_cpus; i++)
|
|
|
open_counters(i, target_pid);
|
|
open_counters(i, target_pid);
|
|
|
|
|
|
|
|
|
|
+ if (file_new)
|
|
|
|
|
+ perf_header__write(header, output);
|
|
|
|
|
+
|
|
|
|
|
+ if (!system_wide) {
|
|
|
|
|
+ pid_synthesize_comm_event(pid, 0);
|
|
|
|
|
+ pid_synthesize_mmap_samples(pid);
|
|
|
|
|
+ } else
|
|
|
|
|
+ synthesize_all();
|
|
|
|
|
+
|
|
|
if (target_pid == -1 && argc) {
|
|
if (target_pid == -1 && argc) {
|
|
|
pid = fork();
|
|
pid = fork();
|
|
|
if (pid < 0)
|
|
if (pid < 0)
|
|
@@ -538,9 +571,6 @@ static int __cmd_record(int argc, const char **argv)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (system_wide)
|
|
|
|
|
- synthesize_samples();
|
|
|
|
|
-
|
|
|
|
|
while (!done) {
|
|
while (!done) {
|
|
|
int hits = samples;
|
|
int hits = samples;
|
|
|
|
|
|