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
46typedef unsigned long U32;
47
48/*=============================================================================
49    GLOBALS
50=============================================================================*/
51
52static U32 read_U32(FILE *fLog)
53{
54    U32 data;
55    fread(&data, sizeof(U32), 1, fLog);
56    return(data);
57}
58
59PERF_OBJHANDLE __PERF_common_Create(struct PERF_Config *config,
60                                    unsigned long ulID,
61                                    PERF_MODULETYPE eModule);
62void __PERF_CUSTOM_create(PERF_OBJHANDLE hObject,
63                          struct PERF_Config *config,
64                          PERF_MODULETYPE eModule);
65
66void 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
326int 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