| OLD | NEW |
| (Empty) | |
| 1 #include <stdio.h> |
| 2 #include <algorithm> |
| 3 #include <unordered_set> |
| 4 #include <unordered_map> |
| 5 |
| 6 // Compiling printf with -finstrument-functions seems to break it? |
| 7 |
| 8 #ifdef _MSC_VER |
| 9 #include <windows.h> |
| 10 #include <process.h> |
| 11 #include <dbghelp.h> |
| 12 |
| 13 #if 0 |
| 14 extern "C" unsigned long __stdcall GetCurrentProcessId(void); |
| 15 |
| 16 extern "C" unsigned long _beginthread( void( __cdecl *start_address )( void * ),
unsigned stack_size, void *arglist ); |
| 17 #endif |
| 18 |
| 19 namespace { |
| 20 |
| 21 // We can easily run out of memory if this is too high. |
| 22 #define N (50*1024*1024) |
| 23 //#define N (1*1024*1024) |
| 24 void *tracebuf[N]; |
| 25 int n = 0; |
| 26 |
| 27 char symbuf[1024*1024]; |
| 28 |
| 29 void dump(void*) { |
| 30 HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); |
| 31 decltype(::SymFromAddr) *symfromaddr = |
| 32 reinterpret_cast<decltype(::SymFromAddr)*>(GetProcAddress(dbghelp, "SymFromA
ddr")); |
| 33 decltype(::SymInitialize) *syminitialize = |
| 34 reinterpret_cast<decltype(::SymInitialize)*>(GetProcAddress(dbghelp, "SymIni
tialize")); |
| 35 decltype(::SymSetOptions) *symsetoptions = |
| 36 reinterpret_cast<decltype(::SymSetOptions)*>(GetProcAddress(dbghelp, "SymSet
Options")); |
| 37 |
| 38 |
| 39 char fname[128]; |
| 40 sprintf(fname, "/src/tmp/cygprofile%lu.txt", GetCurrentProcessId()); |
| 41 FILE *f = fopen(fname, "a"); |
| 42 |
| 43 syminitialize(GetCurrentProcess(), NULL, TRUE); |
| 44 symsetoptions(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY); |
| 45 |
| 46 std::unordered_set<void*> seen; |
| 47 |
| 48 #if 0 |
| 49 std::unordered_map<void*, unsigned> freq; |
| 50 for (int i = 0; i < N; i++) |
| 51 ++freq[tracebuf[i]]; |
| 52 std::vector<void*> funcs; |
| 53 for (auto i : freq) |
| 54 funcs.push_back(i.first); |
| 55 std::sort(funcs.begin(), funcs.end(), [&](void* a, void* b) { |
| 56 return freq[b] < freq[a]; |
| 57 }); |
| 58 std::unordered_set<std::string> seen_names; |
| 59 for (void *func : funcs) { |
| 60 PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbuf; |
| 61 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
| 62 symbol->MaxNameLen = MAX_SYM_NAME; |
| 63 DWORD64 offset = 0; |
| 64 if (symfromaddr(GetCurrentProcess(), (DWORD64)func, &offset, symbol)) { |
| 65 char *name = symbol->Name; |
| 66 if (name[0] == '_') |
| 67 name++; |
| 68 if (seen_names.count(name)) |
| 69 continue; |
| 70 seen_names.insert(name); |
| 71 fprintf(f, "%s (%u)\n", name, freq[func]); |
| 72 } |
| 73 } |
| 74 #endif |
| 75 |
| 76 #if 1 |
| 77 // Due to inlining, multiple functions can end up with the same symbol. |
| 78 std::unordered_set<std::string> seen_names; |
| 79 |
| 80 for (int i = 0; i < N; i++) { |
| 81 if (seen.count(tracebuf[i])) |
| 82 continue; |
| 83 seen.insert(tracebuf[i]); |
| 84 |
| 85 //fprintf(f, "0x%p\n", tracebuf[i]); |
| 86 |
| 87 PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbuf; |
| 88 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
| 89 symbol->MaxNameLen = MAX_SYM_NAME; |
| 90 DWORD64 offset = 0; |
| 91 if (symfromaddr(GetCurrentProcess(), (DWORD64)tracebuf[i], &offset, symbol))
{ |
| 92 char *name = symbol->Name; |
| 93 if (name[0] == '_') |
| 94 name++; |
| 95 if (seen_names.count(name)) |
| 96 continue; |
| 97 seen_names.insert(name); |
| 98 fprintf(f, "%s\n", name); |
| 99 } |
| 100 } |
| 101 #endif |
| 102 |
| 103 fclose(f); |
| 104 } |
| 105 |
| 106 } |
| 107 #endif |
| 108 |
| 109 extern "C" { |
| 110 |
| 111 // Set attributes to be sure we don't instrument ourselves. |
| 112 void __cyg_profile_func_enter(void* this_fn, void* call_site) |
| 113 __attribute__((no_instrument_function)); |
| 114 void __cyg_profile_func_exit(void* this_fn, void* call_site) |
| 115 __attribute__((no_instrument_function)); |
| 116 |
| 117 void __cyg_profile_func_enter(void* this_fn, void* callee_unused) { |
| 118 // This gets pulled into NaCL binaries and all kinds of places. |
| 119 #ifdef _MSC_VER |
| 120 static int done = 0; |
| 121 |
| 122 if (done) |
| 123 return; |
| 124 |
| 125 tracebuf[n++] = this_fn; |
| 126 |
| 127 if (n == N) { |
| 128 done = 1; |
| 129 _beginthread(dump, 0, nullptr); |
| 130 return; |
| 131 } |
| 132 #endif |
| 133 } |
| 134 |
| 135 void __cyg_profile_func_exit(void* this_fn, void* call_site) {} |
| 136 |
| 137 } // extern "C" |
| 138 |
| OLD | NEW |