| 1 | /* This file is part of the Linux Trace Toolkit viewer |
| 2 | * Copyright (C) 2003-2004 Michel Dagenais |
| 3 | * Copyright (C) 2012 Yannick Brosseau |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License Version 2 as |
| 7 | * published by the Free Software Foundation; |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write to the Free Software |
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
| 17 | * MA 02111-1307, USA. |
| 18 | */ |
| 19 | #ifdef HAVE_CONFIG_H |
| 20 | #include <config.h> |
| 21 | #endif |
| 22 | |
| 23 | #include <lttv/traceset-process.h> |
| 24 | #include <lttv/traceset.h> |
| 25 | #include <lttv/event.h> |
| 26 | #include <babeltrace/context.h> |
| 27 | #include <babeltrace/iterator.h> |
| 28 | #include <babeltrace/trace-handle.h> |
| 29 | #include <babeltrace/ctf/events.h> |
| 30 | #include <babeltrace/ctf/iterator.h> |
| 31 | |
| 32 | void lttv_process_traceset_begin(LttvTraceset *traceset, |
| 33 | LttvHooks *before_traceset, |
| 34 | LttvHooks *before_trace, |
| 35 | LttvHooks *event) |
| 36 | { |
| 37 | struct bt_iter_pos begin_pos; |
| 38 | /* simply add hooks in context. _before hooks are called by add_hooks. */ |
| 39 | /* It calls all before_traceset, before_trace, and before_tracefile hooks. */ |
| 40 | lttv_traceset_add_hooks(traceset, |
| 41 | before_traceset, |
| 42 | before_trace, |
| 43 | event); |
| 44 | |
| 45 | |
| 46 | |
| 47 | begin_pos.type = BT_SEEK_BEGIN; |
| 48 | |
| 49 | if(!traceset->iter) { |
| 50 | traceset->iter = bt_ctf_iter_create(lttv_traceset_get_context(traceset), |
| 51 | &begin_pos, |
| 52 | NULL); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | guint lttv_process_traceset_middle(LttvTraceset *traceset, |
| 57 | LttTime end, |
| 58 | gulong nb_events, |
| 59 | const LttvTracesetPosition *end_position) |
| 60 | { |
| 61 | unsigned count = 0; |
| 62 | gint last_ret = 0; |
| 63 | LttvTracesetPosition *currentPos; |
| 64 | |
| 65 | struct bt_ctf_event *bt_event; |
| 66 | |
| 67 | LttvEvent event; |
| 68 | LttTime endPositionTime; |
| 69 | |
| 70 | if(end_position) { |
| 71 | endPositionTime = lttv_traceset_position_get_time(end_position); |
| 72 | } |
| 73 | while(TRUE) { |
| 74 | |
| 75 | if(last_ret == TRUE || ((count >= nb_events) && (nb_events != G_MAXULONG))) { |
| 76 | break; |
| 77 | } |
| 78 | |
| 79 | if((bt_event = bt_ctf_iter_read_event(traceset->iter)) != NULL) { |
| 80 | |
| 81 | LttTime time = ltt_time_from_uint64(bt_ctf_get_timestamp(bt_event)); |
| 82 | if(ltt_time_compare(end, time) <= 0) { |
| 83 | break; |
| 84 | } |
| 85 | /* |
| 86 | currentPos = lttv_traceset_create_current_position(traceset); |
| 87 | if(lttv_traceset_position_compare(currentPos,end_position ) == 0){ |
| 88 | lttv_traceset_destroy_position(currentPos); |
| 89 | break; |
| 90 | } |
| 91 | lttv_traceset_destroy_position(currentPos); |
| 92 | */ |
| 93 | if(end_position && (ltt_time_compare(endPositionTime, time) <= 0)) { |
| 94 | break; |
| 95 | } |
| 96 | count++; |
| 97 | |
| 98 | event.bt_event = bt_event; |
| 99 | |
| 100 | /* Retrieve the associated state */ |
| 101 | event.state = g_ptr_array_index(traceset->state_trace_handle_index, |
| 102 | bt_ctf_event_get_handle_id(bt_event)); |
| 103 | |
| 104 | last_ret = lttv_hooks_call(traceset->event_hooks, &event); |
| 105 | |
| 106 | if(bt_iter_next(bt_ctf_get_iter(traceset->iter)) < 0) { |
| 107 | printf("ERROR NEXT\n"); |
| 108 | break; |
| 109 | } |
| 110 | } else { |
| 111 | /* READ FAILED */ |
| 112 | |
| 113 | break; |
| 114 | |
| 115 | } |
| 116 | } |
| 117 | return count; |
| 118 | } |
| 119 | |
| 120 | void lttv_process_traceset_end(LttvTraceset *traceset, |
| 121 | LttvHooks *after_traceset, |
| 122 | LttvHooks *after_trace, |
| 123 | LttvHooks *event) |
| 124 | { |
| 125 | /* Remove hooks from context. _after hooks are called by remove_hooks. */ |
| 126 | /* It calls all after_traceset, after_trace, and after_tracefile hooks. */ |
| 127 | lttv_traceset_remove_hooks(traceset, |
| 128 | after_traceset, |
| 129 | after_trace, |
| 130 | event); |
| 131 | |
| 132 | } |
| 133 | |
| 134 | |
| 135 | void lttv_traceset_add_hooks(LttvTraceset *traceset, |
| 136 | LttvHooks *before_traceset, |
| 137 | LttvHooks *before_trace, |
| 138 | LttvHooks *event) |
| 139 | { |
| 140 | guint i, nb_trace; |
| 141 | |
| 142 | LttvTrace *trace; |
| 143 | |
| 144 | lttv_hooks_call(before_traceset, traceset); |
| 145 | |
| 146 | lttv_hooks_add_list(traceset->event_hooks, event); |
| 147 | |
| 148 | nb_trace = lttv_traceset_number(traceset); |
| 149 | |
| 150 | for(i = 0 ; i < nb_trace ; i++) { |
| 151 | trace = (LttvTrace *)g_ptr_array_index(traceset->traces,i); |
| 152 | lttv_trace_add_hooks(trace, |
| 153 | before_trace, |
| 154 | event |
| 155 | ); |
| 156 | } |
| 157 | } |
| 158 | void lttv_traceset_remove_hooks(LttvTraceset *traceset, |
| 159 | LttvHooks *after_traceset, |
| 160 | LttvHooks *after_trace, |
| 161 | LttvHooks *event) |
| 162 | { |
| 163 | guint i, nb_trace; |
| 164 | |
| 165 | LttvTrace *trace; |
| 166 | |
| 167 | nb_trace = lttv_traceset_number(traceset); |
| 168 | |
| 169 | for(i = 0 ; i < nb_trace ; i++) { |
| 170 | trace = (LttvTrace *)g_ptr_array_index(traceset->traces,i); |
| 171 | lttv_trace_remove_hooks(trace, |
| 172 | after_trace, |
| 173 | event); |
| 174 | |
| 175 | } |
| 176 | |
| 177 | lttv_hooks_remove_list(traceset->event_hooks, event); |
| 178 | lttv_hooks_call(after_traceset, traceset); |
| 179 | |
| 180 | |
| 181 | } |
| 182 | |
| 183 | |
| 184 | void lttv_trace_add_hooks(LttvTrace *trace, |
| 185 | LttvHooks *before_trace, |
| 186 | LttvHooks *event) |
| 187 | { |
| 188 | lttv_hooks_call(before_trace, trace); |
| 189 | } |
| 190 | |
| 191 | void lttv_trace_remove_hooks(LttvTrace *trace, |
| 192 | LttvHooks *after_trace, |
| 193 | LttvHooks *event) |
| 194 | |
| 195 | { |
| 196 | lttv_hooks_call(after_trace, trace); |
| 197 | } |
| 198 | |
| 199 | void lttv_process_traceset_seek_time(LttvTraceset *traceset, LttTime start) |
| 200 | { |
| 201 | struct bt_iter_pos seekpos; |
| 202 | int ret; |
| 203 | if (traceset->iter == NULL) { |
| 204 | g_warning("Iterator not valid in seek_time"); |
| 205 | return; |
| 206 | } |
| 207 | seekpos.type = BT_SEEK_TIME; |
| 208 | seekpos.u.seek_time = ltt_time_to_uint64(start); |
| 209 | |
| 210 | ret = bt_iter_set_pos(bt_ctf_get_iter(traceset->iter), &seekpos); |
| 211 | if(ret < 0) { |
| 212 | printf("Seek by time error: %s,\n",strerror(-ret)); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | guint lttv_process_traceset_seek_n_forward(LttvTraceset *traceset, |
| 217 | guint n, |
| 218 | check_handler *check, |
| 219 | gboolean *stop_flag, |
| 220 | LttvFilter *filter1, |
| 221 | LttvFilter *filter2, |
| 222 | LttvFilter *filter3, |
| 223 | gpointer data) |
| 224 | { |
| 225 | unsigned count = 0; |
| 226 | while(count < n) { |
| 227 | if(bt_iter_next(bt_ctf_get_iter(traceset->iter)) < 0) { |
| 228 | printf("ERROR NEXT\n"); |
| 229 | break; |
| 230 | } |
| 231 | count++; |
| 232 | } |
| 233 | return count; |
| 234 | } |
| 235 | |
| 236 | guint lttv_process_traceset_seek_n_backward(LttvTraceset *ts, |
| 237 | guint n, |
| 238 | gdouble ratio, |
| 239 | check_handler *check, |
| 240 | gboolean *stop_flag, |
| 241 | LttvFilter *filter1, |
| 242 | LttvFilter *filter2, |
| 243 | LttvFilter *filter3, |
| 244 | gpointer data) |
| 245 | { |
| 246 | guint i, count, ret; |
| 247 | gint extraEvent = 0; |
| 248 | guint64 initialTimeStamp, previousTimeStamp; |
| 249 | LttvTracesetPosition *initialPos, *previousPos, *currentPos, beginPos; |
| 250 | struct bt_iter_pos pos; |
| 251 | beginPos.bt_pos = &pos; |
| 252 | beginPos.iter = ts->iter; |
| 253 | beginPos.bt_pos->type = BT_SEEK_BEGIN; |
| 254 | beginPos.timestamp = G_MAXUINT64; |
| 255 | beginPos.cpu_id = INT_MAX; |
| 256 | /*Save initial position of the traceset*/ |
| 257 | initialPos = lttv_traceset_create_current_position (ts); |
| 258 | |
| 259 | /*Get the timespan of the initial position*/ |
| 260 | initialTimeStamp = lttv_traceset_position_get_timestamp(initialPos); |
| 261 | /* |
| 262 | * Create a position before the initial timestamp according |
| 263 | * to the ratio of nanosecond/event hopefully before the |
| 264 | * the desired seek position |
| 265 | */ |
| 266 | while(1){ |
| 267 | previousTimeStamp = initialTimeStamp - n*(guint)ceil(ratio); |
| 268 | |
| 269 | previousPos = lttv_traceset_create_time_position(ts,ltt_time_from_uint64(previousTimeStamp)); |
| 270 | if(initialTimeStamp == previousTimeStamp) |
| 271 | break; |
| 272 | |
| 273 | currentPos = lttv_traceset_create_time_position(ts,ltt_time_from_uint64(previousTimeStamp)); |
| 274 | /*Corner case: When we are near the beginning of the trace and the previousTimeStamp is before |
| 275 | * the beginning of the trace. We have to seek to the first event. |
| 276 | */ |
| 277 | if((lttv_traceset_position_compare(currentPos,&beginPos ) == 0)){ |
| 278 | lttv_traceset_seek_to_position(&beginPos); |
| 279 | break; |
| 280 | } |
| 281 | /*move traceset position */ |
| 282 | lttv_state_traceset_seek_position(ts, previousPos); |
| 283 | /* iterate to the initial position counting the number of event*/ |
| 284 | count = 0; |
| 285 | do { |
| 286 | if((ret = lttv_traceset_position_compare(currentPos,initialPos)) == 1){ |
| 287 | if(bt_iter_next(bt_ctf_get_iter(ts->iter)) == 0) { |
| 288 | if(bt_ctf_iter_read_event(ts->iter) > 0) { |
| 289 | lttv_traceset_destroy_position(currentPos); |
| 290 | currentPos = lttv_traceset_create_current_position(ts); |
| 291 | count++; |
| 292 | } else { |
| 293 | break; |
| 294 | } |
| 295 | |
| 296 | } else { |
| 297 | |
| 298 | //No more event available |
| 299 | break; |
| 300 | } |
| 301 | } |
| 302 | }while(ret != 0); |
| 303 | |
| 304 | /*substract the desired number of event to the count*/ |
| 305 | extraEvent = count - n; |
| 306 | if (extraEvent >= 0) { |
| 307 | //if the extraEvent is over 0 go back to previousPos and |
| 308 | //move forward the value of extraEvent times |
| 309 | lttv_state_traceset_seek_position(ts, previousPos); |
| 310 | |
| 311 | for(i = 0 ; i < extraEvent ; i++){ |
| 312 | if(bt_iter_next(bt_ctf_get_iter(ts->iter)) < 0){ |
| 313 | printf("ERROR NEXT\n"); |
| 314 | break; |
| 315 | } |
| 316 | |
| 317 | } |
| 318 | break; /* we successfully seeked backward */ |
| 319 | } |
| 320 | else{ |
| 321 | /* if the extraEvent is below 0 create a position before and start over*/ |
| 322 | ratio = ratio * 16; |
| 323 | } |
| 324 | lttv_traceset_destroy_position(currentPos); |
| 325 | } |
| 326 | return 0; |
| 327 | } |