diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/Makefile.perf | 1 | ||||
| -rw-r--r-- | tools/perf/builtin-record.c | 34 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 9 | ||||
| -rw-r--r-- | tools/perf/util/data.c | 120 | ||||
| -rw-r--r-- | tools/perf/util/data.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 95 | ||||
| -rw-r--r-- | tools/perf/util/session.h | 2 |
7 files changed, 158 insertions, 107 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index c873e039aafb..326a26e5fc1c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
| @@ -365,6 +365,7 @@ LIB_OBJS += $(OUTPUT)util/vdso.o | |||
| 365 | LIB_OBJS += $(OUTPUT)util/stat.o | 365 | LIB_OBJS += $(OUTPUT)util/stat.o |
| 366 | LIB_OBJS += $(OUTPUT)util/record.o | 366 | LIB_OBJS += $(OUTPUT)util/record.o |
| 367 | LIB_OBJS += $(OUTPUT)util/srcline.o | 367 | LIB_OBJS += $(OUTPUT)util/srcline.o |
| 368 | LIB_OBJS += $(OUTPUT)util/data.o | ||
| 368 | 369 | ||
| 369 | LIB_OBJS += $(OUTPUT)ui/setup.o | 370 | LIB_OBJS += $(OUTPUT)ui/setup.o |
| 370 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 371 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4ea46ffbfc1c..428e28f3e677 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -345,8 +345,6 @@ out: | |||
| 345 | 345 | ||
| 346 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | 346 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) |
| 347 | { | 347 | { |
| 348 | struct stat st; | ||
| 349 | int flags; | ||
| 350 | int err, feat; | 348 | int err, feat; |
| 351 | unsigned long waking = 0; | 349 | unsigned long waking = 0; |
| 352 | const bool forks = argc > 0; | 350 | const bool forks = argc > 0; |
| @@ -355,7 +353,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
| 355 | struct perf_record_opts *opts = &rec->opts; | 353 | struct perf_record_opts *opts = &rec->opts; |
| 356 | struct perf_evlist *evsel_list = rec->evlist; | 354 | struct perf_evlist *evsel_list = rec->evlist; |
| 357 | struct perf_data_file *file = &rec->file; | 355 | struct perf_data_file *file = &rec->file; |
| 358 | const char *output_name = file->path; | ||
| 359 | struct perf_session *session; | 356 | struct perf_session *session; |
| 360 | bool disabled = false; | 357 | bool disabled = false; |
| 361 | 358 | ||
| @@ -367,35 +364,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
| 367 | signal(SIGUSR1, sig_handler); | 364 | signal(SIGUSR1, sig_handler); |
| 368 | signal(SIGTERM, sig_handler); | 365 | signal(SIGTERM, sig_handler); |
| 369 | 366 | ||
| 370 | if (!output_name) { | ||
| 371 | if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) | ||
| 372 | file->is_pipe = true; | ||
| 373 | else | ||
| 374 | file->path = output_name = "perf.data"; | ||
| 375 | } | ||
| 376 | if (output_name) { | ||
| 377 | if (!strcmp(output_name, "-")) | ||
| 378 | file->is_pipe = true; | ||
| 379 | else if (!stat(output_name, &st) && st.st_size) { | ||
| 380 | char oldname[PATH_MAX]; | ||
| 381 | snprintf(oldname, sizeof(oldname), "%s.old", | ||
| 382 | output_name); | ||
| 383 | unlink(oldname); | ||
| 384 | rename(output_name, oldname); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | flags = O_CREAT|O_RDWR|O_TRUNC; | ||
| 389 | |||
| 390 | if (file->is_pipe) | ||
| 391 | file->fd = STDOUT_FILENO; | ||
| 392 | else | ||
| 393 | file->fd = open(output_name, flags, S_IRUSR | S_IWUSR); | ||
| 394 | if (file->fd < 0) { | ||
| 395 | perror("failed to create output file"); | ||
| 396 | return -1; | ||
| 397 | } | ||
| 398 | |||
| 399 | session = perf_session__new(file, false, NULL); | 367 | session = perf_session__new(file, false, NULL); |
| 400 | if (session == NULL) { | 368 | if (session == NULL) { |
| 401 | pr_err("Not enough memory for reading perf file header\n"); | 369 | pr_err("Not enough memory for reading perf file header\n"); |
| @@ -586,7 +554,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
| 586 | fprintf(stderr, | 554 | fprintf(stderr, |
| 587 | "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", | 555 | "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", |
| 588 | (double)rec->bytes_written / 1024.0 / 1024.0, | 556 | (double)rec->bytes_written / 1024.0 / 1024.0, |
| 589 | output_name, | 557 | file->path, |
| 590 | rec->bytes_written / 24); | 558 | rec->bytes_written / 24); |
| 591 | 559 | ||
| 592 | return 0; | 560 | return 0; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 752bebeac3aa..d934f707ee74 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -929,15 +929,8 @@ static int __cmd_top(struct perf_top *top) | |||
| 929 | struct perf_record_opts *opts = &top->record_opts; | 929 | struct perf_record_opts *opts = &top->record_opts; |
| 930 | pthread_t thread; | 930 | pthread_t thread; |
| 931 | int ret; | 931 | int ret; |
| 932 | struct perf_data_file file = { | ||
| 933 | .mode = PERF_DATA_MODE_WRITE, | ||
| 934 | }; | ||
| 935 | 932 | ||
| 936 | /* | 933 | top->session = perf_session__new(NULL, false, NULL); |
| 937 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | ||
| 938 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | ||
| 939 | */ | ||
| 940 | top->session = perf_session__new(&file, false, NULL); | ||
| 941 | if (top->session == NULL) | 934 | if (top->session == NULL) |
| 942 | return -ENOMEM; | 935 | return -ENOMEM; |
| 943 | 936 | ||
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c new file mode 100644 index 000000000000..7d09faf85cf1 --- /dev/null +++ b/tools/perf/util/data.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | #include <linux/compiler.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <sys/types.h> | ||
| 4 | #include <sys/stat.h> | ||
| 5 | #include <unistd.h> | ||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "data.h" | ||
| 9 | #include "util.h" | ||
| 10 | |||
| 11 | static bool check_pipe(struct perf_data_file *file) | ||
| 12 | { | ||
| 13 | struct stat st; | ||
| 14 | bool is_pipe = false; | ||
| 15 | int fd = perf_data_file__is_read(file) ? | ||
| 16 | STDIN_FILENO : STDOUT_FILENO; | ||
| 17 | |||
| 18 | if (!file->path) { | ||
| 19 | if (!fstat(fd, &st) && S_ISFIFO(st.st_mode)) | ||
| 20 | is_pipe = true; | ||
| 21 | } else { | ||
| 22 | if (!strcmp(file->path, "-")) | ||
| 23 | is_pipe = true; | ||
| 24 | } | ||
| 25 | |||
| 26 | if (is_pipe) | ||
| 27 | file->fd = fd; | ||
| 28 | |||
| 29 | return file->is_pipe = is_pipe; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int check_backup(struct perf_data_file *file) | ||
| 33 | { | ||
| 34 | struct stat st; | ||
| 35 | |||
| 36 | if (!stat(file->path, &st) && st.st_size) { | ||
| 37 | /* TODO check errors properly */ | ||
| 38 | char oldname[PATH_MAX]; | ||
| 39 | snprintf(oldname, sizeof(oldname), "%s.old", | ||
| 40 | file->path); | ||
| 41 | unlink(oldname); | ||
| 42 | rename(file->path, oldname); | ||
| 43 | } | ||
| 44 | |||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | static int open_file_read(struct perf_data_file *file) | ||
| 49 | { | ||
| 50 | struct stat st; | ||
| 51 | int fd; | ||
| 52 | |||
| 53 | fd = open(file->path, O_RDONLY); | ||
| 54 | if (fd < 0) { | ||
| 55 | int err = errno; | ||
| 56 | |||
| 57 | pr_err("failed to open %s: %s", file->path, strerror(err)); | ||
| 58 | if (err == ENOENT && !strcmp(file->path, "perf.data")) | ||
| 59 | pr_err(" (try 'perf record' first)"); | ||
| 60 | pr_err("\n"); | ||
| 61 | return -err; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (fstat(fd, &st) < 0) | ||
| 65 | goto out_close; | ||
| 66 | |||
| 67 | if (!file->force && st.st_uid && (st.st_uid != geteuid())) { | ||
| 68 | pr_err("file %s not owned by current user or root\n", | ||
| 69 | file->path); | ||
| 70 | goto out_close; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (!st.st_size) { | ||
| 74 | pr_info("zero-sized file (%s), nothing to do!\n", | ||
| 75 | file->path); | ||
| 76 | goto out_close; | ||
| 77 | } | ||
| 78 | |||
| 79 | file->size = st.st_size; | ||
| 80 | return fd; | ||
| 81 | |||
| 82 | out_close: | ||
| 83 | close(fd); | ||
| 84 | return -1; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int open_file_write(struct perf_data_file *file) | ||
| 88 | { | ||
| 89 | if (check_backup(file)) | ||
| 90 | return -1; | ||
| 91 | |||
| 92 | return open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int open_file(struct perf_data_file *file) | ||
| 96 | { | ||
| 97 | int fd; | ||
| 98 | |||
| 99 | fd = perf_data_file__is_read(file) ? | ||
| 100 | open_file_read(file) : open_file_write(file); | ||
| 101 | |||
| 102 | file->fd = fd; | ||
| 103 | return fd < 0 ? -1 : 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | int perf_data_file__open(struct perf_data_file *file) | ||
| 107 | { | ||
| 108 | if (check_pipe(file)) | ||
| 109 | return 0; | ||
| 110 | |||
| 111 | if (!file->path) | ||
| 112 | file->path = "perf.data"; | ||
| 113 | |||
| 114 | return open_file(file); | ||
| 115 | } | ||
| 116 | |||
| 117 | void perf_data_file__close(struct perf_data_file *file) | ||
| 118 | { | ||
| 119 | close(file->fd); | ||
| 120 | } | ||
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index ffa0186e6000..d6c262e42f47 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h | |||
| @@ -13,6 +13,7 @@ struct perf_data_file { | |||
| 13 | int fd; | 13 | int fd; |
| 14 | bool is_pipe; | 14 | bool is_pipe; |
| 15 | bool force; | 15 | bool force; |
| 16 | unsigned long size; | ||
| 16 | enum perf_data_mode mode; | 17 | enum perf_data_mode mode; |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| @@ -26,4 +27,7 @@ static inline bool perf_data_file__is_write(struct perf_data_file *file) | |||
| 26 | return file->mode == PERF_DATA_MODE_WRITE; | 27 | return file->mode == PERF_DATA_MODE_WRITE; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 30 | int perf_data_file__open(struct perf_data_file *file); | ||
| 31 | void perf_data_file__close(struct perf_data_file *file); | ||
| 32 | |||
| 29 | #endif /* __PERF_DATA_H */ | 33 | #endif /* __PERF_DATA_H */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e3f63df1d57c..d857c18d2eeb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -16,73 +16,35 @@ | |||
| 16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
| 17 | #include "vdso.h" | 17 | #include "vdso.h" |
| 18 | 18 | ||
| 19 | static int perf_session__open(struct perf_session *self, bool force) | 19 | static int perf_session__open(struct perf_session *self) |
| 20 | { | 20 | { |
| 21 | struct stat input_stat; | 21 | if (self->fd_pipe) { |
| 22 | |||
| 23 | if (!strcmp(self->filename, "-")) { | ||
| 24 | self->fd_pipe = true; | ||
| 25 | self->fd = STDIN_FILENO; | ||
| 26 | |||
| 27 | if (perf_session__read_header(self) < 0) | 22 | if (perf_session__read_header(self) < 0) |
| 28 | pr_err("incompatible file format (rerun with -v to learn more)"); | 23 | pr_err("incompatible file format (rerun with -v to learn more)"); |
| 29 | |||
| 30 | return 0; | 24 | return 0; |
| 31 | } | 25 | } |
| 32 | 26 | ||
| 33 | self->fd = open(self->filename, O_RDONLY); | ||
| 34 | if (self->fd < 0) { | ||
| 35 | int err = errno; | ||
| 36 | |||
| 37 | pr_err("failed to open %s: %s", self->filename, strerror(err)); | ||
| 38 | if (err == ENOENT && !strcmp(self->filename, "perf.data")) | ||
| 39 | pr_err(" (try 'perf record' first)"); | ||
| 40 | pr_err("\n"); | ||
| 41 | return -errno; | ||
| 42 | } | ||
| 43 | |||
| 44 | if (fstat(self->fd, &input_stat) < 0) | ||
| 45 | goto out_close; | ||
| 46 | |||
| 47 | if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { | ||
| 48 | pr_err("file %s not owned by current user or root\n", | ||
| 49 | self->filename); | ||
| 50 | goto out_close; | ||
| 51 | } | ||
| 52 | |||
| 53 | if (!input_stat.st_size) { | ||
| 54 | pr_info("zero-sized file (%s), nothing to do!\n", | ||
| 55 | self->filename); | ||
| 56 | goto out_close; | ||
| 57 | } | ||
| 58 | |||
| 59 | if (perf_session__read_header(self) < 0) { | 27 | if (perf_session__read_header(self) < 0) { |
| 60 | pr_err("incompatible file format (rerun with -v to learn more)"); | 28 | pr_err("incompatible file format (rerun with -v to learn more)"); |
| 61 | goto out_close; | 29 | return -1; |
| 62 | } | 30 | } |
| 63 | 31 | ||
| 64 | if (!perf_evlist__valid_sample_type(self->evlist)) { | 32 | if (!perf_evlist__valid_sample_type(self->evlist)) { |
| 65 | pr_err("non matching sample_type"); | 33 | pr_err("non matching sample_type"); |
| 66 | goto out_close; | 34 | return -1; |
| 67 | } | 35 | } |
| 68 | 36 | ||
| 69 | if (!perf_evlist__valid_sample_id_all(self->evlist)) { | 37 | if (!perf_evlist__valid_sample_id_all(self->evlist)) { |
| 70 | pr_err("non matching sample_id_all"); | 38 | pr_err("non matching sample_id_all"); |
| 71 | goto out_close; | 39 | return -1; |
| 72 | } | 40 | } |
| 73 | 41 | ||
| 74 | if (!perf_evlist__valid_read_format(self->evlist)) { | 42 | if (!perf_evlist__valid_read_format(self->evlist)) { |
| 75 | pr_err("non matching read_format"); | 43 | pr_err("non matching read_format"); |
| 76 | goto out_close; | 44 | return -1; |
| 77 | } | 45 | } |
| 78 | 46 | ||
| 79 | self->size = input_stat.st_size; | ||
| 80 | return 0; | 47 | return 0; |
| 81 | |||
| 82 | out_close: | ||
| 83 | close(self->fd); | ||
| 84 | self->fd = -1; | ||
| 85 | return -1; | ||
| 86 | } | 48 | } |
| 87 | 49 | ||
| 88 | void perf_session__set_id_hdr_size(struct perf_session *session) | 50 | void perf_session__set_id_hdr_size(struct perf_session *session) |
| @@ -110,35 +72,35 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
| 110 | bool repipe, struct perf_tool *tool) | 72 | bool repipe, struct perf_tool *tool) |
| 111 | { | 73 | { |
| 112 | struct perf_session *self; | 74 | struct perf_session *self; |
| 113 | const char *filename = file->path; | ||
| 114 | struct stat st; | ||
| 115 | size_t len; | ||
| 116 | |||
| 117 | if (!filename || !strlen(filename)) { | ||
| 118 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) | ||
| 119 | filename = "-"; | ||
| 120 | else | ||
| 121 | filename = "perf.data"; | ||
| 122 | } | ||
| 123 | 75 | ||
| 124 | len = strlen(filename); | 76 | self = zalloc(sizeof(*self)); |
| 125 | self = zalloc(sizeof(*self) + len); | 77 | if (!self) |
| 126 | |||
| 127 | if (self == NULL) | ||
| 128 | goto out; | 78 | goto out; |
| 129 | 79 | ||
| 130 | memcpy(self->filename, filename, len); | ||
| 131 | self->repipe = repipe; | 80 | self->repipe = repipe; |
| 132 | INIT_LIST_HEAD(&self->ordered_samples.samples); | 81 | INIT_LIST_HEAD(&self->ordered_samples.samples); |
| 133 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); | 82 | INIT_LIST_HEAD(&self->ordered_samples.sample_cache); |
| 134 | INIT_LIST_HEAD(&self->ordered_samples.to_free); | 83 | INIT_LIST_HEAD(&self->ordered_samples.to_free); |
| 135 | machines__init(&self->machines); | 84 | machines__init(&self->machines); |
| 136 | 85 | ||
| 137 | if (perf_data_file__is_read(file)) { | 86 | if (file) { |
| 138 | if (perf_session__open(self, file->force) < 0) | 87 | if (perf_data_file__open(file)) |
| 139 | goto out_delete; | 88 | goto out_delete; |
| 140 | perf_session__set_id_hdr_size(self); | 89 | |
| 141 | } else if (perf_data_file__is_write(file)) { | 90 | self->fd = file->fd; |
| 91 | self->fd_pipe = file->is_pipe; | ||
| 92 | self->filename = file->path; | ||
| 93 | self->size = file->size; | ||
| 94 | |||
| 95 | if (perf_data_file__is_read(file)) { | ||
| 96 | if (perf_session__open(self) < 0) | ||
| 97 | goto out_close; | ||
| 98 | |||
| 99 | perf_session__set_id_hdr_size(self); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | if (!file || perf_data_file__is_write(file)) { | ||
| 142 | /* | 104 | /* |
| 143 | * In O_RDONLY mode this will be performed when reading the | 105 | * In O_RDONLY mode this will be performed when reading the |
| 144 | * kernel MMAP event, in perf_event__process_mmap(). | 106 | * kernel MMAP event, in perf_event__process_mmap(). |
| @@ -153,10 +115,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
| 153 | tool->ordered_samples = false; | 115 | tool->ordered_samples = false; |
| 154 | } | 116 | } |
| 155 | 117 | ||
| 156 | out: | ||
| 157 | return self; | 118 | return self; |
| 158 | out_delete: | 119 | |
| 120 | out_close: | ||
| 121 | perf_data_file__close(file); | ||
| 122 | out_delete: | ||
| 159 | perf_session__delete(self); | 123 | perf_session__delete(self); |
| 124 | out: | ||
| 160 | return NULL; | 125 | return NULL; |
| 161 | } | 126 | } |
| 162 | 127 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index f2f6251fd62c..e1ca2d0ae541 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -39,7 +39,7 @@ struct perf_session { | |||
| 39 | bool fd_pipe; | 39 | bool fd_pipe; |
| 40 | bool repipe; | 40 | bool repipe; |
| 41 | struct ordered_samples ordered_samples; | 41 | struct ordered_samples ordered_samples; |
| 42 | char filename[1]; | 42 | const char *filename; |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | #define PRINT_IP_OPT_IP (1<<0) | 45 | #define PRINT_IP_OPT_IP (1<<0) |
