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 | ||
