2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/tools/tc-print/tc-print.h"
27 #include <folly/Singleton.h>
29 #include "hphp/runtime/vm/repo.h"
30 #include "hphp/runtime/base/preg.h"
31 #include "hphp/runtime/base/program-functions.h"
33 #include "hphp/tools/tc-print/perf-events.h"
34 #include "hphp/tools/tc-print/offline-trans-data.h"
35 #include "hphp/tools/tc-print/offline-code.h"
36 #include "hphp/tools/tc-print/mappers.h"
37 #include "hphp/tools/tc-print/repo-wrapper.h"
38 #include "hphp/tools/tc-print/std-logger.h"
39 #include "hphp/tools/tc-print/tc-print-logger.h"
42 using namespace HPHP::jit
;
44 #define MAX_SYM_LEN 10240
46 std::string
dumpDir("/tmp");
47 std::string configFile
;
48 std::string profFileName
;
49 uint32_t nTopTrans
= 0;
50 uint32_t nTopFuncs
= 0;
51 bool creationOrder
= false;
52 bool transCFG
= false;
53 bool collectBCStats
= false;
54 bool inclusiveStats
= false;
55 bool verboseStats
= false;
56 bool hostOpcodes
= false;
57 folly::Optional
<MD5
> md5Filter
;
58 PerfEventType sortBy
= EVENT_CYCLES
;
59 bool sortByDensity
= false;
60 bool sortBySize
= false;
61 double helpersMinPercentage
= 0;
62 ExtOpcode filterByOpcode
= 0;
63 std::string kindFilter
= "all";
64 uint32_t selectedFuncId
= INVALID_ID
;
66 TCA maxAddr
= (TCA
)-1;
67 uint32_t annotationsVerbosity
= 2;
69 std::vector
<uint32_t> transPrintOrder
;
72 OfflineTransData
* g_transData
;
73 OfflineCode
* transCode
;
75 char errMsgBuff
[MAX_SYM_LEN
];
76 const char* kListKeyword
= "list";
77 TCPrintLogger
* g_logger
;
79 PerfEventsMap
<TCA
> tcaPerfEvents
;
80 PerfEventsMap
<TransID
> transPerfEvents
;
82 #define NTRANS (g_transData->getNumTrans())
83 #define NFUNCS (g_transData->getNumFuncs())
84 #define TREC(TID) (g_transData->getTransRec(TID))
86 void warnTooFew(const std::string
& name
,
90 "Requested top %u %s, but there are only %u available.\n",
97 std::string
toString(T value
) {
104 printf("Usage: tc-print [OPTIONS]\n"
106 " -c <FILE> : uses the given config file\n"
107 " -D : used along with -t, this option sorts the top "
108 "translations by density (count / size) of the selected perf event\n"
109 " -d <DIRECTORY> : looks for dump file in <DIRECTORY> "
111 " -f <FUNC_ID> : prints the translations for the given "
112 "<FUNC_ID>, sorted by start offset\n"
113 " -g <FUNC_ID> : prints the CFG among the translations for the "
115 " -p <FILE> : uses raw profile data from <FILE>\n"
116 " -s : prints all translations sorted by creation "
118 " -u <MD5> : prints all translations from the specified "
120 " -t <NUMBER> : prints top <NUMBER> translations according to "
122 " -k <TRANS_KIND> : used with -t, filters only translations of the "
123 "given kind, e.g. TransLive (default: all)\n"
124 " -a <ADDR> : used with -t, filters only events at addresses "
126 " -A <ADDR> : used with -t, filters only events at addresses "
128 " -T <NUMBER> : prints top <NUMBER> functions according to "
130 " -e <EVENT_TYPE> : sorts by the specified perf event. Pass '%s' "
131 "to get a list of valid event types.\n"
132 " -b : prints bytecode stats\n"
133 " -B <OPCODE> : used in conjunction with -e, prints the top "
134 "bytecode translationc event type. Pass '%s' to get a "
135 "list of valid opcodes.\n"
136 " -i : reports inclusive stats by including helpers "
137 "(perf data must include call graph information)\n"
138 " -n <level> : level of verbosity for annotations. Use 0 for "
139 "no annotations, 1 - for inline, 2 - to print all annotations "
140 "including from a file (default: 2).\n"
141 " -o : print host opcodes\n"
142 " -v <PERCENTAGE> : sets the minimum percentage to <PERCENTAGE> "
143 "when printing the top helpers (implies -i). The lower the percentage,"
144 " the more helpers that will show up.\n"
145 " -h : prints help message\n",
150 void printValidBytecodes() {
151 g_logger
->printGeneric("<OPCODE>:\n");
152 auto validOpcodes
= getValidOpcodeNames();
153 for (size_t i
= 0; i
< validOpcodes
.size(); i
++) {
154 g_logger
->printGeneric(" * %s\n", validOpcodes
[i
].first
.c_str());
158 void printValidEventTypes() {
159 g_logger
->printGeneric("<EVENT_TYPE>:\n");
160 for (size_t i
= 0; i
< NUM_EVENT_TYPES
; i
++) {
161 g_logger
->printGeneric(" * %s\n",
162 eventTypeToCommandLineArgument((PerfEventType
)i
));
166 void parseOptions(int argc
, char *argv
[]) {
169 while ((c
= getopt (argc
, argv
, "hc:Dd:f:g:ip:st:u:S:T:o:e:bB:v:k:a:A:n:"))
173 if (sscanf(optarg
, "%p", &maxAddr
) != 1) {
179 if (sscanf(optarg
, "%p", &minAddr
) != 1) {
194 creationOrder
= true;
195 if (sscanf(optarg
, "%u", &selectedFuncId
) != 1) {
202 if (sscanf(optarg
, "%u", &selectedFuncId
) != 1) {
208 profFileName
= optarg
;
211 creationOrder
= true;
214 if (sscanf(optarg
, "%u", &nTopTrans
) != 1) {
220 if (strlen(optarg
) == 32) {
221 md5Filter
= MD5(optarg
);
230 if (sscanf(optarg
, "%u", &nTopFuncs
) != 1) {
239 sortByDensity
= true;
242 if (!strcmp(optarg
, kListKeyword
)) {
243 printValidEventTypes();
246 sortBy
= commandLineArgumentToEventType(optarg
);
247 if (sortBy
== NUM_EVENT_TYPES
) {
253 collectBCStats
= true;
256 if (!strcmp(optarg
, kListKeyword
)) {
257 printValidBytecodes();
260 filterByOpcode
= stringToExtOpcode(optarg
);
261 if (!filterByOpcode
) {
267 inclusiveStats
= true;
270 if (sscanf(optarg
, "%u", &annotationsVerbosity
) != 1) {
278 inclusiveStats
= true;
279 if (sscanf(optarg
, "%lf", &helpersMinPercentage
) != 1) {
285 if (optopt
== 'd' || optopt
== 'c' || optopt
== 'p' || optopt
== 't') {
286 fprintf (stderr
, "Error: -%c expects an argument\n\n", optopt
);
299 for (uint32_t tid
= 0; tid
< NTRANS
; tid
++) {
300 const auto trec
= TREC(tid
);
301 if (trec
->isValid() &&
302 (selectedFuncId
== INVALID_ID
||
303 selectedFuncId
== trec
->src
.funcID()) &&
304 (kindFilter
== "all" || kindFilter
== show(trec
->kind
).c_str())) {
305 transPrintOrder
.push_back(tid
);
310 void loadPerfEvents() {
313 profFile
= fopen(profFileName
.c_str(), "rt");
316 error("Error opening file " + profFileName
);
319 char program
[MAX_SYM_LEN
];
320 char eventCaption
[MAX_SYM_LEN
];
321 char line
[2*MAX_SYM_LEN
];
323 uint32_t tcSamples
[NUM_EVENT_TYPES
];
324 uint32_t hhvmSamples
[NUM_EVENT_TYPES
];
325 size_t numEntries
= 0;
326 PerfEventType eventType
= NUM_EVENT_TYPES
;
327 // samplesPerKind[event][kind]
328 uint32_t samplesPerKind
[NUM_EVENT_TYPES
][NumTransKinds
];
329 uint32_t samplesPerTCRegion
[NUM_EVENT_TYPES
][TCRCount
];
331 memset(tcSamples
, 0, sizeof(tcSamples
));
332 memset(hhvmSamples
, 0, sizeof(hhvmSamples
));
333 memset(samplesPerKind
, 0, sizeof(samplesPerKind
));
334 memset(samplesPerTCRegion
, 0, sizeof(samplesPerTCRegion
));
336 while (fgets(line
, 2*MAX_SYM_LEN
, profFile
) != nullptr) {
337 always_assert(sscanf(line
, "%s %s %lu", program
, eventCaption
, &numEntries
)
339 always_assert(numEntries
);
341 std::vector
<std::pair
<TCA
,std::string
>> entries
;
343 for (size_t i
= 0; i
< numEntries
; i
++) {
344 fscanf(profFile
, "%p %s\n", &addr
, line
);
345 entries
.push_back(std::pair
<TCA
,std::string
>(addr
, line
));
348 // Strip :p+ PEBS suffix.
349 if (auto pos
= strchr(eventCaption
, ':')) {
353 if (strncmp(program
, "hhvm", 4) == 0) {
354 eventType
= perfScriptOutputToEventType(eventCaption
);
355 if (eventType
== NUM_EVENT_TYPES
) {
358 "loadProfData: invalid event caption '%s'",
363 hhvmSamples
[eventType
]++;
366 addr
= entries
[0].first
;
368 if (inclusiveStats
) {
369 for (size_t i
= 0; i
< entries
.size(); i
++) {
370 if (g_transData
->isAddrInSomeTrans(entries
[i
].first
)) {
371 addr
= entries
[i
].first
;
378 if (!(minAddr
<= addr
&& addr
<= maxAddr
)) continue;
379 if (!g_transData
->isAddrInSomeTrans(addr
)) continue;
380 TransID transId
= g_transData
->getTransContaining(addr
);
381 always_assert(transId
!= INVALID_ID
);
382 tcSamples
[eventType
]++;
384 const TransRec
* trec
= g_transData
->getTransRec(transId
);
385 TransKind kind
= trec
->kind
;
386 samplesPerKind
[eventType
][static_cast<uint32_t>(kind
)]++;
387 TCRegion region
= transCode
->findTCRegionContaining(addr
);
388 always_assert(region
!= TCRCount
);
389 samplesPerTCRegion
[eventType
][region
]++;
391 std::vector
<std::string
> stackTrace
;
393 for (size_t i
= 0; i
< selIdx
; i
++) {
395 if (!strcmp(entries
[i
].second
.c_str(), "[unknown]")) {
397 // Append the address to disambiguate.
398 entries
[i
].second
+= std::string("@")
399 + toString((void*)entries
[i
].first
);
402 stackTrace
.push_back(entries
[i
].second
);
404 reverse(stackTrace
.begin(), stackTrace
.end());
408 tcaPerfEvents
.addEvent(addr
, (PerfEvent
){eventType
, 1}, stackTrace
);
412 AddrToTransMapper
transMapper(g_transData
);
413 transPerfEvents
= tcaPerfEvents
.mapTo(transMapper
);
415 g_logger
->printGeneric("# Number of hhvm samples read "
416 "(%% in TC) from file %s\n",
417 profFileName
.c_str());
419 for (size_t i
= 0; i
< NUM_EVENT_TYPES
; i
++) {
420 if (!hhvmSamples
[i
]) continue;
422 g_logger
->printGeneric("# %-19s TOTAL: %10u (%u in TC = %5.2lf%%)\n",
423 eventTypeToCommandLineArgument((PerfEventType
)i
),
426 100.0 * tcSamples
[i
] / hhvmSamples
[i
]);
428 for (size_t j
= 0; j
< NumTransKinds
; ++j
) {
429 auto ct
= samplesPerKind
[i
][j
];
431 std::string kind
= show(static_cast<TransKind
>(j
));
432 g_logger
->printGeneric("# %26s: %-8u (%5.2lf%%)\n",
433 kind
.c_str(), ct
, 100.0 * ct
/ tcSamples
[i
]);
435 g_logger
->printGeneric("#\n");
437 g_logger
->printGeneric("\n");
439 // print per-TCRegion information
442 g_logger
->printGeneric("# TCRegion ");
443 for (size_t i
= 0; i
< NUM_EVENT_TYPES
; i
++) {
444 g_logger
->printGeneric("%17s ",
445 eventTypeToCommandLineArgument((PerfEventType
)i
));
447 g_logger
->printGeneric("\n");
449 // HW events for each region
450 for (size_t i
= 0; i
< TCRCount
; i
++) {
451 g_logger
->printGeneric("# %8s ",
452 tcRegionToString(static_cast<TCRegion
>(i
)).c_str());
453 for (size_t j
= 0; j
< NUM_EVENT_TYPES
; j
++) {
454 auto ct
= samplesPerTCRegion
[j
][i
];
455 g_logger
->printGeneric("%8u (%5.2lf%%) ", ct
,
456 ct
? (100.0 * ct
/ tcSamples
[j
]) : 0);
458 g_logger
->printGeneric("\n");
460 g_logger
->printGeneric("#\n\n");
465 void loadProfData() {
466 if (!profFileName
.empty()) {
471 // Prints the metadata, bytecode, and disassembly for the given translation
472 void printTrans(TransID transId
) {
473 always_assert(transId
< NTRANS
);
475 g_logger
->printGeneric("\n====================\n");
476 g_transData
->printTransRec(transId
, transPerfEvents
);
478 const TransRec
* tRec
= TREC(transId
);
479 if (!tRec
->isValid()) return;
481 if (!tRec
->blocks
.empty()) {
482 g_logger
->printGeneric("----------\nbytecode:\n----------\n");
483 const Func
* curFunc
= nullptr;
484 for (auto& block
: tRec
->blocks
) {
485 std::stringstream byteInfo
;
486 auto unit
= g_repo
->getUnit(block
.md5
);
488 byteInfo
<< folly::format(
489 "<<< couldn't find unit {} to print bytecode range [{},{}) >>>\n",
490 block
.md5
, block
.bcStart
, block
.bcPast
);
494 auto newFunc
= unit
->getFunc(block
.bcStart
);
495 always_assert(newFunc
);
496 if (newFunc
!= curFunc
) {
498 newFunc
->prettyPrint(byteInfo
, Func::PrintOpts().noFpi().noMetadata());
504 Unit::PrintOpts().range(block
.bcStart
, block
.bcPast
).noFuncs());
505 g_logger
->printBytecode(byteInfo
.str());
509 g_logger
->printGeneric("----------\n%s: main\n----------\n",
510 transCode
->getArchName());
511 transCode
->printDisasm(tRec
->aStart
, tRec
->aLen
, tRec
->bcMapping
,
512 tcaPerfEvents
, hostOpcodes
);
514 g_logger
->printGeneric("----------\n%s: cold\n----------\n",
515 transCode
->getArchName());
516 // Sometimes acoldStart is the same as afrozenStart. Avoid printing the code
517 // twice in such cases.
518 if (tRec
->acoldStart
!= tRec
->afrozenStart
) {
519 transCode
->printDisasm(tRec
->acoldStart
, tRec
->acoldLen
, tRec
->bcMapping
,
520 tcaPerfEvents
, hostOpcodes
);
523 g_logger
->printGeneric("----------\n%s: frozen\n----------\n",
524 transCode
->getArchName());
525 transCode
->printDisasm(tRec
->afrozenStart
, tRec
->afrozenLen
, tRec
->bcMapping
,
526 tcaPerfEvents
, hostOpcodes
);
528 g_logger
->printGeneric("----------\n");
532 void printCFGOutArcs(TransID transId
) {
533 std::vector
<TCA
> jmpTargets
;
535 TCA fallThru
= transCode
->getTransJmpTargets(
536 g_transData
->getTransRec(transId
), &jmpTargets
);
538 auto const srcFuncId
= TREC(transId
)->src
.funcID();
540 for (size_t i
= 0; i
< jmpTargets
.size(); i
++) {
541 TransID targetId
= g_transData
->getTransStartingAt(jmpTargets
[i
]);
542 if (targetId
!= INVALID_ID
&&
543 // filter jumps to prologues of other funcs
544 TREC(targetId
)->src
.funcID() == srcFuncId
&&
545 TREC(targetId
)->kind
!= TransKind::Anchor
) {
547 bool retrans
= (TREC(transId
)->src
.offset() ==
548 TREC(targetId
)->src
.offset());
551 color
= "darkorange";
552 } else if (jmpTargets
[i
] == fallThru
) {
557 g_logger
->printGeneric("t%u -> t%u [color=%s] ;\n", transId
, targetId
,
565 std::vector
<TransID
> inodes
;
567 g_logger
->printGeneric("digraph CFG {\n");
569 g_transData
->findFuncTrans(selectedFuncId
, &inodes
);
572 for (uint32_t i
= 0; i
< inodes
.size(); i
++) {
573 auto tid
= inodes
[i
];
574 uint32_t bcStart
= TREC(tid
)->src
.offset();
575 uint32_t bcStop
= TREC(tid
)->bcPast();
576 const auto kind
= TREC(tid
)->kind
;
577 bool isPrologue
= kind
== TransKind::LivePrologue
||
578 kind
== TransKind::OptPrologue
;
579 const char* shape
= "box";
580 switch (TREC(tid
)->kind
) {
581 case TransKind::Optimize
: shape
= "oval"; break;
582 case TransKind::Profile
: shape
= "hexagon"; break;
583 case TransKind::LivePrologue
:
584 case TransKind::ProfPrologue
:
585 case TransKind::OptPrologue
: shape
= "invtrapezium"; break;
586 default: shape
= "box";
588 g_logger
->printGeneric("t%u [shape=%s,label=\"T: %u\\nbc: [0x%x-0x%x)\","
589 "style=filled%s];\n", tid
, shape
, tid
, bcStart
,
590 bcStop
, (isPrologue
? ",color=blue" : ""));
594 for (uint32_t i
= 0; i
< inodes
.size(); i
++) {
595 uint32_t tid
= inodes
[i
];
596 printCFGOutArcs(tid
);
599 g_logger
->printGeneric("}\n");
602 void printTopFuncs() {
603 if (!nTopFuncs
) return;
604 TransToFuncMapper
funcMapper(g_transData
);
605 PerfEventsMap
<FuncId
> funcPerfEvents
= transPerfEvents
.mapTo(funcMapper
);
606 funcPerfEvents
.printEventsSummary(sortBy
,
610 helpersMinPercentage
);
613 void printTopFuncsBySize() {
614 std::unordered_map
<FuncId
,size_t> funcSize
;
615 FuncId maxFuncId
= 0;
616 for (TransID t
= 0; t
< NTRANS
; t
++) {
617 const auto trec
= TREC(t
);
618 if (trec
->isValid()) {
619 const auto funcId
= trec
->src
.funcID();
620 funcSize
[funcId
] += trec
->aLen
;
621 if (funcId
> maxFuncId
) {
626 std::vector
<FuncId
> funcIds(maxFuncId
+1);
627 for (FuncId fid
= 0; fid
<= maxFuncId
; fid
++) {
630 std::sort(funcIds
.begin(), funcIds
.end(),
631 [&](FuncId fid1
, FuncId fid2
) {
632 return funcSize
[fid1
] > funcSize
[fid2
];
634 g_logger
->printGeneric("FuncID: \tSize (total aLen in bytes):\n");
635 for (size_t i
= 0; i
< nTopFuncs
; i
++) {
636 const auto fid
= funcIds
[i
];
637 g_logger
->printGeneric("%10u\t%10lu\n", fid
, funcSize
[funcIds
[i
]]);
643 const PerfEventsMap
<TransID
>& transPerfEvents
;
644 const PerfEventType etype
;
647 CompTrans(const PerfEventsMap
<TransID
>& _transPerfEvents
,
648 PerfEventType _etype
) :
649 transPerfEvents(_transPerfEvents
), etype(_etype
) {}
651 bool operator()(TransID t1
, TransID t2
) const {
652 const auto count1
= transPerfEvents
.getEventCount(t1
, etype
);
653 const auto count2
= transPerfEvents
.getEventCount(t2
, etype
);
655 const auto size1
= TREC(t1
)->aLen
;
656 const auto size2
= TREC(t2
)->aLen
;
657 return count1
* size2
> count2
* size1
;
659 return count1
> count2
;
663 void printTopTrans() {
664 if (!nTopTrans
) return;
666 // The summary currently includes all translations, so it's misleading
667 // if we're filtering a specific kind of translations or address range.
668 // It also doesn't sort by density, so do print it if sortByDensity is set.
669 if (kindFilter
== "all" && minAddr
== 0 && maxAddr
== (TCA
)-1 &&
671 transPerfEvents
.printEventsSummary(sortBy
,
675 helpersMinPercentage
);
678 // Sort and print the top translations.
679 std::vector
<TransID
> transIds
;
681 for (TransID t
= 0; t
< NTRANS
; t
++) {
682 if (TREC(t
)->isValid() &&
683 (kindFilter
== "all" || kindFilter
== show(TREC(t
)->kind
).c_str()) &&
684 ((minAddr
<= TREC(t
)->aStart
&& TREC(t
)->aStart
<= maxAddr
) ||
685 (minAddr
<= TREC(t
)->acoldStart
&& TREC(t
)->acoldStart
<= maxAddr
))) {
686 transIds
.push_back(t
);
690 CompTrans
compTrans(transPerfEvents
, sortBy
);
691 sort(transIds
.begin(), transIds
.end(), compTrans
);
693 size_t nPrint
= nTopTrans
;
694 if (transIds
.size() < nTopTrans
) {
695 fprintf(stderr
, "Warning: too few translations selected (%lu)\n",
697 nPrint
= transIds
.size();
699 for (size_t i
= 0; i
< nPrint
; i
++) printTrans(transIds
[i
]);
702 void printBytecodeStats(const OfflineTransData
* tdata
,
703 const PerfEventsMap
<TCA
>& events
,
704 PerfEventType etype
) {
706 if (!g_repo
) error("printBytecodeStats: null repo");
707 if (!tdata
) error("printBytecodeStats: null g_transData");
709 AddrToBcMapper
bcMapper(tdata
);
710 PerfEventsMap
<ExtOpcode
> bcPerfEvents
= events
.mapTo(bcMapper
);
712 std::map
<ExtOpcode
,std::string
> opcodeToName
;
713 PerfEventsMap
<ExtOpcode
>::const_iterator it
;
715 for (it
= bcPerfEvents
.begin(); it
!= bcPerfEvents
.end(); it
++) {
716 opcodeToName
[it
->first
] = extOpcodeToString(it
->first
);
719 bcPerfEvents
.printEventsSummary(etype
,
721 PerfEventsMap
<ExtOpcode
>::kAllEntries
,
723 helpersMinPercentage
,
727 void printTopBytecodes(const OfflineTransData
* tdata
,
729 const PerfEventsMap
<TCA
>& samples
,
731 ExtOpcode filterBy
) {
733 always_assert(etype
< NUM_EVENT_TYPES
);
735 AddrToTransFragmentMapper
mapper(tdata
, filterBy
);
736 PerfEventsMap
<TransFragment
> tfragPerfEvents
= samples
.mapTo(mapper
);
738 std::vector
<std::pair
<uint64_t, TransFragment
> > ranking
;
739 PerfEventsMap
<TransFragment
>::const_iterator it
;
741 for (it
= tfragPerfEvents
.begin(); it
!= tfragPerfEvents
.end(); it
++) {
742 ranking
.push_back(std::make_pair(it
->second
[etype
], it
->first
));
745 sort(ranking
.rbegin(), ranking
.rend());
747 for (size_t i
= 0; i
< ranking
.size(); i
++) {
748 const TransFragment
& tfrag
= ranking
[i
].second
;
749 const TransRec
* trec
= tdata
->getTransRec(tfrag
.tid
);
751 Unit
* unit
= g_repo
->getUnit(trec
->md5
);
754 g_logger
->printGeneric("\n====================\n");
755 g_logger
->printGeneric("{\n");
756 g_logger
->printGeneric(" FuncID = %u\n", trec
->src
.funcID());
757 g_logger
->printGeneric(" TransID = %u\n", tfrag
.tid
);
758 tfragPerfEvents
.printEventsHeader(tfrag
);
759 g_logger
->printGeneric("}\n\n");
761 g_logger
->printGeneric("----------\n%s: main\n----------\n",
762 olCode
->getArchName());
763 olCode
->printDisasm(tfrag
.aStart
,
769 g_logger
->printGeneric("----------\n%s: cold\n----------\n",
770 olCode
->getArchName());
771 olCode
->printDisasm(tfrag
.acoldStart
,
777 g_logger
->printGeneric("----------\n%s: frozen\n----------\n",
778 olCode
->getArchName());
779 olCode
->printDisasm(tfrag
.afrozenStart
,
787 int main(int argc
, char *argv
[]) {
788 folly::SingletonVault::singleton()->registrationComplete();
792 parseOptions(argc
, argv
);
794 StdLogger stdoutlogger
{};
795 g_logger
= &stdoutlogger
;
796 g_transData
= new OfflineTransData(dumpDir
);
797 transCode
= new OfflineCode(dumpDir
,
798 g_transData
->getHotBase(),
799 g_transData
->getMainBase(),
800 g_transData
->getProfBase(),
801 g_transData
->getColdBase(),
802 g_transData
->getFrozenBase());
803 g_repo
= new RepoWrapper(g_transData
->getRepoSchema(), configFile
);
807 g_transData
->setAnnotationsVerbosity(annotationsVerbosity
);
810 if (nTopFuncs
> NFUNCS
) {
811 warnTooFew("functions", nTopFuncs
, NFUNCS
);
815 printTopFuncsBySize();
819 } else if (nTopTrans
) {
820 if (nTopTrans
> NTRANS
) {
821 warnTooFew("translations", nTopTrans
, NTRANS
);
825 } else if (transCFG
) {
827 } else if (creationOrder
) {
828 // Print translations (all or for a given funcId) in the order
829 // they were created.
831 for (uint32_t i
=0; i
< transPrintOrder
.size(); i
++) {
832 printTrans(transPrintOrder
[i
]);
834 } else if (collectBCStats
) {
835 printBytecodeStats(g_transData
, tcaPerfEvents
, sortBy
);
836 } else if (filterByOpcode
) {
837 printTopBytecodes(g_transData
,
843 // Print all translations in original order, filtered by unit if desired.
844 for (uint32_t t
= 0; t
< NTRANS
; t
++) {
846 if (!tRec
->isValid()) continue;
847 if (tRec
->kind
== TransKind::Anchor
) continue;
848 if (md5Filter
&& tRec
->md5
!= *md5Filter
) continue;
851 g_logger
->flushTranslation(tRec
->funcName
);