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 
read_U32(FILE * fLog)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 
PERF_Replay(FILE * fLog,PERF_Config * pConfig)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 
main(int argc,char ** argv)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