diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-02-21 17:08:09 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-02-21 20:42:08 -0500 |
commit | 37770884230fd0bbe369782f2a8a676d695d59d2 (patch) | |
tree | d04db2f623332340e5a0a356e551f26b41c26b77 | |
parent | 0065086821e17f8f0402760aac23069b8970eb39 (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.h | 9 | ||||
-rw-r--r-- | trace-input.c | 66 |
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 | |||
38 | struct record { | 42 | struct 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 | ||
59 | struct cpu_data { | 62 | struct 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 | ||
99 | static 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 | } | ||
108 | static 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 | } | ||
116 | static 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 | ||
137 | static inline void remove_record(struct page *page, struct record *record) {} | ||
138 | static inline void add_record(struct page *page, struct record *record) {} | ||
139 | static const char *show_records(struct list_head *pages) | ||
140 | { | ||
141 | return ""; | ||
142 | } | ||
143 | #endif | ||
144 | |||
95 | static int init_cpu(struct tracecmd_input *handle, int cpu); | 145 | static int init_cpu(struct tracecmd_input *handle, int cpu); |
96 | 146 | ||
97 | static int do_read(struct tracecmd_input *handle, void *data, int size) | 147 | static 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) | |||
678 | void tracecmd_record_ref(struct record *record) | 729 | void 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 | ||
683 | static void free_next(struct tracecmd_input *handle, int cpu) | 738 | static 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); |