Bug 1523562 [wpt PR 14417] - Update RTCPeerConnection-helper.js, a=testonly
[gecko.git] / mozglue / build / cygprofile.cpp
blobe4030fdf344cf8dcde2bd832b1b6df778a3ecd9b
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Copied from Chromium's /src/tools/cygprofile_win/cygprofile.cc.
7 #include <stdio.h>
8 #include <atomic>
9 #include <string>
10 #include <unordered_set>
12 #include <windows.h> // Needs to be included before the others.
14 #include <dbghelp.h>
15 #include <process.h>
17 #include "mozilla/Sprintf.h"
18 #include "mozilla/Types.h"
20 namespace {
22 // The main purpose of the order file is to optimize startup time,
23 // so capturing the first N function calls is enough.
24 static constexpr int kSamplesCapacity = 25 * 1024 * 1024;
26 void* samples[kSamplesCapacity];
27 std::atomic_int num_samples;
28 std::atomic_int done;
30 // Symbolize the samples and write them to disk.
31 void dump(void*) {
32 HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
33 auto sym_from_addr = reinterpret_cast<decltype(::SymFromAddr)*>(
34 ::GetProcAddress(dbghelp, "SymFromAddr"));
35 auto sym_initialize = reinterpret_cast<decltype(::SymInitialize)*>(
36 ::GetProcAddress(dbghelp, "SymInitialize"));
37 auto sym_set_options = reinterpret_cast<decltype(::SymSetOptions)*>(
38 ::GetProcAddress(dbghelp, "SymSetOptions"));
40 // Path to the dump file. %s will be substituted by objdir path.
41 static const char kDumpFile[] = "%s/cygprofile.txt";
43 char filename[MAX_PATH];
44 const char* objdir = ::getenv("MOZ_OBJDIR");
46 if (!objdir) {
47 fprintf(stderr, "ERROR: cannot determine objdir\n");
48 return;
51 SprintfLiteral(filename, kDumpFile, objdir);
53 FILE* f = fopen(filename, "w");
54 if (!f) {
55 fprintf(stderr, "ERROR: Cannot open %s\n", filename);
56 return;
59 sym_initialize(::GetCurrentProcess(), NULL, TRUE);
60 sym_set_options(SYMOPT_DEFERRED_LOADS | SYMOPT_PUBLICS_ONLY);
61 char sym_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
63 std::unordered_set<void*> seen;
64 std::unordered_set<std::string> seen_names;
66 for (void* sample : samples) {
67 // Only print the first call of a function.
68 if (seen.count(sample)) continue;
69 seen.insert(sample);
71 SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(sym_buf);
72 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
73 symbol->MaxNameLen = MAX_SYM_NAME;
74 DWORD64 offset = 0;
76 if (sym_from_addr(::GetCurrentProcess(), reinterpret_cast<DWORD64>(sample),
77 &offset, symbol)) {
78 const char* name = symbol->Name;
79 if (name[0] == '_') name++;
80 if (seen_names.count(name)) continue;
81 seen_names.insert(name);
83 fprintf(f, "%s\n", name);
87 fclose(f);
90 } // namespace
92 extern "C" {
94 MOZ_EXPORT void __cyg_profile_func_enter(void* this_fn,
95 void* call_site_unused) {
96 if (done) return;
98 // Get our index for the samples array atomically.
99 int n = num_samples++;
101 if (n < kSamplesCapacity) {
102 samples[n] = this_fn;
104 if (n + 1 == kSamplesCapacity) {
105 // This is the final sample; start dumping the samples to a file (on a
106 // separate thread so as not to disturb the main program).
107 done = 1;
108 _beginthread(dump, 0, nullptr);
113 MOZ_EXPORT void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
115 } // extern "C"