[scripts] Remove `perf-counters` (#35308)
Sebastian "Sebbie" Silbermann committed
Dec 6, 2025 at 12:33 UTC
c0b7c0d31fc325d6933cfe8f81dd23ccfdffa004
12 files changed
-1922
scripts/perf-counters/Makefile
deleted
-3
@@ -1,3 +0,0 @@
1
-build/jsc-perf: src/*
2
- mkdir -p build
3
- g++ -std=c++11 -I/usr/include/webkitgtk-1.0/ -ljavascriptcoregtk-1.0 src/jsc-perf.cpp src/hardware-counter.cpp src/thread-local.cpp -o build/jsc-perf
scripts/perf-counters/README.md
deleted
-16
@@ -1,16 +0,0 @@
1
-# perf-counters
2
-
3
-Lightweight bindings to Linux perf event counters.
4
-
5
-```
6
-$ node
7
-> var PerfCounters = require('perf-counters');
8
-> PerfCounters.init();
9
-> var start = PerfCounters.getCounters(); console.log('test'); var end = PerfCounters.getCounters();
10
-test
11
-> start
12
-{ instructions: 1382, loads: 421, stores: 309 }
13
-> end
14
-{ instructions: 647633, loads: 195771, stores: 133246 }
15
->
16
-```
scripts/perf-counters/binding.gyp
deleted
-15
@@ -1,15 +0,0 @@
1
-{
2
- "targets": [
3
- {
4
- "target_name": "perfcounters",
5
- "sources": [
6
- "src/hardware-counter.cpp",
7
- "src/perf-counters.cpp",
8
- "src/thread-local.cpp",
9
- ],
10
- "cflags": [
11
- "-Wno-sign-compare",
12
- ],
13
- },
14
- ],
15
-}
scripts/perf-counters/index.js
deleted
-3
@@ -1,3 +0,0 @@
1
-'use strict';
2
-
3
-module.exports = require('bindings')('perfcounters');
scripts/perf-counters/package.json
deleted
-10
@@ -1,10 +0,0 @@
1
-{
2
- "name": "perf-counters",
3
- "version": "0.1.2",
4
- "description": "Lightweight bindings to Linux perf event counters.",
5
- "main": "index.js",
6
- "license": "MIT",
7
- "dependencies": {
8
- "bindings": "^1.2.1"
9
- }
10
-}
scripts/perf-counters/src/hardware-counter.cpp
deleted
-469
@@ -1,469 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#include "hardware-counter.h"
9
-
10
-#ifndef NO_HARDWARE_COUNTERS
11
-
12
-#define _GNU_SOURCE 1
13
-#include <stdio.h>
14
-#include <stdlib.h>
15
-#include <string.h>
16
-#include <unistd.h>
17
-#include <fcntl.h>
18
-#include <errno.h>
19
-#include <assert.h>
20
-#include <sys/mman.h>
21
-#include <sys/ioctl.h>
22
-#include <asm/unistd.h>
23
-#include <sys/prctl.h>
24
-#include <linux/perf_event.h>
25
-
26
-namespace HPHP {
27
-///////////////////////////////////////////////////////////////////////////////
28
-
29
-IMPLEMENT_THREAD_LOCAL_NO_CHECK(HardwareCounter,
30
- HardwareCounter::s_counter);
31
-
32
-static bool s_recordSubprocessTimes = false;
33
-static bool s_profileHWEnable;
34
-static std::string s_profileHWEvents;
35
-
36
-static inline bool useCounters() {
37
-#ifdef VALGRIND
38
- return false;
39
-#else
40
- return s_profileHWEnable;
41
-#endif
42
-}
43
-
44
-class HardwareCounterImpl {
45
-public:
46
- HardwareCounterImpl(int type, unsigned long config,
47
- const char* desc = nullptr)
48
- : m_desc(desc ? desc : ""), m_err(0), m_fd(-1), inited(false) {
49
- memset (&pe, 0, sizeof (struct perf_event_attr));
50
- pe.type = type;
51
- pe.size = sizeof (struct perf_event_attr);
52
- pe.config = config;
53
- pe.inherit = s_recordSubprocessTimes;
54
- pe.disabled = 1;
55
- pe.pinned = 0;
56
- pe.exclude_kernel = 0;
57
- pe.exclude_hv = 1;
58
- pe.read_format =
59
- PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING;
60
- }
61
-
62
- ~HardwareCounterImpl() {
63
- close();
64
- }
65
-
66
- void init_if_not() {
67
- /*
68
- * perf_event_open(struct perf_event_attr *hw_event_uptr, pid_t pid,
69
- * int cpu, int group_fd, unsigned long flags)
70
- */
71
- if (inited) return;
72
- inited = true;
73
- m_fd = syscall(__NR_perf_event_open, &pe, 0, -1, -1, 0);
74
- if (m_fd < 0) {
75
- // Logger::Verbose("perf_event_open failed with: %s",
76
- // folly::errnoStr(errno).c_str());
77
- m_err = -1;
78
- return;
79
- }
80
- if (ioctl(m_fd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
81
- // Logger::Warning("perf_event failed to enable: %s",
82
- // folly::errnoStr(errno).c_str());
83
- close();
84
- m_err = -1;
85
- return;
86
- }
87
- reset();
88
- }
89
-
90
- int64_t read() {
91
- uint64_t values[3];
92
- if (readRaw(values)) {
93
- if (!values[2]) return 0;
94
- int64_t value = (double)values[0] * values[1] / values[2];
95
- return value + extra;
96
- }
97
- return 0;
98
- }
99
-
100
- void incCount(int64_t amount) {
101
- extra += amount;
102
- }
103
-
104
- bool readRaw(uint64_t* values) {
105
- if (m_err || !useCounters()) return false;
106
- init_if_not();
107
-
108
- if (m_fd > 0) {
109
- /*
110
- * read the count + scaling values
111
- *
112
- * It is not necessary to stop an event to read its value
113
- */
114
- auto ret = ::read(m_fd, values, sizeof(*values) * 3);
115
- if (ret == sizeof(*values) * 3) {
116
- values[0] -= reset_values[0];
117
- values[1] -= reset_values[1];
118
- values[2] -= reset_values[2];
119
- return true;
120
- }
121
- }
122
- return false;
123
- }
124
-
125
- void reset() {
126
- if (m_err || !useCounters()) return;
127
- init_if_not();
128
- extra = 0;
129
- if (m_fd > 0) {
130
- if (ioctl (m_fd, PERF_EVENT_IOC_RESET, 0) < 0) {
131
- // Logger::Warning("perf_event failed to reset with: %s",
132
- // folly::errnoStr(errno).c_str());
133
- m_err = -1;
134
- return;
135
- }
136
- auto ret = ::read(m_fd, reset_values, sizeof(reset_values));
137
- if (ret != sizeof(reset_values)) {
138
- // Logger::Warning("perf_event failed to reset with: %s",
139
- // folly::errnoStr(errno).c_str());
140
- m_err = -1;
141
- return;
142
- }
143
- }
144
- }
145
-
146
-public:
147
- std::string m_desc;
148
- int m_err;
149
-private:
150
- int m_fd;
151
- struct perf_event_attr pe;
152
- bool inited;
153
- uint64_t reset_values[3];
154
- uint64_t extra{0};
155
-
156
- void close() {
157
- if (m_fd > 0) {
158
- ::close(m_fd);
159
- m_fd = -1;
160
- }
161
- }
162
-};
163
-
164
-class InstructionCounter : public HardwareCounterImpl {
165
-public:
166
- InstructionCounter() :
167
- HardwareCounterImpl(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS) {}
168
-};
169
-
170
-class LoadCounter : public HardwareCounterImpl {
171
-public:
172
- LoadCounter() :
173
- HardwareCounterImpl(PERF_TYPE_HW_CACHE,
174
- (PERF_COUNT_HW_CACHE_L1D | ((PERF_COUNT_HW_CACHE_OP_READ) << 8))) {}
175
-};
176
-
177
-class StoreCounter : public HardwareCounterImpl {
178
-public:
179
- StoreCounter() :
180
- HardwareCounterImpl(PERF_TYPE_HW_CACHE,
181
- PERF_COUNT_HW_CACHE_L1D | ((PERF_COUNT_HW_CACHE_OP_WRITE) << 8)) {}
182
-};
183
-
184
-HardwareCounter::HardwareCounter()
185
- : m_countersSet(false) {
186
- m_instructionCounter.reset(new InstructionCounter());
187
- if (s_profileHWEvents.empty()) {
188
- m_loadCounter.reset(new LoadCounter());
189
- m_storeCounter.reset(new StoreCounter());
190
- } else {
191
- m_countersSet = true;
192
- setPerfEvents(s_profileHWEvents);
193
- }
194
-}
195
-
196
-HardwareCounter::~HardwareCounter() {
197
-}
198
-
199
-void HardwareCounter::Init(bool enable, const std::string& events,
200
- bool subProc) {
201
- s_profileHWEnable = enable;
202
- s_profileHWEvents = events;
203
- s_recordSubprocessTimes = subProc;
204
-}
205
-
206
-void HardwareCounter::Reset() {
207
- s_counter->reset();
208
-}
209
-
210
-void HardwareCounter::reset() {
211
- m_instructionCounter->reset();
212
- if (!m_countersSet) {
213
- m_storeCounter->reset();
214
- m_loadCounter->reset();
215
- }
216
- for (unsigned i = 0; i < m_counters.size(); i++) {
217
- m_counters[i]->reset();
218
- }
219
-}
220
-
221
-int64_t HardwareCounter::GetInstructionCount() {
222
- return s_counter->getInstructionCount();
223
-}
224
-
225
-int64_t HardwareCounter::getInstructionCount() {
226
- return m_instructionCounter->read();
227
-}
228
-
229
-int64_t HardwareCounter::GetLoadCount() {
230
- return s_counter->getLoadCount();
231
-}
232
-
233
-int64_t HardwareCounter::getLoadCount() {
234
- return m_loadCounter->read();
235
-}
236
-
237
-int64_t HardwareCounter::GetStoreCount() {
238
- return s_counter->getStoreCount();
239
-}
240
-
241
-int64_t HardwareCounter::getStoreCount() {
242
- return m_storeCounter->read();
243
-}
244
-
245
-void HardwareCounter::IncInstructionCount(int64_t amount) {
246
- s_counter->m_instructionCounter->incCount(amount);
247
-}
248
-
249
-void HardwareCounter::IncLoadCount(int64_t amount) {
250
- if (!s_counter->m_countersSet) {
251
- s_counter->m_loadCounter->incCount(amount);
252
- }
253
-}
254
-
255
-void HardwareCounter::IncStoreCount(int64_t amount) {
256
- if (!s_counter->m_countersSet) {
257
- s_counter->m_storeCounter->incCount(amount);
258
- }
259
-}
260
-
261
-struct PerfTable perfTable[] = {
262
- /* PERF_TYPE_HARDWARE events */
263
-#define PC(n) PERF_TYPE_HARDWARE, PERF_COUNT_HW_ ## n
264
- { "cpu-cycles", PC(CPU_CYCLES) },
265
- { "cycles", PC(CPU_CYCLES) },
266
- { "instructions", PC(INSTRUCTIONS) },
267
- { "cache-references", PC(CACHE_REFERENCES) },
268
- { "cache-misses", PC(CACHE_MISSES) },
269
- { "branch-instructions", PC(BRANCH_INSTRUCTIONS) },
270
- { "branches", PC(BRANCH_INSTRUCTIONS) },
271
- { "branch-misses", PC(BRANCH_MISSES) },
272
- { "bus-cycles", PC(BUS_CYCLES) },
273
- { "stalled-cycles-frontend", PC(STALLED_CYCLES_FRONTEND) },
274
- { "stalled-cycles-backend", PC(STALLED_CYCLES_BACKEND) },
275
-
276
- /* PERF_TYPE_HW_CACHE hw_cache_id */
277
-#define PCC(n) PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_ ## n
278
- { "L1-dcache-", PCC(L1D) },
279
- { "L1-icache-", PCC(L1I) },
280
- { "LLC-", PCC(LL) },
281
- { "dTLB-", PCC(DTLB) },
282
- { "iTLB-", PCC(ITLB) },
283
- { "branch-", PCC(BPU) },
284
-
285
- /* PERF_TYPE_HW_CACHE hw_cache_op, hw_cache_result */
286
-#define PCCO(n, m) PERF_TYPE_HW_CACHE, \
287
- ((PERF_COUNT_HW_CACHE_OP_ ## n) << 8 | \
288
- (PERF_COUNT_HW_CACHE_RESULT_ ## m) << 16)
289
- { "loads", PCCO(READ, ACCESS) },
290
- { "load-misses", PCCO(READ, MISS) },
291
- { "stores", PCCO(WRITE, ACCESS) },
292
- { "store-misses", PCCO(WRITE, MISS) },
293
- { "prefetches", PCCO(PREFETCH, ACCESS) },
294
- { "prefetch-misses", PCCO(PREFETCH, MISS) }
295
-};
296
-
297
-static int findEvent(const char *event, struct PerfTable *t,
298
- int len, int *match_len) {
299
- int i;
300
-
301
- for (i = 0; i < len; i++) {
302
- if (!strncmp(event, t[i].name, strlen(t[i].name))) {
303
- *match_len = strlen(t[i].name);
304
- return i;
305
- }
306
- }
307
- return -1;
308
-}
309
-
310
-#define CPUID_STEPPING(x) ((x) & 0xf)
311
-#define CPUID_MODEL(x) (((x) & 0xf0) >> 4)
312
-#define CPUID_FAMILY(x) (((x) & 0xf00) >> 8)
313
-#define CPUID_TYPE(x) (((x) & 0x3000) >> 12)
314
-
315
-// hack to get LLC counters on perflab frc machines
316
-static bool isIntelE5_2670() {
317
-#ifdef __x86_64__
318
- unsigned long x;
319
- asm volatile ("cpuid" : "=a"(x): "a"(1) : "ebx", "ecx", "edx");
320
- return CPUID_STEPPING(x) == 6 && CPUID_MODEL(x) == 0xd
321
- && CPUID_FAMILY(x) == 6 && CPUID_TYPE(x) == 0;
322
-#else
323
- return false;
324
-#endif
325
-}
326
-
327
-static void checkLLCHack(const char* event, uint32_t& type, uint64_t& config) {
328
- if (!strncmp(event, "LLC-load", 8) && isIntelE5_2670()) {
329
- type = PERF_TYPE_RAW;
330
- if (!strncmp(&event[4], "loads", 5)) {
331
- config = 0x534f2e;
332
- } else if (!strncmp(&event[4], "load-misses", 11)) {
333
- config = 0x53412e;
334
- }
335
- }
336
-}
337
-
338
-bool HardwareCounter::addPerfEvent(const char* event) {
339
- uint32_t type = 0;
340
- uint64_t config = 0;
341
- int i, match_len;
342
- bool found = false;
343
- const char* ev = event;
344
-
345
- while ((i = findEvent(ev, perfTable,
346
- sizeof(perfTable)/sizeof(struct PerfTable),
347
- &match_len))
348
- != -1) {
349
- if (!found) {
350
- found = true;
351
- type = perfTable[i].type;
352
- } else if (type != perfTable[i].type) {
353
- // Logger::Warning("failed to find perf event: %s", event);
354
- return false;
355
- }
356
- config |= perfTable[i].config;
357
- ev = &ev[match_len];
358
- }
359
-
360
- checkLLCHack(event, type, config);
361
-
362
- // Check if we have a raw spec.
363
- if (!found && event[0] == 'r' && event[1] != 0) {
364
- config = strtoull(event + 1, const_cast<char**>(&ev), 16);
365
- if (*ev == 0) {
366
- found = true;
367
- type = PERF_TYPE_RAW;
368
- }
369
- }
370
-
371
- if (!found || *ev) {
372
- // Logger::Warning("failed to find perf event: %s", event);
373
- return false;
374
- }
375
- std::unique_ptr<HardwareCounterImpl> hwc(
376
- new HardwareCounterImpl(type, config, event));
377
- if (hwc->m_err) {
378
- // Logger::Warning("failed to set perf event: %s", event);
379
- return false;
380
- }
381
- m_counters.emplace_back(std::move(hwc));
382
- if (!m_countersSet) {
383
- // reset load and store counters. This is because
384
- // perf does not seem to handle more than three counters
385
- // very well.
386
- m_loadCounter.reset();
387
- m_storeCounter.reset();
388
- m_countersSet = true;
389
- }
390
- return true;
391
-}
392
-
393
-bool HardwareCounter::eventExists(const char *event) {
394
- // hopefully m_counters set is small, so a linear scan does not hurt
395
- for(unsigned i = 0; i < m_counters.size(); i++) {
396
- if (!strcmp(event, m_counters[i]->m_desc.c_str())) {
397
- return true;
398
- }
399
- }
400
- return false;
401
-}
402
-
403
-bool HardwareCounter::setPerfEvents(std::string sevents) {
404
- // Make a copy of the string for use with strtok.
405
- auto const sevents_buf = static_cast<char*>(malloc(sevents.size() + 1));
406
- memcpy(sevents_buf, sevents.data(), sevents.size());
407
- sevents_buf[sevents.size()] = '\0';
408
-
409
- char* strtok_buf = nullptr;
410
- char* s = strtok_r(sevents_buf, ",", &strtok_buf);
411
- bool success = true;
412
- while (s) {
413
- if (!eventExists(s) && !addPerfEvent(s)) {
414
- success = false;
415
- break;
416
- }
417
- s = strtok_r(nullptr, ",", &strtok_buf);
418
- }
419
- free(sevents_buf);
420
- return success;
421
-}
422
-
423
-bool HardwareCounter::SetPerfEvents(std::string events) {
424
- return s_counter->setPerfEvents(events);
425
-}
426
-
427
-void HardwareCounter::clearPerfEvents() {
428
- m_counters.clear();
429
-}
430
-
431
-void HardwareCounter::ClearPerfEvents() {
432
- s_counter->clearPerfEvents();
433
-}
434
-
435
-const std::string
436
- s_instructions("instructions"),
437
- s_loads("loads"),
438
- s_stores("stores");
439
-
440
-void HardwareCounter::getPerfEvents(PerfEventCallback f, void* data) {
441
- f(s_instructions, getInstructionCount(), data);
442
- if (!m_countersSet) {
443
- f(s_loads, getLoadCount(), data);
444
- f(s_stores, getStoreCount(), data);
445
- }
446
- for (unsigned i = 0; i < m_counters.size(); i++) {
447
- f(m_counters[i]->m_desc, m_counters[i]->read(), data);
448
- }
449
-}
450
-
451
-void HardwareCounter::GetPerfEvents(PerfEventCallback f, void* data) {
452
- s_counter->getPerfEvents(f, data);
453
-}
454
-
455
-///////////////////////////////////////////////////////////////////////////////
456
-}
457
-
458
-
459
-#else // NO_HARDWARE_COUNTERS
460
-
461
-namespace HPHP {
462
-///////////////////////////////////////////////////////////////////////////////
463
-
464
-HardwareCounter HardwareCounter::s_counter;
465
-
466
-///////////////////////////////////////////////////////////////////////////////
467
-}
468
-
469
-#endif // NO_HARDWARE_COUNTERS
scripts/perf-counters/src/hardware-counter.h
deleted
-108
@@ -1,108 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#ifndef incl_HPHP_UTIL_HARDWARE_COUNTER_H_
9
-#define incl_HPHP_UTIL_HARDWARE_COUNTER_H_
10
-
11
-#include "thread-local.h"
12
-
13
-#include <cstdint>
14
-#include <memory>
15
-#include <vector>
16
-
17
-namespace HPHP {
18
-///////////////////////////////////////////////////////////////////////////////
19
-
20
-#ifndef NO_HARDWARE_COUNTERS
21
-
22
-class InstructionCounter;
23
-class LoadCounter;
24
-class StoreCounter;
25
-
26
-struct PerfTable {
27
- const char* name;
28
- uint32_t type;
29
- uint64_t config;
30
-};
31
-
32
-class HardwareCounterImpl;
33
-
34
-class HardwareCounter {
35
-public:
36
- HardwareCounter();
37
- ~HardwareCounter();
38
-
39
- static void Reset();
40
- static int64_t GetInstructionCount();
41
- static int64_t GetLoadCount();
42
- static int64_t GetStoreCount();
43
- static bool SetPerfEvents(std::string events);
44
- static void IncInstructionCount(int64_t amount);
45
- static void IncLoadCount(int64_t amount);
46
- static void IncStoreCount(int64_t amount);
47
-
48
- typedef void (*PerfEventCallback)(const std::string&, int64_t, void*);
49
- static void GetPerfEvents(PerfEventCallback f, void* data);
50
- static void ClearPerfEvents();
51
- static void Init(bool enable, const std::string& events, bool subProc);
52
- static DECLARE_THREAD_LOCAL_NO_CHECK(HardwareCounter, s_counter);
53
- bool m_countersSet{false};
54
-private:
55
- void reset();
56
- int64_t getInstructionCount();
57
- int64_t getLoadCount();
58
- int64_t getStoreCount();
59
- bool eventExists(const char* event);
60
- bool addPerfEvent(const char* event);
61
- bool setPerfEvents(std::string events);
62
- void getPerfEvents(PerfEventCallback f, void* data);
63
- void clearPerfEvents();
64
-
65
- std::unique_ptr<InstructionCounter> m_instructionCounter;
66
- std::unique_ptr<LoadCounter> m_loadCounter;
67
- std::unique_ptr<StoreCounter> m_storeCounter;
68
- std::vector<std::unique_ptr<HardwareCounterImpl>> m_counters;
69
-};
70
-
71
-#else // NO_HARDWARE_COUNTERS
72
-
73
-/* Stub implementation for platforms without hardware counters (non-linux)
74
- * This mock class pretends to track performance events, but just returns
75
- * static values, so it doesn't even need to worry about thread safety
76
- * for the one static instance of itself.
77
- */
78
-class HardwareCounter {
79
-public:
80
- HardwareCounter() : m_countersSet(false) { }
81
- ~HardwareCounter() { }
82
-
83
- static void Reset() { }
84
- static int64_t GetInstructionCount() { return 0; }
85
- static int64_t GetLoadCount() { return 0; }
86
- static int64_t GetStoreCount() { return 0; }
87
- static bool SetPerfEvents(folly::StringPiece events) { return false; }
88
- static void IncInstructionCount(int64_t amount) {}
89
- static void IncLoadCount(int64_t amount) {}
90
- static void IncStoreCount(int64_t amount) {}
91
- typedef void (*PerfEventCallback)(const std::string&, int64_t, void*);
92
- static void GetPerfEvents(PerfEventCallback f, void* data) { }
93
- static void ClearPerfEvents() { }
94
- static void Init(bool enable, const std::string& events, bool subProc) {}
95
-
96
- // Normally exposed by DECLARE_THREAD_LOCAL_NO_CHECK
97
- void getCheck() { }
98
- void destroy() { }
99
- static HardwareCounter s_counter;
100
- bool m_countersSet;
101
-};
102
-
103
-#endif // NO_HARDWARE_COUNTERS
104
-
105
-///////////////////////////////////////////////////////////////////////////////
106
-}
107
-
108
-#endif
scripts/perf-counters/src/jsc-perf.cpp
deleted
-202
@@ -1,202 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#include <errno.h>
9
-#include <stdlib.h>
10
-#include <string.h>
11
-
12
-#include <fstream>
13
-#include <iostream>
14
-#include <string>
15
-
16
-#include <JavaScriptCore/JavaScript.h>
17
-
18
-#include "hardware-counter.h"
19
-
20
-using HPHP::HardwareCounter;
21
-
22
-void add_native_hook(
23
- JSContextRef ctx,
24
- JSObjectRef obj,
25
- const char *name,
26
- JSObjectCallAsFunctionCallback hook
27
-) {
28
- JSStringRef jsName = JSStringCreateWithUTF8CString(name);
29
- JSObjectSetProperty(
30
- ctx,
31
- obj,
32
- jsName,
33
- JSObjectMakeFunctionWithCallback(ctx, jsName, hook),
34
- kJSPropertyAttributeNone,
35
- NULL
36
- );
37
- JSStringRelease(jsName);
38
-}
39
-
40
-static void fprint_value(
41
- FILE *file,
42
- JSContextRef context,
43
- JSValueRef obj
44
-) {
45
- JSStringRef jsStr = JSValueToStringCopy(context, obj, NULL);
46
- size_t size = JSStringGetMaximumUTF8CStringSize(jsStr);
47
- char *str = (char *) calloc(
48
- size,
49
- 1
50
- );
51
- JSStringGetUTF8CString(
52
- jsStr,
53
- str,
54
- size
55
- );
56
- JSStringRelease(jsStr);
57
- fprintf(file, "%s", str);
58
- free(str);
59
-}
60
-
61
-static JSValueRef js_print(
62
- JSContextRef context,
63
- JSObjectRef object,
64
- JSObjectRef thisObject,
65
- size_t argumentCount,
66
- const JSValueRef arguments[],
67
- JSValueRef *exception
68
-) {
69
- for (int i = 0; i < argumentCount; i++) {
70
- if (i != 0) {
71
- printf(" ");
72
- }
73
- fprint_value(stdout, context, arguments[i]);
74
- }
75
- printf("\n");
76
- return JSValueMakeUndefined(context);
77
-}
78
-
79
-static JSValueRef js_perf_counters_init(
80
- JSContextRef context,
81
- JSObjectRef object,
82
- JSObjectRef thisObject,
83
- size_t argumentCount,
84
- const JSValueRef arguments[],
85
- JSValueRef *exception
86
-) {
87
- // TODO: Allow customizing recorded events
88
- bool enable = true;
89
- std::string events = "";
90
- bool recordSubprocesses = false;
91
- HardwareCounter::Init(enable, events, recordSubprocesses);
92
- HardwareCounter::s_counter.getCheck();
93
-
94
- return JSValueMakeUndefined(context);
95
-}
96
-
97
-static JSValueRef js_perf_counters_get_counters(
98
- JSContextRef context,
99
- JSObjectRef object,
100
- JSObjectRef thisObject,
101
- size_t argumentCount,
102
- const JSValueRef arguments[],
103
- JSValueRef *exception
104
-) {
105
- JSObjectRef result = JSObjectMake(context, NULL, NULL);
106
- std::pair<JSContextRef, JSObjectRef> pair(context, result);
107
-
108
- HardwareCounter::GetPerfEvents(
109
- [](const std::string& key, int64_t value, void* data) {
110
- std::pair<JSContextRef, JSObjectRef>& pair =
111
- *reinterpret_cast<std::pair<JSContextRef, JSObjectRef>*>(data);
112
- JSContextRef context = pair.first;
113
- JSObjectRef result = pair.second;
114
-
115
- JSObjectSetProperty(
116
- context,
117
- result,
118
- JSStringCreateWithUTF8CString(key.c_str()),
119
- JSValueMakeNumber(context, value),
120
- kJSPropertyAttributeNone,
121
- NULL
122
- );
123
- },
124
- &pair);
125
-
126
- return result;
127
-}
128
-
129
-int main(int argc, char **argv) {
130
- if (argc != 2) {
131
- fprintf(stderr, "usage: jsc-runner file\n");
132
- exit(1);
133
- }
134
-
135
- char *filename = argv[1];
136
- std::ifstream ifs(filename);
137
- if (ifs.fail()) {
138
- std::cerr << "Error opening \"" << filename << "\": " << strerror(errno) << "\n";
139
- exit(1);
140
- }
141
- std::string script(
142
- (std::istreambuf_iterator<char>(ifs)),
143
- (std::istreambuf_iterator<char>())
144
- );
145
- JSStringRef jsScript = JSStringCreateWithUTF8CString(script.c_str());
146
- JSStringRef jsURL = JSStringCreateWithUTF8CString(argv[1]);
147
-
148
- JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
149
- add_native_hook(
150
- ctx,
151
- JSContextGetGlobalObject(ctx),
152
- "print",
153
- js_print
154
- );
155
-
156
- JSObjectRef jsPerfCounters = JSObjectMake(ctx, NULL, NULL);
157
- add_native_hook(
158
- ctx,
159
- jsPerfCounters,
160
- "init",
161
- js_perf_counters_init
162
- );
163
- add_native_hook(
164
- ctx,
165
- jsPerfCounters,
166
- "getCounters",
167
- js_perf_counters_get_counters
168
- );
169
- JSObjectSetProperty(
170
- ctx,
171
- JSContextGetGlobalObject(ctx),
172
- JSStringCreateWithUTF8CString("PerfCounters"),
173
- jsPerfCounters,
174
- kJSPropertyAttributeNone,
175
- NULL
176
- );
177
-
178
- JSValueRef jsError = NULL;
179
- JSValueRef result = JSEvaluateScript(
180
- ctx,
181
- jsScript,
182
- NULL,
183
- jsURL,
184
- 0,
185
- &jsError
186
- );
187
- if (!result) {
188
- fprintf(stderr, "Exception: ");
189
- fprint_value(stderr, ctx, jsError);
190
- fprintf(stderr, "\n");
191
- JSStringRef jsStackStr = JSStringCreateWithUTF8CString("stack");
192
- if (JSValueIsObject(ctx, jsError)) {
193
- JSValueRef jsStack = JSObjectGetProperty(ctx, (JSObjectRef)jsError, jsStackStr, NULL);
194
- JSStringRelease(jsStackStr);
195
- fprint_value(stderr, ctx, jsStack);
196
- fprintf(stderr, "\n");
197
- }
198
- exit(1);
199
- }
200
-
201
- JSGlobalContextRelease(ctx);
202
-}
scripts/perf-counters/src/perf-counters.cpp
deleted
-53
@@ -1,53 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#include <node.h>
9
-
10
-#include "hardware-counter.h"
11
-
12
-namespace PerfCounters {
13
-
14
-using HPHP::HardwareCounter;
15
-
16
-void Init(const v8::FunctionCallbackInfo<v8::Value>& args) {
17
- // TODO: Allow customizing recorded events
18
- bool enable = true;
19
- std::string events = "";
20
- bool recordSubprocesses = false;
21
- HardwareCounter::Init(enable, events, recordSubprocesses);
22
- HardwareCounter::s_counter.getCheck();
23
-}
24
-
25
-void GetCounters(const v8::FunctionCallbackInfo<v8::Value>& args) {
26
- v8::Isolate* isolate = args.GetIsolate();
27
- v8::Local<v8::Object> obj = v8::Object::New(isolate);
28
- std::pair<v8::Isolate*, v8::Local<v8::Object>> pair(isolate, obj);
29
-
30
- HardwareCounter::GetPerfEvents(
31
- [](const std::string& key, int64_t value, void* data) {
32
- std::pair<v8::Isolate*, v8::Local<v8::Object>>& pair =
33
- *reinterpret_cast<std::pair<v8::Isolate*, v8::Local<v8::Object>>*>(data);
34
- v8::Isolate* isolate = pair.first;
35
- v8::Local<v8::Object> obj = pair.second;
36
- obj->Set(
37
- v8::String::NewFromUtf8(isolate, key.c_str()),
38
- v8::Number::New(isolate, value)
39
- );
40
- },
41
- &pair);
42
-
43
- args.GetReturnValue().Set(obj);
44
-}
45
-
46
-void InitModule(v8::Local<v8::Object> exports) {
47
- NODE_SET_METHOD(exports, "init", Init);
48
- NODE_SET_METHOD(exports, "getCounters", GetCounters);
49
-}
50
-
51
-NODE_MODULE(perfcounters, InitModule)
52
-
53
-}
scripts/perf-counters/src/portability.h
deleted
-184
@@ -1,184 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#ifndef incl_HPHP_PORTABILITY_H_
9
-#define incl_HPHP_PORTABILITY_H_
10
-
11
-// From folly/Likely.h
12
-#if defined(__GNUC__) && __GNUC__ >= 4
13
-#define LIKELY(x) (__builtin_expect((x), 1))
14
-#define UNLIKELY(x) (__builtin_expect((x), 0))
15
-#else
16
-#define LIKELY(x) (x)
17
-#define UNLIKELY(x) (x)
18
-#endif
19
-
20
-//////////////////////////////////////////////////////////////////////
21
-
22
-/*
23
- * Various macros to make certain things conditional on either
24
- * compiler or architecture.
25
- *
26
- * Currently we don't *really* compile on anything other than gcc or
27
- * sometimes clang, and there are some parts of the code using
28
- * __attribute__ stuff directly, but some things go through these
29
- * macros to make it maybe easier to change later.
30
- */
31
-
32
-//////////////////////////////////////////////////////////////////////
33
-
34
-// TODO: does clang define __GNUC__ ?
35
-#ifndef __GNUC__
36
-# define __attribute__(x)
37
-#endif
38
-
39
-//////////////////////////////////////////////////////////////////////
40
-
41
-#ifdef ATTRIBUTE_UNUSED
42
-# undef ATTRIBUTE_UNUSED
43
-#endif
44
-#ifdef ATTRIBUTE_NORETURN
45
-# undef ATTRIBUTE_NORETURN
46
-#endif
47
-#ifdef ATTRIBUTE_PRINTF
48
-# undef ATTRIBUTE_PRINTF
49
-#endif
50
-#ifdef ATTRIBUTE_PRINTF_STRING
51
-# undef ATTRIBUTE_PRINTF_STRING
52
-#endif
53
-
54
-#define ATTRIBUTE_PRINTF_STRING FOLLY_PRINTF_FORMAT
55
-
56
-#ifdef _MSC_VER
57
-#define ATTRIBUTE_NORETURN __declspec(noreturn)
58
-#define ATTRIBUTE_PRINTF(a1, a2)
59
-#ifndef __thread
60
-# define __thread __declspec(thread)
61
-#endif
62
-#define ATTRIBUTE_UNUSED
63
-
64
-#define ALWAYS_INLINE __forceinline
65
-#define EXTERNALLY_VISIBLE
66
-#define FLATTEN
67
-#define NEVER_INLINE __declspec(noinline)
68
-#define UNUSED
69
-#else
70
-#define ATTRIBUTE_NORETURN __attribute__((__noreturn__))
71
-#define ATTRIBUTE_PRINTF(a1, a2) \
72
- __attribute__((__format__ (__printf__, a1, a2)))
73
-#define ATTRIBUTE_UNUSED __attribute__((__unused__))
74
-
75
-#define ALWAYS_INLINE inline __attribute__((__always_inline__))
76
-#define EXTERNALLY_VISIBLE __attribute__((__externally_visible__))
77
-#define FLATTEN __attribute__((__flatten__))
78
-#define NEVER_INLINE __attribute__((__noinline__))
79
-#define UNUSED __attribute__((__unused__))
80
-#endif
81
-
82
-#ifdef DEBUG
83
-# define DEBUG_ONLY /* nop */
84
-#else
85
-# define DEBUG_ONLY UNUSED
86
-#endif
87
-
88
-/*
89
- * We need to keep some unreferenced functions from being removed by
90
- * the linker. There is no compile time mechanism for doing this, but
91
- * by putting them in the same section as some other, referenced function
92
- * in the same file, we can keep them around.
93
- *
94
- * So this macro should be used to mark at least one function that is
95
- * referenced, and other functions that are not referenced in the same
96
- * file.
97
- *
98
- * Note: this may not work properly with LTO. We'll revisit when/if we
99
- * move to it.
100
- */
101
-#ifndef __APPLE__
102
-# define KEEP_SECTION \
103
- __attribute__((__section__(".text.keep")))
104
-#else
105
-# define KEEP_SECTION \
106
- __attribute__((__section__(".text,.text.keep")))
107
-#endif
108
-
109
-#if defined(__APPLE__)
110
-// OS X has a macro "isset" defined in this header. Force the include so we can
111
-// make sure the macro gets undef'd. (I think this also applies to BSD, but we
112
-// can cross that road when we come to it.)
113
-# include <sys/param.h>
114
-# ifdef isset
115
-# undef isset
116
-# endif
117
-#endif
118
-
119
-//////////////////////////////////////////////////////////////////////
120
-
121
-#if defined(__x86_64__)
122
-
123
-# if defined(__clang__)
124
-# define DECLARE_FRAME_POINTER(fp) \
125
- ActRec* fp; \
126
- asm volatile("mov %%rbp, %0" : "=r" (fp) ::)
127
-# else
128
-# define DECLARE_FRAME_POINTER(fp) register ActRec* fp asm("rbp");
129
-# endif
130
-
131
-#elif defined(_M_X64)
132
-
133
-// TODO: FIXME! Without this implemented properly, the JIT
134
-// will fail "pretty spectacularly".
135
-# define DECLARE_FRAME_POINTER(fp) \
136
- always_assert(false); \
137
- register ActRec* fp = nullptr;
138
-
139
-#elif defined(__AARCH64EL__)
140
-
141
-# if defined(__clang__)
142
-# error Clang implementation not done for ARM
143
-# endif
144
-# define DECLARE_FRAME_POINTER(fp) register ActRec* fp asm("x29");
145
-
146
-#elif defined(__powerpc64__)
147
-
148
-# if defined(__clang__)
149
-# error Clang implementation not done for PPC64
150
-# endif
151
-# define DECLARE_FRAME_POINTER(fp) register ActRec* fp = (ActRec*) __builtin_frame_address(0);
152
-
153
-#else
154
-
155
-# error What are the stack and frame pointers called on your architecture?
156
-
157
-#endif
158
-
159
-//////////////////////////////////////////////////////////////////////
160
-
161
-// We reserve the exit status 127 to signal a failure in the
162
-// interpreter. 127 is a valid exit code on all reasonable
163
-// architectures: POSIX requires at least 8 unsigned bits and
164
-// Windows 32 signed bits.
165
-#define HPHP_EXIT_FAILURE 127
166
-
167
-//////////////////////////////////////////////////////////////////////
168
-
169
-#if FACEBOOK
170
-// Linking in libbfd is a gigantic PITA. If you want this yourself in a non-FB
171
-// build, feel free to define HAVE_LIBBFD and specify the right options to link
172
-// in libbfd.a in the extra C++ options.
173
-#define HAVE_LIBBFD 1
174
-#endif
175
-
176
-#ifndef PACKAGE
177
-// The value doesn't matter, but it must be defined before you include
178
-// bfd.h
179
-#define PACKAGE "hhvm"
180
-#endif
181
-
182
-//////////////////////////////////////////////////////////////////////
183
-
184
-#endif
scripts/perf-counters/src/thread-local.cpp
deleted
-99
@@ -1,99 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#include "thread-local.h"
9
-
10
-#ifdef __linux__
11
-#include <link.h>
12
-#include <asm/prctl.h>
13
-#include <sys/prctl.h>
14
-extern "C" {
15
-extern int arch_prctl(int, unsigned long*);
16
-}
17
-#endif //__linux__
18
-
19
-namespace HPHP {
20
-
21
-#ifdef USE_GCC_FAST_TLS
22
-
23
-void ThreadLocalManager::OnThreadExit(void* p) {
24
- auto list = getList(p);
25
- p = list->head;
26
- delete list;
27
- while (p != nullptr) {
28
- auto* pNode = static_cast<ThreadLocalNode<void>*>(p);
29
- if (pNode->m_on_thread_exit_fn) {
30
- pNode->m_on_thread_exit_fn(p);
31
- }
32
- p = pNode->m_next;
33
- }
34
-}
35
-
36
-void ThreadLocalManager::PushTop(void* nodePtr, size_t nodeSize) {
37
- auto& node = *static_cast<ThreadLocalNode<void>*>(nodePtr);
38
- auto key = GetManager().m_key;
39
- auto list = getList(pthread_getspecific(key));
40
- if (UNLIKELY(!list)) {
41
- ThreadLocalSetValue(key, list = new ThreadLocalList);
42
- }
43
- node.m_next = list->head;
44
- node.m_size = nodeSize;
45
- list->head = node.m_next;
46
-}
47
-
48
-ThreadLocalManager& ThreadLocalManager::GetManager() {
49
- static ThreadLocalManager m;
50
- return m;
51
-}
52
-
53
-#ifdef __APPLE__
54
-ThreadLocalManager::ThreadLocalList::ThreadLocalList() {
55
- pthread_t self = pthread_self();
56
- handler.__routine = ThreadLocalManager::OnThreadExit;
57
- handler.__arg = this;
58
- handler.__next = self->__cleanup_stack;
59
- self->__cleanup_stack = &handler;
60
-}
61
-#endif
62
-
63
-#endif
64
-
65
-#ifdef __linux__
66
-
67
-static int visit_phdr(dl_phdr_info* info, size_t, void*) {
68
- for (size_t i = 0, n = info->dlpi_phnum; i < n; ++i) {
69
- const auto& hdr = info->dlpi_phdr[i];
70
- auto addr = info->dlpi_addr + hdr.p_vaddr;
71
- if (addr < 0x100000000LL && hdr.p_type == PT_TLS) {
72
- // found the main thread-local section
73
- assert(int(hdr.p_memsz) == hdr.p_memsz); // ensure no truncation
74
- return hdr.p_memsz;
75
- }
76
- }
77
- return 0;
78
-}
79
-
80
-std::pair<void*,size_t> getCppTdata() {
81
- uintptr_t addr;
82
- if (!arch_prctl(ARCH_GET_FS, &addr)) {
83
- // fs points to the end of the threadlocal area.
84
- size_t size = dl_iterate_phdr(&visit_phdr, nullptr);
85
- return {(void*)(addr - size), size};
86
- }
87
- return {nullptr, 0};
88
-}
89
-
90
-#else
91
-
92
-// how do you find the thread local section on your system?
93
-std::pair<void*,size_t> getCppTdata() {
94
- return {nullptr, 0};
95
-}
96
-
97
-#endif //__linux__
98
-
99
-}
scripts/perf-counters/src/thread-local.h
deleted
-760
@@ -1,760 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
-#ifndef incl_HPHP_THREAD_LOCAL_H_
9
-#define incl_HPHP_THREAD_LOCAL_H_
10
-
11
-#include <assert.h>
12
-#include <stdio.h>
13
-#include <stdlib.h>
14
-#include <stdint.h>
15
-#include <pthread.h>
16
-#include <errno.h>
17
-#include <stdexcept>
18
-#include <type_traits>
19
-#include <utility>
20
-#include "portability.h"
21
-
22
-namespace HPHP {
23
-
24
-// return the location of the current thread's tdata section
25
-std::pair<void*,size_t> getCppTdata();
26
-
27
-inline uintptr_t tlsBase() {
28
- uintptr_t retval;
29
-#if defined(__x86_64__)
30
- asm ("movq %%fs:0, %0" : "=r" (retval));
31
-#elif defined(__AARCH64EL__)
32
- // mrs == "move register <-- system"
33
- // tpidr_el0 == "thread process id register for exception level 0"
34
- asm ("mrs %0, tpidr_el0" : "=r" (retval));
35
-#elif defined (__powerpc64__)
36
- asm ("xor %0,%0,%0\n\t"
37
- "or %0,%0,13\n\t"
38
- : "=r" (retval));
39
-#elif defined(_M_X64)
40
- retval = (uintptr_t)_readfsbase_u64();
41
- retval = *(uintptr_t*)(retval + 88);
42
-#else
43
-# error How do you access thread-local storage on this machine?
44
-#endif
45
- return retval;
46
-}
47
-
48
-///////////////////////////////////////////////////////////////////////////////
49
-// gcc >= 4.3.0 supports the '__thread' keyword for thread locals
50
-//
51
-// Clang seems to have added this feature, or at the very least it is ignoring
52
-// __thread keyword and compiling anyway
53
-//
54
-// On OSX, gcc does emulate TLS but in a manner that invalidates assumptions
55
-// we have made about __thread and makes accessing thread-local variables in a
56
-// JIT-friendly fashion difficult (as the compiler is doing a lot of magic that
57
-// is not contractual or documented that we would need to duplicate in emitted
58
-// code) so for now we're not going to use it. One possibility if we really
59
-// want to do this is to generate functions that access variables of interest
60
-// in ThreadLocal* (all of them are NoCheck right now) and use the bytes of
61
-// gcc's compiled functions to find the values we would need to pass to
62
-// __emutls_get_address.
63
-//
64
-// icc 13.0.0 appears to support it as well but we end up with
65
-// assembler warnings of unknown importance about incorrect section
66
-// types
67
-//
68
-// __thread on cygwin and mingw uses pthreads emulation not native tls so
69
-// the emulation for thread local must be used as well
70
-//
71
-// So we use __thread on gcc, icc and clang, unless we are on OSX. On OSX, we
72
-// use our own emulation. Use the DECLARE_THREAD_LOCAL() and
73
-// IMPLEMENT_THREAD_LOCAL() macros to access either __thread or the emulation
74
-// as appropriate.
75
-
76
-#if !defined(NO_TLS) && \
77
- !defined(__CYGWIN__) && !defined(__MINGW__) && \
78
- ((__llvm__ && __clang__) || \
79
- __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || \
80
- __INTEL_COMPILER || defined(_MSC_VER))
81
-#define USE_GCC_FAST_TLS
82
-#endif
83
-
84
-///////////////////////////////////////////////////////////////////////////////
85
-// helper
86
-
87
-inline void ThreadLocalCheckReturn(int ret, const char *funcName) {
88
- if (ret != 0) {
89
- // This is used from global constructors so the safest thing to do is just
90
- // print to stderr and exit().
91
- fprintf(stderr, "%s returned %d", funcName, ret);
92
- exit(1);
93
- }
94
-}
95
-
96
-inline void ThreadLocalCreateKey(pthread_key_t *key, void (*del)(void*)) {
97
- int ret = pthread_key_create(key, del);
98
- ThreadLocalCheckReturn(ret, "pthread_key_create");
99
-}
100
-
101
-inline void ThreadLocalSetValue(pthread_key_t key, const void* value) {
102
- int ret = pthread_setspecific(key, value);
103
- ThreadLocalCheckReturn(ret, "pthread_setspecific");
104
-}
105
-
106
-#ifdef __APPLE__
107
-typedef struct __darwin_pthread_handler_rec darwin_pthread_handler;
108
-#endif
109
-
110
-///////////////////////////////////////////////////////////////////////////////
111
-
112
-/**
113
- * A thread-local object is a "global" object within a thread. This is useful
114
- * for writing apartment-threaded code, where nothing is actually shared
115
- * between different threads (hence no locking) but those variables are not
116
- * on stack in local scope. To use it, just do something like this,
117
- *
118
- * IMPLEMENT_THREAD_LOCAL(MyClass, static_object);
119
- * static_object->data_ = ...;
120
- * static_object->doSomething();
121
- *
122
- * IMPLEMENT_THREAD_LOCAL(int, static_number);
123
- * int value = *static_number;
124
- *
125
- * So, syntax-wise it's similar to pointers. The type parameter can be a
126
- * primitive types. If it's a class, there has to be a default constructor.
127
- */
128
-
129
-///////////////////////////////////////////////////////////////////////////////
130
-#if defined(USE_GCC_FAST_TLS)
131
-
132
-/**
133
- * We keep a linked list of destructors in ThreadLocalManager to be called on
134
- * thread exit. ThreadLocalNode is a node in this list.
135
- */
136
-template <typename T>
137
-struct ThreadLocalNode {
138
- T * m_p;
139
- void (*m_on_thread_exit_fn)(void * p);
140
- void * m_next;
141
- size_t m_size;
142
-};
143
-
144
-struct ThreadLocalManager {
145
- template<class T>
146
- static void PushTop(ThreadLocalNode<T>& node) {
147
- PushTop(&node, sizeof(T));
148
- }
149
- template<class F> void scan(F& mark) const;
150
-
151
-private:
152
- static void PushTop(void* node, size_t size);
153
- struct ThreadLocalList {
154
- void* head{nullptr};
155
-#ifdef __APPLE__
156
- ThreadLocalList();
157
- darwin_pthread_handler handler;
158
-#endif
159
- };
160
- static ThreadLocalList* getList(void* p) {
161
- return static_cast<ThreadLocalList*>(p);
162
- }
163
- ThreadLocalManager() : m_key(0) {
164
-#ifdef __APPLE__
165
- ThreadLocalCreateKey(&m_key, nullptr);
166
-#else
167
- ThreadLocalCreateKey(&m_key, ThreadLocalManager::OnThreadExit);
168
-#endif
169
- };
170
- static void OnThreadExit(void *p);
171
- pthread_key_t m_key;
172
-
173
- static ThreadLocalManager& GetManager();
174
-};
175
-
176
-///////////////////////////////////////////////////////////////////////////////
177
-// ThreadLocal allocates by calling new without parameters and frees by calling
178
-// delete
179
-
180
-template<typename T>
181
-void ThreadLocalOnThreadExit(void * p) {
182
- ThreadLocalNode<T> * pNode = (ThreadLocalNode<T>*)p;
183
- delete pNode->m_p;
184
- pNode->m_p = nullptr;
185
-}
186
-
187
-/**
188
- * The USE_GCC_FAST_TLS implementation of ThreadLocal is just a lazy-initialized
189
- * pointer wrapper. In this case, we have one ThreadLocal object per thread.
190
- */
191
-template<typename T>
192
-struct ThreadLocal {
193
- T *get() const {
194
- if (m_node.m_p == nullptr) {
195
- const_cast<ThreadLocal<T>*>(this)->create();
196
- }
197
- return m_node.m_p;
198
- }
199
-
200
- NEVER_INLINE void create();
201
-
202
- bool isNull() const { return m_node.m_p == nullptr; }
203
-
204
- void destroy() {
205
- delete m_node.m_p;
206
- m_node.m_p = nullptr;
207
- }
208
-
209
- void nullOut() {
210
- m_node.m_p = nullptr;
211
- }
212
-
213
- T *operator->() const {
214
- return get();
215
- }
216
-
217
- T &operator*() const {
218
- return *get();
219
- }
220
-
221
- ThreadLocalNode<T> m_node;
222
-};
223
-
224
-template<typename T>
225
-void ThreadLocal<T>::create() {
226
- if (m_node.m_on_thread_exit_fn == nullptr) {
227
- m_node.m_on_thread_exit_fn = ThreadLocalOnThreadExit<T>;
228
- ThreadLocalManager::PushTop(m_node);
229
- }
230
- assert(m_node.m_p == nullptr);
231
- m_node.m_p = new T();
232
-}
233
-
234
-/**
235
- * ThreadLocalNoCheck is a pointer wrapper like ThreadLocal, except that it is
236
- * explicitly initialized with getCheck(), rather than being initialized when
237
- * it is first dereferenced.
238
- */
239
-template<typename T>
240
-struct ThreadLocalNoCheck {
241
- NEVER_INLINE T *getCheck() const;
242
- T* getNoCheck() const {
243
- assert(m_node.m_p);
244
- return m_node.m_p;
245
- }
246
-
247
- NEVER_INLINE void create();
248
-
249
- bool isNull() const { return m_node.m_p == nullptr; }
250
-
251
- void destroy() {
252
- delete m_node.m_p;
253
- m_node.m_p = nullptr;
254
- }
255
-
256
- T *operator->() const {
257
- return getNoCheck();
258
- }
259
-
260
- T &operator*() const {
261
- return *getNoCheck();
262
- }
263
-
264
- ThreadLocalNode<T> m_node;
265
-private:
266
- void setNull() { m_node.m_p = nullptr; }
267
-};
268
-
269
-template<typename T>
270
-void ThreadLocalNoCheck<T>::create() {
271
- if (m_node.m_on_thread_exit_fn == nullptr) {
272
- m_node.m_on_thread_exit_fn = ThreadLocalOnThreadExit<T>;
273
- ThreadLocalManager::PushTop(m_node);
274
- }
275
- assert(m_node.m_p == nullptr);
276
- m_node.m_p = new T();
277
-}
278
-template<typename T>
279
-T *ThreadLocalNoCheck<T>::getCheck() const {
280
- if (m_node.m_p == nullptr) {
281
- const_cast<ThreadLocalNoCheck<T>*>(this)->create();
282
- }
283
- return m_node.m_p;
284
-}
285
-
286
-
287
-///////////////////////////////////////////////////////////////////////////////
288
-// Singleton thread-local storage for T
289
-
290
-template<typename T>
291
-void ThreadLocalSingletonOnThreadExit(void *obj) {
292
- T::OnThreadExit((T*)obj);
293
-}
294
-
295
-// ThreadLocalSingleton has NoCheck property
296
-template <typename T>
297
-class ThreadLocalSingleton {
298
-public:
299
- ThreadLocalSingleton() { s_inited = true; }
300
-
301
- NEVER_INLINE static T *getCheck();
302
-
303
- static T* getNoCheck() {
304
- assert(s_inited);
305
- assert(s_singleton == (T*)&s_storage);
306
- return (T*)&s_storage;
307
- }
308
-
309
- static bool isNull() { return s_singleton == nullptr; }
310
-
311
- static void destroy() {
312
- assert(!s_singleton || s_singleton == (T*)&s_storage);
313
- T* p = s_singleton;
314
- if (p) {
315
- T::Delete(p);
316
- s_singleton = nullptr;
317
- }
318
- }
319
-
320
- T *operator->() const {
321
- return getNoCheck();
322
- }
323
-
324
- T &operator*() const {
325
- return *getNoCheck();
326
- }
327
-
328
-private:
329
- static __thread T *s_singleton;
330
- typedef typename std::aligned_storage<sizeof(T), sizeof(void*)>::type
331
- StorageType;
332
- static __thread StorageType s_storage;
333
- static bool s_inited; // no-fast-TLS requires construction so be consistent
334
-};
335
-
336
-template<typename T>
337
-bool ThreadLocalSingleton<T>::s_inited = false;
338
-
339
-template<typename T>
340
-T *ThreadLocalSingleton<T>::getCheck() {
341
- assert(s_inited);
342
- if (!s_singleton) {
343
- T* p = (T*) &s_storage;
344
- T::Create(p);
345
- s_singleton = p;
346
- }
347
- return s_singleton;
348
-}
349
-
350
-template<typename T> __thread T *ThreadLocalSingleton<T>::s_singleton;
351
-template<typename T> __thread typename ThreadLocalSingleton<T>::StorageType
352
- ThreadLocalSingleton<T>::s_storage;
353
-
354
-
355
-///////////////////////////////////////////////////////////////////////////////
356
-// some classes don't need new/delete at all
357
-
358
-template<typename T, bool throwOnNull = true>
359
-struct ThreadLocalProxy {
360
- T *get() const {
361
- if (m_p == nullptr && throwOnNull) {
362
- throw std::runtime_error("ThreadLocalProxy::get() called before set()");
363
- }
364
- return m_p;
365
- }
366
-
367
- void set(T* obj) {
368
- m_p = obj;
369
- }
370
-
371
- bool isNull() const { return m_p == nullptr; }
372
-
373
- void destroy() {
374
- m_p = nullptr;
375
- }
376
-
377
- T *operator->() const {
378
- return get();
379
- }
380
-
381
- T &operator*() const {
382
- return *get();
383
- }
384
-
385
- T * m_p;
386
-};
387
-
388
-/*
389
- * How to use the thread-local macros:
390
- *
391
- * Use DECLARE_THREAD_LOCAL to declare a *static* class field as thread local:
392
- * class SomeClass {
393
- * static DECLARE_THREAD_LOCAL(SomeFieldType, f);
394
- * }
395
- *
396
- * Use IMPLEMENT_THREAD_LOCAL in the cpp file to implement the field:
397
- * IMPLEMENT_THREAD_LOCAL(SomeFieldType, SomeClass::f);
398
- *
399
- * Remember: *Never* write IMPLEMENT_THREAD_LOCAL in a header file.
400
- */
401
-
402
-#define DECLARE_THREAD_LOCAL(T, f) \
403
- __thread HPHP::ThreadLocal<T> f
404
-#define IMPLEMENT_THREAD_LOCAL(T, f) \
405
- __thread HPHP::ThreadLocal<T> f
406
-
407
-#define DECLARE_THREAD_LOCAL_NO_CHECK(T, f) \
408
- __thread HPHP::ThreadLocalNoCheck<T> f
409
-#define IMPLEMENT_THREAD_LOCAL_NO_CHECK(T, f) \
410
- __thread HPHP::ThreadLocalNoCheck<T> f
411
-
412
-#define DECLARE_THREAD_LOCAL_PROXY(T, N, f) \
413
- __thread HPHP::ThreadLocalProxy<T, N> f
414
-#define IMPLEMENT_THREAD_LOCAL_PROXY(T, N, f) \
415
- __thread HPHP::ThreadLocalProxy<T, N> f
416
-
417
-#else /* USE_GCC_FAST_TLS */
418
-
419
-///////////////////////////////////////////////////////////////////////////////
420
-// ThreadLocal allocates by calling new() without parameters
421
-
422
-template<typename T>
423
-void ThreadLocalOnThreadExit(void *p) {
424
- delete (T*)p;
425
-}
426
-
427
-#ifdef __APPLE__
428
-// The __thread variables in class T will be freed when pthread calls
429
-// the destructor function on Mac. We can register a handler in
430
-// pthread_t->__cleanup_stack similar to pthread_cleanup_push(). The handler
431
-// will be called earlier so the __thread variables will still exist in the
432
-// handler when the thread exits.
433
-//
434
-// See the details at:
435
-// https://github.com/facebook/hhvm/issues/4444#issuecomment-92497582
436
-typedef struct __darwin_pthread_handler_rec darwin_pthread_handler;
437
-
438
-template<typename T>
439
-void ThreadLocalOnThreadCleanup(void *key) {
440
- void *obj = pthread_getspecific((pthread_key_t)key);
441
- if (obj) {
442
- ThreadLocalOnThreadExit<T>(obj);
443
- }
444
-}
445
-
446
-inline void ThreadLocalSetCleanupHandler(pthread_key_t cleanup_key,
447
- pthread_key_t key,
448
- void (*del)(void*)) {
449
- // Prevent from adding the handler for multiple times.
450
- darwin_pthread_handler *handler =
451
- (darwin_pthread_handler*)pthread_getspecific(cleanup_key);
452
- if (handler)
453
- return;
454
-
455
- pthread_t self = pthread_self();
456
-
457
- handler = new darwin_pthread_handler();
458
- handler->__routine = del;
459
- handler->__arg = (void*)key;
460
- handler->__next = self->__cleanup_stack;
461
- self->__cleanup_stack = handler;
462
-
463
- ThreadLocalSetValue(cleanup_key, handler);
464
-}
465
-#endif
466
-
467
-/**
468
- * This is the emulation version of ThreadLocal. In this case, the ThreadLocal
469
- * object is a true global, and the get() method returns a thread-dependent
470
- * pointer from pthread's thread-specific data management.
471
- */
472
-template<typename T>
473
-class ThreadLocal {
474
-public:
475
- /**
476
- * Constructor that has to be called from a thread-neutral place.
477
- */
478
- ThreadLocal() : m_key(0) {
479
-#ifdef __APPLE__
480
- ThreadLocalCreateKey(&m_key, nullptr);
481
- ThreadLocalCreateKey(&m_cleanup_key,
482
- ThreadLocalOnThreadExit<darwin_pthread_handler>);
483
-#else
484
- ThreadLocalCreateKey(&m_key, ThreadLocalOnThreadExit<T>);
485
-#endif
486
- }
487
-
488
- T *get() const {
489
- T *obj = (T*)pthread_getspecific(m_key);
490
- if (obj == nullptr) {
491
- obj = new T();
492
- ThreadLocalSetValue(m_key, obj);
493
-#ifdef __APPLE__
494
- ThreadLocalSetCleanupHandler(m_cleanup_key, m_key,
495
- ThreadLocalOnThreadCleanup<T>);
496
-#endif
497
- }
498
- return obj;
499
- }
500
-
501
- bool isNull() const { return pthread_getspecific(m_key) == nullptr; }
502
-
503
- void destroy() {
504
- delete (T*)pthread_getspecific(m_key);
505
- ThreadLocalSetValue(m_key, nullptr);
506
- }
507
-
508
- void nullOut() {
509
- ThreadLocalSetValue(m_key, nullptr);
510
- }
511
-
512
- /**
513
- * Access object's member or method through this operator overload.
514
- */
515
- T *operator->() const {
516
- return get();
517
- }
518
-
519
- T &operator*() const {
520
- return *get();
521
- }
522
-
523
-private:
524
- pthread_key_t m_key;
525
-
526
-#ifdef __APPLE__
527
- pthread_key_t m_cleanup_key;
528
-#endif
529
-};
530
-
531
-template<typename T>
532
-class ThreadLocalNoCheck {
533
-public:
534
- /**
535
- * Constructor that has to be called from a thread-neutral place.
536
- */
537
- ThreadLocalNoCheck() : m_key(0) {
538
-#ifdef __APPLE__
539
- ThreadLocalCreateKey(&m_key, nullptr);
540
- ThreadLocalCreateKey(&m_cleanup_key,
541
- ThreadLocalOnThreadExit<darwin_pthread_handler>);
542
-#else
543
- ThreadLocalCreateKey(&m_key, ThreadLocalOnThreadExit<T>);
544
-#endif
545
- }
546
-
547
- NEVER_INLINE T *getCheck() const;
548
-
549
- T* getNoCheck() const {
550
- T *obj = (T*)pthread_getspecific(m_key);
551
- assert(obj);
552
- return obj;
553
- }
554
-
555
- bool isNull() const { return pthread_getspecific(m_key) == nullptr; }
556
-
557
- void destroy() {
558
- delete (T*)pthread_getspecific(m_key);
559
- ThreadLocalSetValue(m_key, nullptr);
560
- }
561
-
562
- /**
563
- * Access object's member or method through this operator overload.
564
- */
565
- T *operator->() const {
566
- return getNoCheck();
567
- }
568
-
569
- T &operator*() const {
570
- return *getNoCheck();
571
- }
572
-
573
-public:
574
- void setNull() { ThreadLocalSetValue(m_key, nullptr); }
575
- pthread_key_t m_key;
576
-
577
-#ifdef __APPLE__
578
- pthread_key_t m_cleanup_key;
579
-#endif
580
-};
581
-
582
-template<typename T>
583
-T *ThreadLocalNoCheck<T>::getCheck() const {
584
- T *obj = (T*)pthread_getspecific(m_key);
585
- if (obj == nullptr) {
586
- obj = new T();
587
- ThreadLocalSetValue(m_key, obj);
588
-#ifdef __APPLE__
589
- ThreadLocalSetCleanupHandler(m_cleanup_key, m_key,
590
- ThreadLocalOnThreadCleanup<T>);
591
-#endif
592
- }
593
- return obj;
594
-}
595
-
596
-///////////////////////////////////////////////////////////////////////////////
597
-// Singleton thread-local storage for T
598
-
599
-template<typename T>
600
-void ThreadLocalSingletonOnThreadExit(void *obj) {
601
- T::OnThreadExit((T*)obj);
602
- free(obj);
603
-}
604
-
605
-#ifdef __APPLE__
606
-template<typename T>
607
-void ThreadLocalSingletonOnThreadCleanup(void *key) {
608
- void *obj = pthread_getspecific((pthread_key_t)key);
609
- if (obj) {
610
- ThreadLocalSingletonOnThreadExit<T>(obj);
611
- }
612
-}
613
-#endif
614
-
615
-// ThreadLocalSingleton has NoCheck property
616
-template<typename T>
617
-class ThreadLocalSingleton {
618
-public:
619
- ThreadLocalSingleton() { getKey(); }
620
-
621
- NEVER_INLINE static T *getCheck();
622
- static T* getNoCheck() {
623
- assert(s_inited);
624
- T *obj = (T*)pthread_getspecific(s_key);
625
- assert(obj);
626
- return obj;
627
- }
628
-
629
- static bool isNull() {
630
- return !s_inited || pthread_getspecific(s_key) == nullptr;
631
- }
632
-
633
- static void destroy() {
634
- void* p = pthread_getspecific(s_key);
635
- T::Delete((T*)p);
636
- free(p);
637
- ThreadLocalSetValue(s_key, nullptr);
638
- }
639
-
640
- T *operator->() const {
641
- return getNoCheck();
642
- }
643
-
644
- T &operator*() const {
645
- return *getNoCheck();
646
- }
647
-
648
-private:
649
- static pthread_key_t s_key;
650
- static bool s_inited; // pthread_key_t has no portable valid sentinel
651
-
652
-#ifdef __APPLE__
653
- static pthread_key_t s_cleanup_key;
654
-#endif
655
-
656
- static pthread_key_t getKey() {
657
- if (!s_inited) {
658
- s_inited = true;
659
-#ifdef __APPLE__
660
- ThreadLocalCreateKey(&s_key, nullptr);
661
- ThreadLocalCreateKey(&s_cleanup_key,
662
- ThreadLocalOnThreadExit<darwin_pthread_handler>);
663
-#else
664
- ThreadLocalCreateKey(&s_key, ThreadLocalSingletonOnThreadExit<T>);
665
-#endif
666
- }
667
- return s_key;
668
- }
669
-};
670
-
671
-template<typename T>
672
-T *ThreadLocalSingleton<T>::getCheck() {
673
- assert(s_inited);
674
- T *obj = (T*)pthread_getspecific(s_key);
675
- if (obj == nullptr) {
676
- obj = (T*)malloc(sizeof(T));
677
- T::Create(obj);
678
- ThreadLocalSetValue(s_key, obj);
679
-#ifdef __APPLE__
680
- ThreadLocalSetCleanupHandler(s_cleanup_key, s_key,
681
- ThreadLocalSingletonOnThreadCleanup<T>);
682
-#endif
683
- }
684
- return obj;
685
-}
686
-
687
-template<typename T>
688
-pthread_key_t ThreadLocalSingleton<T>::s_key;
689
-template<typename T>
690
-bool ThreadLocalSingleton<T>::s_inited = false;
691
-
692
-#ifdef __APPLE__
693
-template<typename T>
694
-pthread_key_t ThreadLocalSingleton<T>::s_cleanup_key;
695
-#endif
696
-
697
-///////////////////////////////////////////////////////////////////////////////
698
-// some classes don't need new/delete at all
699
-
700
-template<typename T, bool throwOnNull = true>
701
-class ThreadLocalProxy {
702
-public:
703
- /**
704
- * Constructor that has to be called from a thread-neutral place.
705
- */
706
- ThreadLocalProxy() : m_key(0) {
707
- ThreadLocalCreateKey(&m_key, nullptr);
708
- }
709
-
710
- T *get() const {
711
- T *obj = (T*)pthread_getspecific(m_key);
712
- if (obj == nullptr && throwOnNull) {
713
- throw std::runtime_error("ThreadLocalProxy::get() called before set()");
714
- }
715
- return obj;
716
- }
717
-
718
- void set(T* obj) {
719
- ThreadLocalSetValue(m_key, obj);
720
- }
721
-
722
- bool isNull() const { return pthread_getspecific(m_key) == nullptr; }
723
-
724
- void destroy() {
725
- ThreadLocalSetValue(m_key, nullptr);
726
- }
727
-
728
- /**
729
- * Access object's member or method through this operator overload.
730
- */
731
- T *operator->() const {
732
- return get();
733
- }
734
-
735
- T &operator*() const {
736
- return *get();
737
- }
738
-
739
-public:
740
- pthread_key_t m_key;
741
-};
742
-
743
-/**
744
- * The emulation version of the thread-local macros
745
- */
746
-#define DECLARE_THREAD_LOCAL(T, f) HPHP::ThreadLocal<T> f
747
-#define IMPLEMENT_THREAD_LOCAL(T, f) HPHP::ThreadLocal<T> f
748
-
749
-#define DECLARE_THREAD_LOCAL_NO_CHECK(T, f) HPHP::ThreadLocalNoCheck<T> f
750
-#define IMPLEMENT_THREAD_LOCAL_NO_CHECK(T, f) HPHP::ThreadLocalNoCheck<T> f
751
-
752
-#define DECLARE_THREAD_LOCAL_PROXY(T, N, f) HPHP::ThreadLocalProxy<T, N> f
753
-#define IMPLEMENT_THREAD_LOCAL_PROXY(T, N, f) HPHP::ThreadLocalProxy<T, N> f
754
-
755
-#endif /* USE_GCC_FAST_TLS */
756
-
757
-///////////////////////////////////////////////////////////////////////////////
758
-}
759
-
760
-#endif // incl_HPHP_THREAD_LOCAL_H_