use new hugify method only in fb builds
[hiphop-php.git] / hphp / util / ringbuffer.cpp
blob136ccd5340f2ef22568392fc7fe1cc9a9f88513a
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/ringbuffer.h"
19 #include <algorithm>
20 #include <atomic>
21 #include <cstdio>
22 #include <cstring>
24 #include <folly/Bits.h>
25 #include <folly/portability/PThread.h>
26 #include <folly/portability/Unistd.h>
28 #include "hphp/util/assertions.h"
30 namespace HPHP {
31 namespace Trace {
34 * Thread-private ascii ringbuffer.
36 static const int kMaxRBBytes = 1 << 19; // 512KB
37 __thread int tl_rbPtr;
38 __thread char* tl_ring_ptr;
40 const char* ringbufferName(RingBufferType t) {
41 switch (t) {
42 # define RBTYPE(n) case RBType##n: return #n;
43 RBTYPES
44 # undef RBTYPE
46 not_reached();
49 KEEP_SECTION
50 void vtraceRingbuffer(const char* fmt, va_list ap) {
51 char buf[4096];
52 char* bufP = &buf[0];
53 // Silently truncate long inputs.
54 int msgBytes = std::min(int(sizeof(buf)) - 1,
55 vsnprintf(buf, sizeof(buf) - 1, fmt, ap));
56 if (UNLIKELY(!tl_ring_ptr)) {
57 tl_ring_ptr = (char*)calloc(kMaxRBBytes, 1);
59 // Remember these for the binary ringbuffer.
60 char* start = &tl_ring_ptr[tl_rbPtr];
61 int totalLen = msgBytes;
62 // Include the nulls; we will sometimes include these strings
63 // by reference from the global ringbuffer.
64 buf[msgBytes++] = '\0';
65 while(msgBytes) {
66 int leftInCurPiece = kMaxRBBytes - tl_rbPtr;
67 int toWrite = std::min(msgBytes, leftInCurPiece);
68 memcpy(&tl_ring_ptr[tl_rbPtr], bufP, toWrite);
69 msgBytes -= toWrite;
70 bufP += toWrite;
71 tl_rbPtr = (tl_rbPtr + toWrite) % kMaxRBBytes;
73 ringbufferMsg(start, totalLen);
76 // From GDB:
77 // (gdb) call HPHP::Trace::dumpRingBuffer()
78 void dumpRingbuffer() {
79 if (tl_ring_ptr) {
80 write(1, tl_ring_ptr + tl_rbPtr, kMaxRBBytes - tl_rbPtr);
81 write(1, tl_ring_ptr, tl_rbPtr);
85 RingBufferEntry* g_ring_ptr;
86 std::atomic<int> g_ringIdx(0);
87 std::atomic<uint32_t> g_seqnum(0);
89 RingBufferEntry* allocEntry(RingBufferType t) {
90 assert(folly::isPowTwo(kMaxRBEntries));
91 RingBufferEntry* rb;
92 int newRingPos, oldRingPos;
93 if (UNLIKELY(!g_ring_ptr)) {
94 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
95 pthread_mutex_lock(&mtx);
96 if (!g_ring_ptr) {
97 g_ring_ptr = (RingBufferEntry*)calloc(sizeof(RingBufferEntry),
98 kMaxRBEntries);
100 pthread_mutex_unlock(&mtx);
102 do {
103 oldRingPos = g_ringIdx.load(std::memory_order_acquire);
104 rb = &g_ring_ptr[oldRingPos];
105 newRingPos = (oldRingPos + 1) % kMaxRBEntries;
106 } while (!g_ringIdx.compare_exchange_weak(oldRingPos, newRingPos,
107 std::memory_order_acq_rel));
108 rb->seq = g_seqnum.fetch_add(1, std::memory_order_relaxed);
109 rb->type = t;
110 rb->threadId = (uint32_t)((int64_t)pthread_self() & 0xFFFFFFFF);
111 return rb;
114 void
115 ringbufferMsg(const char* msg, size_t msgLen, RingBufferType t) {
116 auto& info = allocEntry(t)->msg;
117 info.msg = msg;
118 info.len = msgLen;
119 info.truncatedRip = static_cast<uint32_t>(
120 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
123 void
124 ringbufferEntry(RingBufferType t, uint64_t sk, uint64_t data) {
125 auto& info = allocEntry(t)->vmPoint;
126 info.sk = sk;
127 info.data = data;
130 void
131 ringbufferEntryRip(RingBufferType t, uint64_t sk) {
132 auto rip = reinterpret_cast<uint64_t>(__builtin_return_address(0));
133 ringbufferEntry(t, sk, rip);
136 void ringbufferGeneric(const char* name, uint64_t data) {
137 auto& info = allocEntry(RBTypeGeneric)->generic;
138 info.name = name;
139 info.data = data;
142 void ringbufferGeneric(const char* name, const void* data) {
143 ringbufferGeneric(name, reinterpret_cast<uint64_t>(data));