Move serialize functions to variable-serializer.cpp
[hiphop-php.git] / hphp / util / ringbuffer.cpp
blobc95c0f2c3699bfb7d06f1aee3721f9a488d4f731
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 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>
23 #include <unistd.h>
25 #include <folly/Bits.h>
27 #include "hphp/util/assertions.h"
29 namespace HPHP {
30 namespace Trace {
33 * Thread-private ascii ringbuffer.
35 static const int kMaxRBBytes = 1 << 19; // 512KB
36 __thread int tl_rbPtr;
37 __thread char* tl_ring_ptr;
39 const char* ringbufferName(RingBufferType t) {
40 switch (t) {
41 # define RBTYPE(n) case RBType##n: return #n;
42 RBTYPES
43 # undef RBTYPE
45 not_reached();
48 KEEP_SECTION
49 void vtraceRingbuffer(const char* fmt, va_list ap) {
50 char buf[4096];
51 char* bufP = &buf[0];
52 // Silently truncate long inputs.
53 int msgBytes = std::min(int(sizeof(buf)) - 1,
54 vsnprintf(buf, sizeof(buf) - 1, fmt, ap));
55 if (UNLIKELY(!tl_ring_ptr)) {
56 tl_ring_ptr = (char*)calloc(kMaxRBBytes, 1);
58 // Remember these for the binary ringbuffer.
59 char* start = &tl_ring_ptr[tl_rbPtr];
60 int totalLen = msgBytes;
61 // Include the nulls; we will sometimes include these strings
62 // by reference from the global ringbuffer.
63 buf[msgBytes++] = '\0';
64 while(msgBytes) {
65 int leftInCurPiece = kMaxRBBytes - tl_rbPtr;
66 int toWrite = std::min(msgBytes, leftInCurPiece);
67 memcpy(&tl_ring_ptr[tl_rbPtr], bufP, toWrite);
68 msgBytes -= toWrite;
69 bufP += toWrite;
70 tl_rbPtr = (tl_rbPtr + toWrite) % kMaxRBBytes;
72 ringbufferMsg(start, totalLen);
75 // From GDB:
76 // (gdb) call HPHP::Trace::dumpRingBuffer()
77 void dumpRingbuffer() {
78 if (tl_ring_ptr) {
79 write(1, tl_ring_ptr + tl_rbPtr, kMaxRBBytes - tl_rbPtr);
80 write(1, tl_ring_ptr, tl_rbPtr);
84 RingBufferEntry* g_ring_ptr;
85 std::atomic<int> g_ringIdx(0);
86 std::atomic<uint32_t> g_seqnum(0);
88 RingBufferEntry*
89 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->m_seq = g_seqnum.fetch_add(1, std::memory_order_relaxed);
109 rb->m_type = t;
110 rb->m_threadId = (uint32_t)((int64_t)pthread_self() & 0xFFFFFFFF);
111 return rb;
114 static inline RingBufferEntry*
115 initEntry(RingBufferType t) {
116 RingBufferEntry* rb = allocEntry(t);
117 return rb;
120 static inline RingBufferEntry*
121 initEntry(RingBufferType t, uint64_t sk, uint64_t data) {
122 RingBufferEntry* rb = allocEntry(t);
123 rb->m_sk = sk;
124 rb->m_data = data;
125 return rb;
128 void
129 ringbufferMsg(const char* msg, size_t msgLen, RingBufferType t) {
130 RingBufferEntry* rb = initEntry(t);
131 rb->m_msg = msg;
132 rb->m_len = msgLen;
133 rb->m_truncatedRip = static_cast<uint32_t>(
134 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
137 void
138 ringbufferEntry(RingBufferType t, uint64_t sk, uint64_t data) {
139 initEntry(t, sk, data);
142 void
143 ringbufferEntryRip(RingBufferType t, uint64_t sk) {
144 auto rip = reinterpret_cast<uint64_t>(__builtin_return_address(0));
145 ringbufferEntry(t, sk, rip);