diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-12-18 13:28:16 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2009-12-18 13:28:16 -0500 |
commit | b05f27dc7d0dab346e20795ce4d9f6d56d3e18ea (patch) | |
tree | f04d884bb24f28edcdaf7a01119e11e1eca1badf | |
parent | d889066760e48795b4c778e4589ec089e41f009d (diff) |
trace-cmd: Have function graph keep record around
The function graph tracer looks forward in the trace to determine
if a function is a leaf or not. In doing so, it causes the mapping
of records to change. This produces a nasty side effect where the
caller can have the record stored, and it will suddenly invalidate
the record's mapping.
This refreshes the record passed in and does a trick by calling
the tracecmd_peek_data function that will cache the location
after the leaf function's return entry.
This unfortunately causes a side effect too where if the last
entry in the trace is a leaf function, we can't hide the exit entry
and it will print regardless. But this side effect wont crash the
application, but the previous side effect will.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | trace-ftrace.c | 29 | ||||
-rw-r--r-- | trace-input.c | 18 |
2 files changed, 44 insertions, 3 deletions
diff --git a/trace-ftrace.c b/trace-ftrace.c index 0920430..459f74b 100644 --- a/trace-ftrace.c +++ b/trace-ftrace.c | |||
@@ -250,12 +250,37 @@ fgraph_ent_handler(struct trace_seq *s, struct record *record, | |||
250 | rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); | 250 | rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); |
251 | if (rec) | 251 | if (rec) |
252 | rec = get_return_for_leaf(s, cpu, pid, val, rec); | 252 | rec = get_return_for_leaf(s, cpu, pid, val, rec); |
253 | if (rec) | 253 | |
254 | if (rec) { | ||
255 | /* | ||
256 | * The record returned needs to be freed. | ||
257 | * We also do a new peek on this CPU to update the | ||
258 | * record cache. (peek caches the record, but the | ||
259 | * refresh below will update the CPU iterator. | ||
260 | * If peek has a record in cache, it will update the | ||
261 | * iterator to that) | ||
262 | */ | ||
254 | ret = print_graph_entry_leaf(s, event, data, rec); | 263 | ret = print_graph_entry_leaf(s, event, data, rec); |
255 | else | 264 | free_record(rec); |
265 | tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); | ||
266 | } else | ||
256 | ret = print_graph_nested(s, event, data); | 267 | ret = print_graph_nested(s, event, data); |
257 | 268 | ||
258 | free(data); | 269 | free(data); |
270 | |||
271 | /* | ||
272 | * The above peek may unmap the record given to us. | ||
273 | * But callers may still have a reference to that record. | ||
274 | * We need to make sure it is still mapped. | ||
275 | * | ||
276 | * Note, this causes a known bug. If the last item in the trace | ||
277 | * was a leaf function, we can't remove it. The peek cache | ||
278 | * above will be NULL (no records after the leaf) so a new peek | ||
279 | * will simply read the return entry of the leaf and print it | ||
280 | * again. | ||
281 | */ | ||
282 | tracecmd_refresh_record(tracecmd_curr_thread_handle, | ||
283 | record); | ||
259 | return ret; | 284 | return ret; |
260 | } | 285 | } |
261 | 286 | ||
diff --git a/trace-input.c b/trace-input.c index 5c8dfae..8cc8865 100644 --- a/trace-input.c +++ b/trace-input.c | |||
@@ -1137,13 +1137,29 @@ tracecmd_peek_data(struct tracecmd_input *handle, int cpu) | |||
1137 | unsigned long long extend; | 1137 | unsigned long long extend; |
1138 | unsigned int type_len; | 1138 | unsigned int type_len; |
1139 | int length; | 1139 | int length; |
1140 | int ret; | ||
1140 | 1141 | ||
1141 | /* Hack to work around function graph read ahead */ | 1142 | /* Hack to work around function graph read ahead */ |
1142 | tracecmd_curr_thread_handle = handle; | 1143 | tracecmd_curr_thread_handle = handle; |
1143 | 1144 | ||
1144 | if (handle->cpu_data[cpu].next) { | 1145 | if (handle->cpu_data[cpu].next) { |
1145 | /* Make sure it's still mapped */ | 1146 | /* Make sure it's still mapped */ |
1146 | tracecmd_refresh_record(handle, handle->cpu_data[cpu].next); | 1147 | ret = tracecmd_refresh_record(handle, handle->cpu_data[cpu].next); |
1148 | if (ret < 0) { | ||
1149 | free_record(handle->cpu_data[cpu].next); | ||
1150 | handle->cpu_data[cpu].next = NULL; | ||
1151 | return NULL; | ||
1152 | } | ||
1153 | /* | ||
1154 | * Make sure the index and timestamp are where | ||
1155 | * we want them, because the refresh did not update it. | ||
1156 | */ | ||
1157 | if (ret && handle->cpu_data[cpu].timestamp != record->ts) { | ||
1158 | handle->cpu_data[cpu].index = | ||
1159 | (record->offset & (handle->page_size - 1)) + | ||
1160 | record->record_size; | ||
1161 | handle->cpu_data[cpu].timestamp = record->ts; | ||
1162 | } | ||
1147 | return handle->cpu_data[cpu].next; | 1163 | return handle->cpu_data[cpu].next; |
1148 | } | 1164 | } |
1149 | 1165 | ||