1 2 /* 3 * Copyright (C) Texas Instruments - http://www.ti.com/ 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 #ifdef __PERF_READER__ 22 23 #define __DECODE(c) (((c) < 0 || (c) > 63) ? '#' : ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789./_" [c])) 24 25 #include "perf.h" 26 /*============================================================================= 27 DEFINITIONS 28 =============================================================================*/ 29 30 /* minimum and maximum time-correction handled */ 31 #define MIN_DELTA 1U 32 #define MAX_DELTA 4292967295U 33 34 35 /** __PERF_CUSTOMIZABLE__ must be enabled, as we are using the 36 * standard PERF module for printing */ 37 #ifndef __PERF_CUSTOMIZABLE__ 38 #error "Must define __PERF_CUSTOMIZABLE__ to enable printing for reader" 39 #else 40 41 #include "perf_config.h" 42 #include "perf.h" 43 44 #include <errno.h> 45 46 typedef unsigned long U32; 47 48 /*============================================================================= 49 GLOBALS 50 =============================================================================*/ 51 52 static U32 read_U32(FILE *fLog) 53 { 54 U32 data; 55 fread(&data, sizeof(U32), 1, fLog); 56 return(data); 57 } 58 59 PERF_OBJHANDLE __PERF_common_Create(struct PERF_Config *config, 60 unsigned long ulID, 61 PERF_MODULETYPE eModule); 62 void __PERF_CUSTOM_create(PERF_OBJHANDLE hObject, 63 struct PERF_Config *config, 64 PERF_MODULETYPE eModule); 65 66 void PERF_Replay(FILE *fLog, PERF_Config *pConfig) 67 { 68 U32 ulData0, ulData1, ulData2, ulData3, ulData4, ulData5, ulData6, ulData7, operation; 69 char szFile[21], szFunc[21]; 70 U32 sending, multiple, frame, size; 71 PERF_OBJHANDLE hObject = NULL; 72 PERF_Private *me = NULL; 73 long time_correction = 0; 74 union __PERF_float_long uA, uV; 75 76 /* logging is disabled during replay because the __log_ API-s get the 77 time on their own, and are not feasible to be modified to work with 78 replayed times */ 79 if (pConfig->trace_file) 80 { 81 free(pConfig->trace_file); 82 pConfig->trace_file = NULL; 83 } 84 85 /* read initialization info */ 86 87 /* we support having multiple log files concatenated into one log file */ 88 /* read through each log file */ 89 /* we have to pre-read to detect end of file */ 90 while ((ulData0 = read_U32(fLog)), !feof(fLog)) 91 { 92 93 /* if there is no object, create one */ 94 if (!hObject) 95 { 96 /* create PERF replay object */ 97 /* pre-read word is the eModuleType */ 98 ulData1 = read_U32(fLog); /* ID */ 99 100 hObject = __PERF_common_Create(pConfig, ulData1, ulData0); 101 if (!hObject) 102 { 103 fprintf(stderr, "error: could not create PERF replay object\n"); 104 exit(1); 105 } 106 107 me = get_Private(hObject); 108 109 /* set up initial state */ 110 me->ulPID = read_U32(fLog); /* PID */ 111 ulData1 = read_U32(fLog); /* startTime.sec */ 112 ulData2 = read_U32(fLog); /* startTime.usec */ 113 TIME_SET(me->time, ulData1, ulData2); 114 time_correction = 0; 115 116 /* continue setting up the PERF object */ 117 __PERF_CUSTOM_create(hObject, pConfig, ulData0); 118 if (me->uMode == PERF_Mode_Replay) 119 { 120 fprintf(stderr, "Only replay mode is selected. Aborting...\n"); 121 PERF_Done(hObject); 122 } 123 } 124 else 125 { 126 /* pre-read word is replay time difference, except for PERF_LOG_Location logs */ 127 /* get operation */ 128 ulData1 = read_U32(fLog); 129 operation = ulData1 & PERF_LOG_Mask; 130 131 if (operation != PERF_LOG_Location) 132 { 133 /* invariant: time_replayed = time_logged + time_correction */ 134 135 /* if a negative or too-small time-stamp is encountered */ 136 if (ulData0 > MAX_DELTA || ulData0 < MIN_DELTA || 137 /* or if we cannot completely correct a prior time correction */ 138 (time_correction && ulData0 < MIN_DELTA + (U32) (-time_correction))) 139 { /* store the time difference than cannot be replayed in the 140 time_correction variable, and replay a MIN_DELTA time 141 difference */ 142 time_correction += (long) ulData0 - (long) MIN_DELTA; 143 ulData0 = MIN_DELTA; 144 } 145 else if (time_correction) 146 { 147 ulData0 = ulData0 + (U32) time_correction; 148 time_correction = 0; 149 } 150 TIME_INCREASE(me->time, ulData0); 151 ulData0 = ulData1; 152 } 153 154 /* Check for buffer operations */ 155 if (operation & PERF_LOG_Buffer) 156 { 157 /* Buffer operation */ 158 if (operation & PERF_LOG_Xfering) { 159 sending = PERF_FlagXfering; 160 size = PERF_bits(ulData0, 2 * PERF_ModuleBits, 161 30 - 2 * PERF_ModuleBits) << 3; 162 } else { 163 sending = operation & PERF_LOG_Sending; 164 size = PERF_bits(ulData0, PERF_ModuleBits, 165 28 - PERF_ModuleBits); 166 ulData0 &= PERF_ModuleMask; 167 } 168 169 /* read address */ 170 ulData1 = read_U32(fLog); 171 multiple = (ulData1 & PERF_LOG_Multiple) ? PERF_FlagMultiple : PERF_FlagSingle; 172 frame = (ulData1 & PERF_LOG_Frame) ? PERF_FlagFrame : PERF_FlagBuffer; 173 174 /* read 2nd address if logged multiple buffers */ 175 ulData2 = PERF_IsMultiple(multiple) ? read_U32(fLog) : 0; 176 177 __PERF_CUSTOM_Buffer(hObject, 178 sending, 179 multiple, 180 frame, 181 ulData1 & ~3, 182 ulData2, 183 size, 184 PERF_bits(ulData0, 0, PERF_ModuleBits), 185 PERF_bits(ulData0, PERF_ModuleBits, PERF_ModuleBits) ); 186 } 187 /* Check for command operations */ 188 else if (operation & PERF_LOG_Command) 189 { 190 ulData1 = read_U32(fLog); 191 ulData2 = read_U32(fLog); 192 __PERF_CUSTOM_Command(hObject, 193 operation & PERF_LOG_Sending, 194 ulData1, 195 ulData2, 196 ulData0 & PERF_LOG_NotMask); 197 } 198 else switch (operation) 199 { 200 /* Log operation */ 201 case PERF_LOG_Log: 202 ulData1 = read_U32(fLog); 203 ulData2 = read_U32(fLog); 204 205 __PERF_CUSTOM_Log(hObject, 206 ulData0 & PERF_LOG_NotMask, 207 ulData1, 208 ulData2); 209 break; 210 211 /* SyncAV operation */ 212 case PERF_LOG_Sync: 213 uA.l = read_U32(fLog); 214 uV.l = read_U32(fLog); 215 216 __PERF_CUSTOM_SyncAV(hObject, uA.f, uV.f, 217 ulData0 & PERF_LOG_NotMask); 218 break; 219 220 case PERF_LOG_Done: 221 /* This can be also PERF_Thread, PERF_Boundary */ 222 operation = ulData0 & PERF_LOG_Mask2; 223 switch (operation) 224 { 225 /* Thread Creation operation */ 226 case PERF_LOG_Thread: 227 ulData1 = read_U32(fLog); 228 229 __PERF_CUSTOM_ThreadCreated(hObject, 230 ulData0 & PERF_LOG_NotMask2, 231 ulData1); 232 break; 233 234 /* Boundary operation */ 235 case PERF_LOG_Boundary: 236 __PERF_CUSTOM_Boundary(hObject, 237 ulData0 & PERF_LOG_NotMask2); 238 break; 239 240 case PERF_LOG_Done: 241 __PERF_Done(hObject); 242 243 break; 244 } 245 break; 246 247 /* location log */ 248 case PERF_LOG_Location: 249 ulData2 = read_U32(fLog); 250 ulData3 = read_U32(fLog); 251 ulData4 = read_U32(fLog); 252 ulData5 = read_U32(fLog); 253 ulData6 = read_U32(fLog); 254 ulData7 = read_U32(fLog); 255 256 /* decode szFile */ 257 szFile[19] = __DECODE(ulData2 & 0x3f); 258 szFile[18] = __DECODE((ulData2 >> 6) & 0x3f); 259 szFile[17] = __DECODE((ulData2 >> 12) & 0x3f); 260 szFile[16] = __DECODE((ulData2 >> 18) & 0x3f); 261 szFile[15] = __DECODE((ulData2 >> 24) & 0x3f); 262 szFile[14] = __DECODE(((ulData2 >> 26) & 0x30) | ((ulData0 >> 24) & 0x0f)); 263 szFile[13] = __DECODE(ulData3 & 0x3f); 264 szFile[12] = __DECODE((ulData3 >> 6) & 0x3f); 265 szFile[11] = __DECODE((ulData3 >> 12) & 0x3f); 266 szFile[10] = __DECODE((ulData3 >> 18) & 0x3f); 267 szFile[9] = __DECODE((ulData3 >> 24) & 0x3f); 268 szFile[8] = __DECODE(((ulData3 >> 26) & 0x30) | ((ulData0 >> 28) & 0x0f)); 269 szFile[7] = __DECODE(ulData4 & 0x3f); 270 szFile[6] = __DECODE((ulData4 >> 6) & 0x3f); 271 szFile[5] = __DECODE((ulData4 >> 12) & 0x3f); 272 szFile[4] = __DECODE((ulData4 >> 18) & 0x3f); 273 szFile[3] = __DECODE((ulData4 >> 24) & 0x3f); 274 szFile[2] = __DECODE(((ulData4 >> 26) & 0x30) | (ulData1 & 0x0f)); 275 szFile[1] = __DECODE(ulData0 & 0x3f); 276 szFile[0] = __DECODE((ulData0 >> 6) & 0x3f); 277 szFile[20] = '\0'; 278 279 szFunc[19] = __DECODE(ulData5 & 0x3f); 280 szFunc[18] = __DECODE((ulData5 >> 6) & 0x3f); 281 szFunc[17] = __DECODE((ulData5 >> 12) & 0x3f); 282 szFunc[16] = __DECODE((ulData5 >> 18) & 0x3f); 283 szFunc[15] = __DECODE((ulData5 >> 24) & 0x3f); 284 szFunc[14] = __DECODE(((ulData5 >> 26) & 0x30) | ((ulData1 >> 4) & 0x0f)); 285 szFunc[13] = __DECODE(ulData6 & 0x3f); 286 szFunc[12] = __DECODE((ulData6 >> 6) & 0x3f); 287 szFunc[11] = __DECODE((ulData6 >> 12) & 0x3f); 288 szFunc[10] = __DECODE((ulData6 >> 18) & 0x3f); 289 szFunc[9] = __DECODE((ulData6 >> 24) & 0x3f); 290 szFunc[8] = __DECODE(((ulData6 >> 26) & 0x30) | ((ulData1 >> 8) & 0x0f)); 291 szFunc[7] = __DECODE(ulData7 & 0x3f); 292 szFunc[6] = __DECODE((ulData7 >> 6) & 0x3f); 293 szFunc[5] = __DECODE((ulData7 >> 12) & 0x3f); 294 szFunc[4] = __DECODE((ulData7 >> 18) & 0x3f); 295 szFunc[3] = __DECODE((ulData7 >> 24) & 0x3f); 296 szFunc[2] = __DECODE(((ulData7 >> 26) & 0x30) | ((ulData1 >> 12) & 0x0f)); 297 szFunc[1] = __DECODE((ulData0 >> 12) & 0x3f); 298 szFunc[0] = __DECODE((ulData0 >> 18) & 0x3f); 299 szFunc[20] = '\0'; 300 301 /* skip leading /-s */ 302 for (ulData2 = 0; szFile[ulData2] == '/'; ulData2++); 303 for (ulData3 = 0; szFunc[ulData3] == '/'; ulData3++); 304 305 ulData1 = (ulData1 >> 16) & 0xfff; 306 __PERF_CUSTOM_Location(hObject,szFile + ulData2, ulData1, 307 szFunc + ulData3); 308 309 break; 310 311 default: 312 fprintf(stderr, "Unknown operation recorded: %lx\n", ulData0); 313 exit(1); 314 break; 315 } 316 } 317 } 318 319 if (hObject) 320 { 321 fprintf(stderr, "Incomplete log ended...\n"); 322 PERF_Done(hObject); 323 } 324 } 325 326 int main(int argc, char **argv) 327 { 328 int i; 329 FILE *log = NULL; 330 PERF_Config config; 331 332 333 for (i = 1; i < argc; i++) 334 { 335 /* replay file */ 336 337 /* open input, or stdin if '-' is specified */ 338 log = strcmp(argv [i], "-") ? fopen(argv [i], "rb") : stdin; 339 340 if (log) 341 { 342 /* read config file */ 343 PERF_Config_Init(&config); 344 PERF_Config_Read(&config, "replay"); 345 config.mask = 0xFFFFFFFF; 346 347 /* note config gets modified during Replay */ 348 PERF_Replay(log, &config); 349 350 PERF_Config_Release(&config); 351 352 /* don't close stdin! */ 353 if (log != stdin) fclose(log); 354 } 355 else 356 { 357 fprintf(stderr, "Could not open log file %s: %d\n", 358 argv [i], errno); 359 } 360 } 361 362 return (0); 363 } 364 365 #endif /* __PERF_CUSTOMIZABLE__ */ 366 367 #endif /* __PERF_READER__ */ 368 369