@samitouri / QOS-React-1 / commits / c0b7c0d31f

[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_