aboutsummaryrefslogtreecommitdiffstats
path: root/trace-input.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-29 13:42:17 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-29 14:09:56 -0500
commit397292ce2da1208e15a1902eda41213f92228420 (patch)
tree07f91b744d032f0520f57a59cb28612212186626 /trace-input.c
parent554aae82850b51e86167322bd946343d98a1ebfd (diff)
trace-cmd: Add page references for records
It can be confusing for a user of tracecmd records to keep track when its data is mapped. The data of a record points to a mmapped page of the data file. But currently only one page is mapped at a time. If two records are read that are on different pages, the first record's memory will be unmmaped. Instead of putting the management to the user, this patch changes the design to keep a reference count to the page. When a record is created, it adds one to the page's reference count. The page is only unmmaped when the reference count goes to zero. A check on tracecmd_close is made to make sure all pages have been unmmaped, otherwise a warning is printed. This would happen if a record is not freed properly. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'trace-input.c')
-rw-r--r--trace-input.c281
1 files changed, 170 insertions, 111 deletions
diff --git a/trace-input.c b/trace-input.c
index 0bb750c..2fabb2d 100644
--- a/trace-input.c
+++ b/trace-input.c
@@ -17,10 +17,19 @@
17#include <errno.h> 17#include <errno.h>
18 18
19#include "trace-cmd.h" 19#include "trace-cmd.h"
20#include "list.h"
20 21
21/* for debugging read instead of mmap */ 22/* for debugging read instead of mmap */
22static int force_read = 0; 23static int force_read = 0;
23 24
25struct page {
26 struct list_head list;
27 off64_t offset;
28 struct tracecmd_input *handle;
29 void *map;
30 int ref_count;
31};
32
24struct cpu_data { 33struct cpu_data {
25 /* the first two never change */ 34 /* the first two never change */
26 unsigned long long file_offset; 35 unsigned long long file_offset;
@@ -28,28 +37,27 @@ struct cpu_data {
28 unsigned long long offset; 37 unsigned long long offset;
29 unsigned long long size; 38 unsigned long long size;
30 unsigned long long timestamp; 39 unsigned long long timestamp;
40 struct list_head pages;
31 struct record *next; 41 struct record *next;
32 char *page; 42 struct page *page;
33 void *read_page;
34 int cpu; 43 int cpu;
35 int index; 44 int index;
36 int page_size; 45 int page_size;
37}; 46};
38 47
39struct tracecmd_input { 48struct tracecmd_input {
40 struct pevent *pevent; 49 struct pevent *pevent;
41 int fd; 50 int fd;
42 int long_size; 51 int long_size;
43 int page_size; 52 int page_size;
44 int read_page; 53 int read_page;
45 int cpus; 54 int cpus;
46 struct cpu_data *cpu_data; 55 struct cpu_data *cpu_data;
47 56
48 /* file information */ 57 /* file information */
49 size_t header_files_start; 58 size_t header_files_start;
50 size_t ftrace_files_start; 59 size_t ftrace_files_start;
51 size_t event_files_start; 60 size_t event_files_start;
52
53}; 61};
54 62
55__thread struct tracecmd_input *tracecmd_curr_thread_handle; 63__thread struct tracecmd_input *tracecmd_curr_thread_handle;
@@ -109,7 +117,7 @@ static char *read_string(struct tracecmd_input *handle)
109 } 117 }
110 if (i < r) 118 if (i < r)
111 break; 119 break;
112 120
113 if (str) { 121 if (str) {
114 size += BUFSIZ; 122 size += BUFSIZ;
115 str = realloc(str, size); 123 str = realloc(str, size);
@@ -121,7 +129,7 @@ static char *read_string(struct tracecmd_input *handle)
121 str = malloc(size); 129 str = malloc(size);
122 if (!str) 130 if (!str)
123 return NULL; 131 return NULL;
124 memcpy(str, buf, size); 132 memcpy(str, buf, size);
125 } 133 }
126 } 134 }
127 135
@@ -504,7 +512,97 @@ static unsigned int read_type_len_ts(struct tracecmd_input *handle, void *ptr)
504static int calc_index(struct tracecmd_input *handle, 512static int calc_index(struct tracecmd_input *handle,
505 void *ptr, int cpu) 513 void *ptr, int cpu)
506{ 514{
507 return (unsigned long)ptr - (unsigned long)handle->cpu_data[cpu].page; 515 return (unsigned long)ptr - (unsigned long)handle->cpu_data[cpu].page->map;
516}
517
518
519static int read_page(struct tracecmd_input *handle, off64_t offset,
520 void *map)
521{
522 off64_t save_seek;
523 off64_t ret;
524
525 /* other parts of the code may expect the pointer to not move */
526 save_seek = lseek64(handle->fd, 0, SEEK_CUR);
527
528 ret = lseek64(handle->fd, offset, SEEK_SET);
529 if (ret < 0)
530 return -1;
531 ret = read(handle->fd, map, handle->page_size);
532 if (ret < 0)
533 return -1;
534
535 /* reset the file pointer back */
536 lseek64(handle->fd, save_seek, SEEK_SET);
537
538 return 0;
539}
540
541static struct page *allocate_page(struct tracecmd_input *handle,
542 int cpu, off64_t offset)
543{
544 struct cpu_data *cpu_data = &handle->cpu_data[cpu];
545 struct page *page;
546 int ret;
547
548 list_for_each_entry(page, &cpu_data->pages, struct page, list) {
549 if (page->offset == offset) {
550 page->ref_count++;
551 return page;
552 }
553 }
554
555 page = malloc(sizeof(*page));
556 if (!page)
557 return NULL;
558
559 memset(page, 0, sizeof(*page));
560 page->offset = offset;
561 page->handle = handle;
562
563 if (handle->read_page) {
564 page->map = malloc(handle->page_size);
565 if (page->map) {
566 ret = read_page(handle, offset, page->map);
567 if (ret < 0) {
568 free(page->map);
569 page->map = NULL;
570 }
571 }
572 } else {
573 page->map = mmap(NULL, handle->page_size, PROT_READ, MAP_PRIVATE,
574 handle->fd, offset);
575 if (page->map == MAP_FAILED)
576 page->map = NULL;
577 }
578
579 if (!page->map) {
580 free(page);
581 return NULL;
582 }
583
584 list_add(&page->list, &cpu_data->pages);
585 page->ref_count = 1;
586
587 return page;
588}
589
590static void __free_page(struct tracecmd_input *handle, struct page *page)
591{
592 if (!page->ref_count)
593 die("Page ref count is zero!\n");
594
595 page->ref_count--;
596 if (page->ref_count)
597 return;
598
599 if (handle->read_page)
600 free(page->map);
601 else
602 munmap(page->map, handle->page_size);
603
604 list_del(&page->list);
605 free(page);
508} 606}
509 607
510static void free_page(struct tracecmd_input *handle, int cpu) 608static void free_page(struct tracecmd_input *handle, int cpu)
@@ -512,17 +610,19 @@ static void free_page(struct tracecmd_input *handle, int cpu)
512 if (!handle->cpu_data[cpu].page) 610 if (!handle->cpu_data[cpu].page)
513 return; 611 return;
514 612
515 if (!handle->read_page) 613 __free_page(handle, handle->cpu_data[cpu].page);
516 munmap(handle->cpu_data[cpu].page, handle->page_size);
517 614
518 handle->cpu_data[cpu].page = NULL; 615 handle->cpu_data[cpu].page = NULL;
519} 616}
520 617
521static void free_read_page(struct tracecmd_input *handle, int cpu) 618void free_record(struct record *record)
522{ 619{
523 free_page(handle, cpu); 620 if (record->private) {
524 if (handle->read_page) 621 struct page *page = record->private;
525 free(handle->cpu_data[cpu].read_page); 622 __free_page(page->handle, page);
623 }
624
625 free(record);
526} 626}
527 627
528/* 628/*
@@ -531,7 +631,7 @@ static void free_read_page(struct tracecmd_input *handle, int cpu)
531static int update_page_info(struct tracecmd_input *handle, int cpu) 631static int update_page_info(struct tracecmd_input *handle, int cpu)
532{ 632{
533 struct pevent *pevent = handle->pevent; 633 struct pevent *pevent = handle->pevent;
534 void *ptr = handle->cpu_data[cpu].page; 634 void *ptr = handle->cpu_data[cpu].page->map;
535 635
536 /* FIXME: handle header page */ 636 /* FIXME: handle header page */
537 if (pevent->header_page_ts_size != 8) { 637 if (pevent->header_page_ts_size != 8) {
@@ -558,35 +658,6 @@ static int update_page_info(struct tracecmd_input *handle, int cpu)
558 return 0; 658 return 0;
559} 659}
560 660
561static int get_read_page(struct tracecmd_input *handle, int cpu,
562 off64_t offset)
563{
564 off64_t save_seek;
565 off64_t ret;
566
567 free_page(handle, cpu);
568
569 handle->cpu_data[cpu].page = handle->cpu_data[cpu].read_page;
570
571 /* other parts of the code may expect the pointer to not move */
572 save_seek = lseek64(handle->fd, 0, SEEK_CUR);
573
574 ret = lseek64(handle->fd, offset, SEEK_SET);
575 if (ret < 0)
576 return -1;
577 ret = read(handle->fd, handle->cpu_data[cpu].page, handle->page_size);
578 if (ret < 0)
579 return -1;
580
581 /* reset the file pointer back */
582 lseek64(handle->fd, save_seek, SEEK_SET);
583
584 if (update_page_info(handle, cpu))
585 return -1;
586
587 return 0;
588}
589
590/* 661/*
591 * get_page maps a page for a given cpu. 662 * get_page maps a page for a given cpu.
592 * 663 *
@@ -623,15 +694,10 @@ static int get_page(struct tracecmd_input *handle, int cpu,
623 handle->cpu_data[cpu].file_size) - 694 handle->cpu_data[cpu].file_size) -
624 offset; 695 offset;
625 696
626 if (handle->read_page) 697 free_page(handle, cpu);
627 return get_read_page(handle, cpu, offset);
628
629 if (handle->cpu_data[cpu].page)
630 free_page(handle, cpu);
631 698
632 handle->cpu_data[cpu].page = mmap(NULL, handle->page_size, PROT_READ, MAP_PRIVATE, 699 handle->cpu_data[cpu].page = allocate_page(handle, cpu, offset);
633 handle->fd, offset); 700 if (!handle->cpu_data[cpu].page)
634 if (handle->cpu_data[cpu].page == MAP_FAILED)
635 return -1; 701 return -1;
636 702
637 if (update_page_info(handle, cpu)) 703 if (update_page_info(handle, cpu))
@@ -876,7 +942,7 @@ int tracecmd_refresh_record(struct tracecmd_input *handle,
876 if (ret) 942 if (ret)
877 return 1; 943 return 1;
878 944
879 record->data = cpu_data->page + index; 945 record->data = cpu_data->page->map + index;
880 946
881 type_len_ts = read_type_len_ts(handle, record->data); 947 type_len_ts = read_type_len_ts(handle, record->data);
882 len = len4host(handle, type_len_ts); 948 len = len4host(handle, type_len_ts);
@@ -1140,9 +1206,9 @@ tracecmd_peek_data(struct tracecmd_input *handle, int cpu)
1140{ 1206{
1141 struct pevent *pevent = handle->pevent; 1207 struct pevent *pevent = handle->pevent;
1142 struct record *record; 1208 struct record *record;
1143 void *page = handle->cpu_data[cpu].page; 1209 struct page *page = handle->cpu_data[cpu].page;
1144 int index = handle->cpu_data[cpu].index; 1210 int index = handle->cpu_data[cpu].index;
1145 void *ptr = page + index; 1211 void *ptr;
1146 unsigned long long extend; 1212 unsigned long long extend;
1147 unsigned int type_len; 1213 unsigned int type_len;
1148 int length; 1214 int length;
@@ -1176,8 +1242,10 @@ tracecmd_peek_data(struct tracecmd_input *handle, int cpu)
1176 if (!page) 1242 if (!page)
1177 return NULL; 1243 return NULL;
1178 1244
1245 ptr = page->map + index;
1246
1179 if (!index) 1247 if (!index)
1180 ptr = handle->cpu_data[cpu].page + pevent->header_page_data_offset; 1248 ptr = handle->cpu_data[cpu].page->map + pevent->header_page_data_offset;
1181 1249
1182read_again: 1250read_again:
1183 index = calc_index(handle, ptr, cpu); 1251 index = calc_index(handle, ptr, cpu);
@@ -1236,6 +1304,8 @@ read_again:
1236 handle->cpu_data[cpu].next = record; 1304 handle->cpu_data[cpu].next = record;
1237 1305
1238 record->record_size = handle->cpu_data[cpu].index - index; 1306 record->record_size = handle->cpu_data[cpu].index - index;
1307 record->private = page;
1308 page->ref_count++;
1239 1309
1240 return record; 1310 return record;
1241} 1311}
@@ -1261,63 +1331,37 @@ tracecmd_read_data(struct tracecmd_input *handle, int cpu)
1261 return record; 1331 return record;
1262} 1332}
1263 1333
1264static int init_read(struct tracecmd_input *handle, int cpu)
1265{
1266 off64_t ret;
1267 off64_t save_seek;
1268
1269 handle->cpu_data[cpu].read_page = malloc(handle->page_size);
1270 if (!handle->cpu_data[cpu].read_page)
1271 return -1;
1272
1273 handle->cpu_data[cpu].page = handle->cpu_data[cpu].read_page;
1274
1275 /* other parts of the code may expect the pointer to not move */
1276 save_seek = lseek64(handle->fd, 0, SEEK_CUR);
1277
1278 ret = lseek64(handle->fd, (off64_t)handle->cpu_data[cpu].offset, SEEK_SET);
1279 if (ret < 0)
1280 return -1;
1281 ret = read(handle->fd, handle->cpu_data[cpu].page, handle->page_size);
1282 if (ret < 0)
1283 return -1;
1284
1285 /* reset the file pointer back */
1286 lseek64(handle->fd, save_seek, SEEK_SET);
1287
1288 handle->cpu_data[cpu].timestamp =
1289 data2host8(handle->pevent, handle->cpu_data[cpu].page);
1290
1291 return 0;
1292}
1293
1294static int init_cpu(struct tracecmd_input *handle, int cpu) 1334static int init_cpu(struct tracecmd_input *handle, int cpu)
1295{ 1335{
1296 handle->cpu_data[cpu].offset = handle->cpu_data[cpu].file_offset; 1336 struct cpu_data *cpu_data = &handle->cpu_data[cpu];
1297 handle->cpu_data[cpu].size = handle->cpu_data[cpu].file_size; 1337
1298 handle->cpu_data[cpu].timestamp = 0; 1338 cpu_data->offset = cpu_data->file_offset;
1339 cpu_data->size = cpu_data->file_size;
1340 cpu_data->timestamp = 0;
1299 1341
1300 if (!handle->cpu_data[cpu].size) { 1342 if (!cpu_data->size) {
1301 printf("CPU %d is empty\n", cpu); 1343 printf("CPU %d is empty\n", cpu);
1302 return 0; 1344 return 0;
1303 } 1345 }
1304 1346
1305 if (handle->read_page) 1347 list_head_init(&cpu_data->pages);
1306 return init_read(handle, cpu);
1307 1348
1308 if (!force_read) { 1349 cpu_data->page = allocate_page(handle, cpu, cpu_data->offset);
1309 handle->cpu_data[cpu].page = mmap(NULL, handle->page_size, PROT_READ, 1350 if (!cpu_data->page && !handle->read_page) {
1310 MAP_PRIVATE, handle->fd, handle->cpu_data[cpu].offset);
1311 }
1312 if (force_read || handle->cpu_data[cpu].page == MAP_FAILED) {
1313 /* fall back to just reading pages */
1314 perror("mmap"); 1351 perror("mmap");
1315 fprintf(stderr, "Can not mmap file, will read instead\n"); 1352 fprintf(stderr, "Can not mmap file, will read instead\n");
1316 handle->read_page = 1;
1317 1353
1318 return init_read(handle, cpu); 1354 if (cpu)
1319 } 1355 /* Other CPUs worked! bail */
1356 return -1;
1320 1357
1358 /* try again without mmapping, just read it directly */
1359 handle->read_page = 1;
1360 cpu_data->page = allocate_page(handle, cpu, cpu_data->offset);
1361 if (!cpu_data->page)
1362 /* Still no luck, bail! */
1363 return -1;
1364 }
1321 1365
1322 if (update_page_info(handle, cpu)) 1366 if (update_page_info(handle, cpu))
1323 return -1; 1367 return -1;
@@ -1374,6 +1418,9 @@ int tracecmd_init_data(struct tracecmd_input *handle)
1374 return -1; 1418 return -1;
1375 memset(handle->cpu_data, 0, sizeof(*handle->cpu_data) * handle->cpus); 1419 memset(handle->cpu_data, 0, sizeof(*handle->cpu_data) * handle->cpus);
1376 1420
1421 if (force_read)
1422 handle->read_page = 1;
1423
1377 for (cpu = 0; cpu < handle->cpus; cpu++) { 1424 for (cpu = 0; cpu < handle->cpus; cpu++) {
1378 unsigned long long offset; 1425 unsigned long long offset;
1379 1426
@@ -1498,8 +1545,20 @@ void tracecmd_close(struct tracecmd_input *handle)
1498 if (!handle) 1545 if (!handle)
1499 return; 1546 return;
1500 1547
1501 for (cpu = 0; cpu < handle->cpus; cpu++) 1548 for (cpu = 0; cpu < handle->cpus; cpu++) {
1502 free_read_page(handle, cpu); 1549 struct record *rec;
1550 /*
1551 * The tracecmd_peek_data may have cached a record
1552 * Do a read to flush it out.
1553 */
1554 rec = tracecmd_read_data(handle, cpu);
1555 if (rec)
1556 free_record(rec);
1557 free_page(handle, cpu);
1558 if (!list_empty(&handle->cpu_data[cpu].pages))
1559 warning("pages still allocated on cpu %d", cpu);
1560 }
1561
1503 free(handle->cpu_data); 1562 free(handle->cpu_data);
1504 1563
1505 close(handle->fd); 1564 close(handle->fd);