Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-core/tools/r4300prof.c
2 views
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus - r4300prof.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Copyright (C) 2008 Richard Goedeken *
5
* *
6
* This program is free software; you can redistribute it and/or modify *
7
* it under the terms of the GNU General Public License as published by *
8
* the Free Software Foundation; either version 2 of the License, or *
9
* (at your option) any later version. *
10
* *
11
* This program 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 *
14
* GNU General Public License for more details. *
15
* *
16
* You should have received a copy of the GNU General Public License *
17
* along with this program; if not, write to the *
18
* Free Software Foundation, Inc., *
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
/* Global data */
27
unsigned int instr_samples[132];
28
char instr_name[][10] =
29
{
30
"reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ",
31
"ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI",
32
"BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR",
33
"LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR",
34
"SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1",
35
"LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ",
36
"BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL",
37
"SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL",
38
"MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT",
39
"MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD",
40
"ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT",
41
"SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA",
42
"TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL",
43
"TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1",
44
"DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD",
45
"f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND",
46
"f.TRUNC", "f.CEIL", "f.FLOOR"
47
};
48
unsigned int instr_type[131] = { 9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0,
49
7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7,
51
7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10,
52
2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3,
53
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
54
8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2,
55
2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5,
56
5, 5, 5 };
57
char instr_typename[][20] = { "Load", "Store", "Data move/convert", "32-bit math", "64-bit math", "Float Math",
58
"Jump", "Branch", "Exceptions", "Reserved", "Other" };
59
60
/* Global functions */
61
int GetInstrType(int opcode);
62
int AddrCompare(const void *, const void *);
63
int ParseProfLine(const char *pchIn, long *plAddress, int *piSamples, float *pfPercentage);
64
65
/* defined types */
66
typedef struct __attribute__ ((__packed__))
67
{
68
int mipsop;
69
long x86addr;
70
} r4300op;
71
72
typedef struct
73
{
74
long x86addr;
75
int samples;
76
} profilehit;
77
78
/* static functions */
79
static int isSpace(char ch)
80
{
81
return (ch == ' ' || ch == '\t' ? 1 : 0);
82
}
83
84
static int isNum(char ch)
85
{
86
return (ch >= '0' && ch <= '9' ? 1 : 0);
87
}
88
89
static int isFloat(char ch)
90
{
91
return ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' || ch == '-' || ch == 'e' ? 1 : 0);
92
}
93
94
static int isHex(char ch)
95
{
96
return ((ch >= '0' && ch <= '9') || ((ch & 0xdf) >= 'A' && (ch & 0xdf) <= 'F') ? 1 : 0);
97
}
98
99
/* main */
100
int main(int argc, void *argv[])
101
{
102
long lOpStart, lOpEnd;
103
int flength, oplistlength, totaltime, proflistlength;
104
int samp_unknown, samp_blockend, samp_notcompiled, samp_wrappers, samp_flush;
105
int i, j;
106
FILE *pfIn;
107
r4300op *pOpAddrTable;
108
profilehit *pProfTable;
109
char *pch, *pchSampleData;
110
111
/* check arguments */
112
if (argc < 3)
113
{
114
printf("Usage: r4300prof r4300addr.dat x86profile.txt\n\n");
115
printf("r4300addr.dat - binary table of r4300 opcodes and corresponding x86 starting addresses\n");
116
printf("x86profile.txt - text file containing a list of profile sample counts by x86 address on the heap\n\n");
117
return 1;
118
}
119
120
/* open r4300 opcode/x86 address table generated from emulator run */
121
printf("Loading %s...\n", argv[1]);
122
pfIn = fopen(argv[1], "rb");
123
if (pfIn == NULL)
124
{
125
printf("Couldn't open input file: %s\n", argv[1]);
126
return 2;
127
}
128
129
/* get file length and calculate number of r4300op table entries */
130
fseek(pfIn, 0L, SEEK_END);
131
flength = (int) ftell(pfIn);
132
fseek(pfIn, 0L, SEEK_SET);
133
oplistlength = flength / sizeof(r4300op);
134
135
/* read the file */
136
pOpAddrTable = (r4300op *) malloc(flength);
137
if (pOpAddrTable == NULL)
138
{
139
printf("Failed to allocate %i bytes for OpAddrTable!\n", flength);
140
fclose(pfIn);
141
return 3;
142
}
143
fread(pOpAddrTable, 1, flength, pfIn);
144
fclose(pfIn);
145
printf("%i r4300 instruction locations read.\n", oplistlength);
146
147
/* sort the opcode/address table according to x86addr */
148
qsort(pOpAddrTable, oplistlength, sizeof(r4300op), AddrCompare);
149
150
/* remove any 0-length r4300 instructions */
151
i = 0;
152
j = 0;
153
while (i < oplistlength)
154
{
155
pOpAddrTable[j].mipsop = pOpAddrTable[i].mipsop;
156
pOpAddrTable[j].x86addr = pOpAddrTable[i].x86addr;
157
i++;
158
if (pOpAddrTable[j].x86addr != pOpAddrTable[i].x86addr)
159
j++;
160
}
161
oplistlength = j;
162
printf("%i non-empty MIPS instructions.\n", oplistlength);
163
164
/* convert each r4300 opcode to an instruction type index */
165
for (i = 0; i < oplistlength; i++)
166
if (pOpAddrTable[i].mipsop > 0 || pOpAddrTable[i].mipsop < -16)
167
pOpAddrTable[i].mipsop = GetInstrType(pOpAddrTable[i].mipsop);
168
169
/* open the profiling sample data file */
170
printf("Loading %s...\n", argv[2]);
171
pfIn = fopen(argv[2], "rb");
172
if (pfIn == NULL)
173
{
174
printf("Couldn't open input file: %s\n", argv[2]);
175
free(pOpAddrTable);
176
return 4;
177
}
178
179
/* load it */
180
fseek(pfIn, 0L, SEEK_END);
181
flength = (int) ftell(pfIn);
182
fseek(pfIn, 0L, SEEK_SET);
183
pchSampleData = (char *) malloc(flength + 16);
184
if (pchSampleData == NULL)
185
{
186
printf("Failed to allocate %i bytes for pchSampleData!\n", flength + 16);
187
fclose(pfIn);
188
free(pOpAddrTable);
189
return 5;
190
}
191
fread(pchSampleData, 1, flength, pfIn);
192
pchSampleData[flength] = 0;
193
fclose(pfIn);
194
195
/* count the number of newlines in the ascii-formatted sample data file */
196
proflistlength = 1;
197
pch = pchSampleData;
198
while (pch = strchr(pch, '\n'))
199
{
200
proflistlength++;
201
pch++;
202
}
203
printf("%i lines in sample data file.\n", proflistlength);
204
205
/* extract text data into binary table */
206
pProfTable = (profilehit *) malloc(proflistlength * sizeof(profilehit));
207
if (pProfTable == NULL)
208
{
209
printf("Failed to allocate %i bytes for pProfTable!\n", proflistlength * sizeof(profilehit));
210
free(pOpAddrTable);
211
free(pchSampleData);
212
return 6;
213
}
214
pch = pchSampleData;
215
j = 0;
216
long long llOffset = 0;
217
while (j < proflistlength)
218
{
219
long lAddress;
220
int iSamples;
221
float fPercentage;
222
char *pchNext = strchr(pch, '\n');
223
if (pchNext != NULL) *pchNext++ = 0; // null-terminate this line
224
if (strstr(pch, "range:0x") != NULL) // search for offset change
225
{
226
pch = strstr(pch, "range:0x") + 8; // extract hex value and update our offset
227
char *pch2 = pch;
228
while (isHex(*pch2)) pch2++;
229
*pch2 = 0;
230
llOffset = strtoll(pch, NULL, 16);
231
}
232
else // parse line for sample point
233
{
234
int rval = ParseProfLine(pch, &lAddress, &iSamples, &fPercentage);
235
if (rval != 0)
236
{
237
pProfTable[j].x86addr = (unsigned long) (lAddress + llOffset);
238
pProfTable[j].samples = iSamples;
239
j++;
240
}
241
}
242
pch = pchNext;
243
if (pch == NULL) break;
244
}
245
free(pchSampleData);
246
proflistlength = j;
247
printf("Found %i profile hits.\n", proflistlength);
248
249
/* clear r4300 instruction sample data table */
250
for (i = 0; i < 132; i++)
251
instr_samples[i] = 0;
252
253
/* calculate r4300 instruction profiling data by merging the tables */
254
samp_unknown = 0;
255
samp_blockend = 0;
256
samp_notcompiled = 0;
257
samp_wrappers = 0;
258
samp_flush = 0;
259
i = 0; // i == OpAddrTable index
260
lOpStart = pOpAddrTable[0].x86addr;
261
lOpEnd = pOpAddrTable[1].x86addr;
262
for (j = 0; j < proflistlength; j++) // j == pProfTable index
263
{
264
long lOpx86addr = pProfTable[j].x86addr;
265
if (lOpx86addr >= lOpStart && lOpx86addr <= lOpEnd) /* these profile samples lie within current r4300 instruction */
266
{
267
int instr = pOpAddrTable[i].mipsop;
268
if (instr == -1) printf("%lx sample point lies between %i/%lx and %i/%lx\n", lOpx86addr, instr, lOpStart, pOpAddrTable[i+1].mipsop, lOpEnd);
269
270
if (instr == -1)
271
samp_unknown += pProfTable[j].samples;
272
else if (instr == -2)
273
samp_notcompiled += pProfTable[j].samples;
274
else if (instr == -3)
275
samp_blockend += pProfTable[j].samples;
276
else if (instr == -4)
277
samp_wrappers += pProfTable[j].samples;
278
else if (instr == -5)
279
samp_flush += pProfTable[j].samples;
280
else
281
instr_samples[instr] += pProfTable[j].samples;
282
continue;
283
}
284
if (lOpx86addr < pOpAddrTable[0].x86addr || lOpx86addr >= pOpAddrTable[oplistlength-1].x86addr)
285
{ /* outside the range of all recompiled instructions */
286
samp_unknown += pProfTable[j].samples;
287
continue;
288
}
289
if (lOpx86addr < lOpStart) /* discontinuity in profile list, go back to start */
290
{
291
i = 0;
292
lOpStart = pOpAddrTable[0].x86addr;
293
lOpEnd = pOpAddrTable[1].x86addr;
294
j--;
295
continue;
296
}
297
/* this profile point is ahead of current r4300 instruction */
298
do /* race ahead in r4300 opcode list until we hit this profile sample point */
299
{
300
i++;
301
} while (i+1 < oplistlength && lOpx86addr > pOpAddrTable[i+1].x86addr);
302
lOpStart = pOpAddrTable[i].x86addr;
303
lOpEnd = pOpAddrTable[i+1].x86addr;
304
if (lOpx86addr < lOpStart || lOpx86addr > lOpEnd)
305
{
306
printf("Error: lOpx86addr = %lx but lOpStart, lOpEnd = %lx, %lx\n", lOpx86addr, lOpStart, lOpEnd);
307
return 7;
308
}
309
/* we have found the correct r4300 instruction corresponding to this profile point */
310
j--;
311
}
312
313
/* print the results */
314
unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
315
printf("\nInstruction time (samples):\n");
316
totaltime = 0;
317
for (i = 0; i < 131; i++)
318
{
319
printf("%8s: %08i ", instr_name[i], instr_samples[i]);
320
if (i % 5 == 4) printf("\n");
321
iTypeCount[instr_type[i]] += instr_samples[i];
322
totaltime += instr_samples[i];
323
}
324
int special = samp_flush + samp_wrappers + samp_notcompiled + samp_blockend;
325
printf("\n\nSpecial code samples:\n");
326
printf(" Regcache flushing: %i\n", samp_flush);
327
printf(" Jump wrappers: %i\n", samp_wrappers);
328
printf(" NOTCOMPILED: %i\n", samp_notcompiled);
329
printf(" block postfix & link samples: %i\n", samp_blockend);
330
331
printf("\nUnaccounted samples: %i\n", samp_unknown);
332
printf("Total accounted instruction samples: %i\n", totaltime + special);
333
for (i = 0; i < 11; i++)
334
{
335
printf("%20s: %04.1f%% (%i)\n", instr_typename[i], (float) iTypeCount[i] * 100.0 / totaltime, iTypeCount[i]);
336
}
337
338
free(pOpAddrTable);
339
free(pProfTable);
340
return 0;
341
}
342
343
int AddrCompare(const void *p1, const void *p2)
344
{
345
const r4300op *pOp1 = (const r4300op *) p1;
346
const r4300op *pOp2 = (const r4300op *) p2;
347
348
if (pOp1->x86addr < pOp2->x86addr)
349
return -1;
350
else if (pOp1->x86addr == pOp2->x86addr)
351
return (int) (pOp1 - pOp2); /* this forces qsort to be stable */
352
else
353
return 1;
354
}
355
356
int ParseProfLine(const char *pchIn, long *plAddress, int *piSamples, float *pfPercentage)
357
{
358
char chVal[128], *pchOut;
359
360
/* skip any initial whitespace */
361
while (isSpace(*pchIn)) pchIn++;
362
if (!isHex(*pchIn)) return 0;
363
364
/* parse hexadecimal address value */
365
pchOut = chVal;
366
while (isHex(*pchIn)) *pchOut++ = *pchIn++;
367
*pchOut = 0;
368
if (!isSpace(*pchIn)) return 0;
369
*plAddress = strtol(chVal, NULL, 16);
370
371
/* skip more whitespace */
372
while (isSpace(*pchIn)) pchIn++;
373
if (!isNum(*pchIn)) return 0;
374
375
/* parse decimal sample count value */
376
pchOut = chVal;
377
while (isNum(*pchIn)) *pchOut++ = *pchIn++;
378
*pchOut = 0;
379
if (!isSpace(*pchIn)) return 0;
380
*piSamples = atoi(chVal);
381
382
/* skip more whitespace */
383
while (isSpace(*pchIn)) pchIn++;
384
if (!isFloat(*pchIn)) return 0;
385
386
/* parse floating-point percentage value */
387
pchOut = chVal;
388
while (isFloat(*pchIn)) *pchOut++ = *pchIn++;
389
*pchOut = 0;
390
if (!isSpace(*pchIn) && *pchIn != '\r' && *pchIn != '\n' && *pchIn != 0) return 0;
391
*pfPercentage = atof(chVal);
392
393
/* if this isn't the end of the line, it's not a valid sample point */
394
while (isSpace(*pchIn)) pchIn++;
395
if (*pchIn != '\r' && *pchIn != '\n' && *pchIn != 0) return 0;
396
397
return 1;
398
}
399
400
static int InstrTypeStd[64] =
401
{
402
-1, -1, 02, 03, 04, 05, 06, 07, 8, 9, 10, 11, 12, 13, 14, 15,
403
-1, -1, 00, 00, 16, 17, 18, 19, 20, 21, 22, 23, 00, 00, 00, 00,
404
24, 25, 27, 26, 28, 29, 31, 30, 32, 33, 35, 34, 37, 38, 36, 01,
405
42, 39, 00, 00, 01, 40, 00, 41, 46, 43, 00, 00, 01, 44, 00, 45
406
};
407
408
static int InstrTypeSpecial[64] =
409
{
410
55, 00, 56, 57, 58, 00, 59, 60,
411
61, 62, 00, 00, 63, 01, 00, 00,
412
64, 65, 66, 67, 68, 00, 69, 70,
413
71, 72, 73, 74, 75, 76, 77, 78,
414
79, 80, 81, 82, 83, 84, 85, 86,
415
00, 00, 87, 88, 89, 90, 91, 92,
416
01, 01, 01, 01, 96, 00, 01, 00,
417
93, 00, 94, 95, 97, 00, 98, 99
418
};
419
420
static int InstrTypeRegImm[32] =
421
{
422
47, 48, 49, 50, 00, 00, 00, 00, 01, 01, 01, 01, 01, 00, 01, 00,
423
51, 52, 53, 54, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00
424
};
425
426
static int InstrTypeCop1[32] =
427
{
428
111, 112, 113, 00, 114, 115, 116, 00,
429
-1, 00, 00, 00, 00, 00, 00, 00,
430
-1, -1, 00, 00, -1, -1, 00, 00,
431
00, 00, 00, 00, 00, 00, 00, 00
432
};
433
434
static int InstrTypeCop1Math[64] =
435
{
436
119, 120, 121, 122, 123, 124, 125, 126,
437
127, 128, 129, 130, 127, 128, 129, 130,
438
00, 00, 00, 00, 00, 00, 00, 00,
439
00, 00, 00, 00, 00, 00, 00, 00,
440
117, 117, 00, 00, 117, 117, 00, 00,
441
00, 00, 00, 00, 00, 00, 00, 00,
442
118, 118, 118, 118, 118, 118, 118, 118,
443
118, 118, 118, 118, 118, 118, 118, 118
444
};
445
446
447
int GetInstrType(int opcode)
448
{
449
int iType = (opcode >> 26) & 63;
450
451
if (iType == 0)
452
{
453
/* SPECIAL instruction */
454
iType = opcode & 63;
455
return InstrTypeSpecial[iType];
456
}
457
else if (iType == 1)
458
{
459
/* REGIMM instruction */
460
iType = (opcode >> 16) & 31;
461
return InstrTypeRegImm[iType];
462
}
463
else if (iType == 16)
464
{
465
/* COP0 instruction */
466
int iType1 = opcode & 0x01FFFFFF;
467
int iType2 = (opcode >> 21) & 31;
468
if (iType1 == 1)
469
return 106; // TLBR
470
else if (iType1 == 2)
471
return 104; // TLBWI
472
else if (iType1 == 6)
473
return 107; // TLBWR
474
else if (iType1 == 8)
475
return 105; // TLBP
476
else if (iType1 == 24)
477
return 108; // ERET
478
else if ((opcode & 0x7FF) == 0 && iType2 == 0)
479
return 109; // MFC0
480
else if ((opcode & 0x7FF) == 0 && iType2 == 4)
481
return 110; // MTC0
482
else
483
return 0; // reserved
484
}
485
else if (iType == 17)
486
{
487
/* COP1 instruction */
488
int iType1 = (opcode >> 21) & 31;
489
if (iType1 == 8)
490
{
491
/* conditional branch */
492
int iType2 = (opcode >> 16) & 31;
493
if (iType2 == 0)
494
return 100; // BC1F
495
else if (iType2 == 1)
496
return 101; // BC1T
497
else if (iType2 == 2)
498
return 102; // BC1FL
499
else if (iType2 == 3)
500
return 103; // BC1TL
501
else
502
return 0; // reserved
503
}
504
else if (iType1 == 16 || iType1 == 17 || iType1 == 20 || iType1 == 21)
505
{
506
/* Single, Double, Word, Long instructions */
507
int iType2 = opcode & 63;
508
return InstrTypeCop1Math[iType2];
509
}
510
else
511
{
512
/* other Cop1 (move) */
513
return InstrTypeCop1[iType1];
514
}
515
}
516
517
/* standard MIPS instruction */
518
return InstrTypeStd[iType];
519
}
520
521
522