| Index: tools/cygprofile/cygprofile2.cc
|
| diff --git a/tools/cygprofile/cygprofile2.cc b/tools/cygprofile/cygprofile2.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5c883fecaf07176ffb723b2ac572257ad73c48dc
|
| --- /dev/null
|
| +++ b/tools/cygprofile/cygprofile2.cc
|
| @@ -0,0 +1,138 @@
|
| +#include <stdio.h>
|
| +#include <algorithm>
|
| +#include <unordered_set>
|
| +#include <unordered_map>
|
| +
|
| +// Compiling printf with -finstrument-functions seems to break it?
|
| +
|
| +#ifdef _MSC_VER
|
| +#include <windows.h>
|
| +#include <process.h>
|
| +#include <dbghelp.h>
|
| +
|
| +#if 0
|
| +extern "C" unsigned long __stdcall GetCurrentProcessId(void);
|
| +
|
| +extern "C" unsigned long _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void *arglist );
|
| +#endif
|
| +
|
| +namespace {
|
| +
|
| +// We can easily run out of memory if this is too high.
|
| +#define N (50*1024*1024)
|
| +//#define N (1*1024*1024)
|
| +void *tracebuf[N];
|
| +int n = 0;
|
| +
|
| +char symbuf[1024*1024];
|
| +
|
| +void dump(void*) {
|
| + HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
|
| + decltype(::SymFromAddr) *symfromaddr =
|
| + reinterpret_cast<decltype(::SymFromAddr)*>(GetProcAddress(dbghelp, "SymFromAddr"));
|
| + decltype(::SymInitialize) *syminitialize =
|
| + reinterpret_cast<decltype(::SymInitialize)*>(GetProcAddress(dbghelp, "SymInitialize"));
|
| + decltype(::SymSetOptions) *symsetoptions =
|
| + reinterpret_cast<decltype(::SymSetOptions)*>(GetProcAddress(dbghelp, "SymSetOptions"));
|
| +
|
| +
|
| + char fname[128];
|
| + sprintf(fname, "/src/tmp/cygprofile%lu.txt", GetCurrentProcessId());
|
| + FILE *f = fopen(fname, "a");
|
| +
|
| + syminitialize(GetCurrentProcess(), NULL, TRUE);
|
| + symsetoptions(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY);
|
| +
|
| + std::unordered_set<void*> seen;
|
| +
|
| +#if 0
|
| + std::unordered_map<void*, unsigned> freq;
|
| + for (int i = 0; i < N; i++)
|
| + ++freq[tracebuf[i]];
|
| + std::vector<void*> funcs;
|
| + for (auto i : freq)
|
| + funcs.push_back(i.first);
|
| + std::sort(funcs.begin(), funcs.end(), [&](void* a, void* b) {
|
| + return freq[b] < freq[a];
|
| + });
|
| + std::unordered_set<std::string> seen_names;
|
| + for (void *func : funcs) {
|
| + PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbuf;
|
| + symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
| + symbol->MaxNameLen = MAX_SYM_NAME;
|
| + DWORD64 offset = 0;
|
| + if (symfromaddr(GetCurrentProcess(), (DWORD64)func, &offset, symbol)) {
|
| + char *name = symbol->Name;
|
| + if (name[0] == '_')
|
| + name++;
|
| + if (seen_names.count(name))
|
| + continue;
|
| + seen_names.insert(name);
|
| + fprintf(f, "%s (%u)\n", name, freq[func]);
|
| + }
|
| + }
|
| +#endif
|
| +
|
| +#if 1
|
| + // Due to inlining, multiple functions can end up with the same symbol.
|
| + std::unordered_set<std::string> seen_names;
|
| +
|
| + for (int i = 0; i < N; i++) {
|
| + if (seen.count(tracebuf[i]))
|
| + continue;
|
| + seen.insert(tracebuf[i]);
|
| +
|
| + //fprintf(f, "0x%p\n", tracebuf[i]);
|
| +
|
| + PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbuf;
|
| + symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
| + symbol->MaxNameLen = MAX_SYM_NAME;
|
| + DWORD64 offset = 0;
|
| + if (symfromaddr(GetCurrentProcess(), (DWORD64)tracebuf[i], &offset, symbol)) {
|
| + char *name = symbol->Name;
|
| + if (name[0] == '_')
|
| + name++;
|
| + if (seen_names.count(name))
|
| + continue;
|
| + seen_names.insert(name);
|
| + fprintf(f, "%s\n", name);
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + fclose(f);
|
| +}
|
| +
|
| +}
|
| +#endif
|
| +
|
| +extern "C" {
|
| +
|
| +// Set attributes to be sure we don't instrument ourselves.
|
| +void __cyg_profile_func_enter(void* this_fn, void* call_site)
|
| + __attribute__((no_instrument_function));
|
| +void __cyg_profile_func_exit(void* this_fn, void* call_site)
|
| + __attribute__((no_instrument_function));
|
| +
|
| +void __cyg_profile_func_enter(void* this_fn, void* callee_unused) {
|
| + // This gets pulled into NaCL binaries and all kinds of places.
|
| +#ifdef _MSC_VER
|
| + static int done = 0;
|
| +
|
| + if (done)
|
| + return;
|
| +
|
| + tracebuf[n++] = this_fn;
|
| +
|
| + if (n == N) {
|
| + done = 1;
|
| + _beginthread(dump, 0, nullptr);
|
| + return;
|
| + }
|
| +#endif
|
| +}
|
| +
|
| +void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
|
| +
|
| +} // extern "C"
|
| +
|
|
|