aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-02-21 17:08:09 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-02-21 20:42:08 -0500
commit37770884230fd0bbe369782f2a8a676d695d59d2 (patch)
treed04db2f623332340e5a0a356e551f26b41c26b77
parent0065086821e17f8f0402760aac23069b8970eb39 (diff)
trace-cmd: Add debugging to find where leaked records are
Add DEBUG_RECORD macro that records the address of the caller to get a record, and if there are leaked records existing, print out where the extra records were allocated from. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--parse-events.h9
-rw-r--r--trace-input.c66
2 files changed, 72 insertions, 3 deletions
diff --git a/parse-events.h b/parse-events.h
index 3a4ef08..5c58b62 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -35,6 +35,10 @@
35#define TRACE_SEQ_BUF_SIZE 4096 35#define TRACE_SEQ_BUF_SIZE 4096
36#endif 36#endif
37 37
38#ifndef DEBUG_RECORD
39#define DEBUG_RECORD 0
40#endif
41
38struct record { 42struct record {
39 unsigned long long ts; 43 unsigned long long ts;
40 unsigned long long offset; 44 unsigned long long offset;
@@ -46,6 +50,11 @@ struct record {
46 int ref_count; 50 int ref_count;
47 int locked; /* Do not free, even if ref_count is zero */ 51 int locked; /* Do not free, even if ref_count is zero */
48 void *private; 52 void *private;
53#if DEBUG_RECORD
54 struct record *prev;
55 struct record *next;
56 long alloc_addr;
57#endif
49}; 58};
50 59
51/* 60/*
diff --git a/trace-input.c b/trace-input.c
index 62e9f3f..377ace7 100644
--- a/trace-input.c
+++ b/trace-input.c
@@ -54,6 +54,9 @@ struct page {
54 void *map; 54 void *map;
55 int ref_count; 55 int ref_count;
56 long long lost_events; 56 long long lost_events;
57#if DEBUG_RECORD
58 struct record *records;
59#endif
57}; 60};
58 61
59struct cpu_data { 62struct cpu_data {
@@ -92,6 +95,53 @@ struct tracecmd_input {
92 95
93__thread struct tracecmd_input *tracecmd_curr_thread_handle; 96__thread struct tracecmd_input *tracecmd_curr_thread_handle;
94 97
98#if DEBUG_RECORD
99static void remove_record(struct page *page, struct record *record)
100{
101 if (record->prev)
102 record->prev->next = record->next;
103 else
104 page->records = record->next;
105 if (record->next)
106 record->next->prev = record->prev;
107}
108static void add_record(struct page *page, struct record *record)
109{
110 if (page->records)
111 page->records->prev = record;
112 record->next = page->records;
113 record->prev = NULL;
114 page->records = record;
115}
116static const char *show_records(struct list_head *pages)
117{
118 static char buf[BUFSIZ + 1];
119 struct record *record;
120 struct page *page;
121 int len;
122
123 memset(buf, 0, sizeof(buf));
124 len = 0;
125 list_for_each_entry(page, pages, struct page, list) {
126 for (record = page->records; record; record = record->next) {
127 int n;
128 n = snprintf(buf+len, BUFSIZ - len, " 0x%lx", record->alloc_addr);
129 len += n;
130 if (len >= BUFSIZ)
131 break;
132 }
133 }
134 return buf;
135}
136#else
137static inline void remove_record(struct page *page, struct record *record) {}
138static inline void add_record(struct page *page, struct record *record) {}
139static const char *show_records(struct list_head *pages)
140{
141 return "";
142}
143#endif
144
95static int init_cpu(struct tracecmd_input *handle, int cpu); 145static int init_cpu(struct tracecmd_input *handle, int cpu);
96 146
97static int do_read(struct tracecmd_input *handle, void *data, int size) 147static int do_read(struct tracecmd_input *handle, void *data, int size)
@@ -648,6 +698,7 @@ static void __free_record(struct record *record)
648{ 698{
649 if (record->private) { 699 if (record->private) {
650 struct page *page = record->private; 700 struct page *page = record->private;
701 remove_record(page, record);
651 __free_page(page->handle, page); 702 __free_page(page->handle, page);
652 } 703 }
653 704
@@ -678,6 +729,10 @@ void free_record(struct record *record)
678void tracecmd_record_ref(struct record *record) 729void tracecmd_record_ref(struct record *record)
679{ 730{
680 record->ref_count++; 731 record->ref_count++;
732#if DEBUG_RECORD
733 /* Update locating of last reference */
734 record->alloc_addr = (unsigned long)__builtin_return_address(0);
735#endif
681} 736}
682 737
683static void free_next(struct tracecmd_input *handle, int cpu) 738static void free_next(struct tracecmd_input *handle, int cpu)
@@ -1583,6 +1638,7 @@ read_again:
1583 1638
1584 record->record_size = handle->cpu_data[cpu].index - index; 1639 record->record_size = handle->cpu_data[cpu].index - index;
1585 record->private = page; 1640 record->private = page;
1641 add_record(page, record);
1586 page->ref_count++; 1642 page->ref_count++;
1587 1643
1588 return record; 1644 return record;
@@ -1605,9 +1661,12 @@ tracecmd_read_data(struct tracecmd_input *handle, int cpu)
1605 1661
1606 record = tracecmd_peek_data(handle, cpu); 1662 record = tracecmd_peek_data(handle, cpu);
1607 handle->cpu_data[cpu].next = NULL; 1663 handle->cpu_data[cpu].next = NULL;
1608 if (record) 1664 if (record) {
1609 record->locked = 0; 1665 record->locked = 0;
1610 1666#if DEBUG_RECORD
1667 record->alloc_addr = (unsigned long)__builtin_return_address(0);
1668#endif
1669 }
1611 return record; 1670 return record;
1612} 1671}
1613 1672
@@ -2124,7 +2183,8 @@ void tracecmd_close(struct tracecmd_input *handle)
2124 free_next(handle, cpu); 2183 free_next(handle, cpu);
2125 free_page(handle, cpu); 2184 free_page(handle, cpu);
2126 if (!list_empty(&handle->cpu_data[cpu].pages)) 2185 if (!list_empty(&handle->cpu_data[cpu].pages))
2127 warning("pages still allocated on cpu %d", cpu); 2186 warning("pages still allocated on cpu %d%s",
2187 cpu, show_records(&handle->cpu_data[cpu].pages));
2128 } 2188 }
2129 2189
2130 free(handle->cpu_data); 2190 free(handle->cpu_data);