2 +----------------------------------------------------------------------+
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"
24 #include <folly/Bits.h>
25 #include <folly/portability/PThread.h>
26 #include <folly/portability/Unistd.h>
28 #include "hphp/util/assertions.h"
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
) {
42 # define RBTYPE(n) case RBType##n: return #n;
50 void vtraceRingbuffer(const char* fmt
, va_list ap
) {
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';
66 int leftInCurPiece
= kMaxRBBytes
- tl_rbPtr
;
67 int toWrite
= std::min(msgBytes
, leftInCurPiece
);
68 memcpy(&tl_ring_ptr
[tl_rbPtr
], bufP
, toWrite
);
71 tl_rbPtr
= (tl_rbPtr
+ toWrite
) % kMaxRBBytes
;
73 ringbufferMsg(start
, totalLen
);
77 // (gdb) call HPHP::Trace::dumpRingBuffer()
78 void dumpRingbuffer() {
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
));
92 int newRingPos
, oldRingPos
;
93 if (UNLIKELY(!g_ring_ptr
)) {
94 static pthread_mutex_t mtx
= PTHREAD_MUTEX_INITIALIZER
;
95 pthread_mutex_lock(&mtx
);
97 g_ring_ptr
= (RingBufferEntry
*)calloc(sizeof(RingBufferEntry
),
100 pthread_mutex_unlock(&mtx
);
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
);
110 rb
->threadId
= (uint32_t)((int64_t)pthread_self() & 0xFFFFFFFF);
115 ringbufferMsg(const char* msg
, size_t msgLen
, RingBufferType t
) {
116 auto& info
= allocEntry(t
)->msg
;
119 info
.truncatedRip
= static_cast<uint32_t>(
120 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
124 ringbufferEntry(RingBufferType t
, uint64_t sk
, uint64_t data
) {
125 auto& info
= allocEntry(t
)->vmPoint
;
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 ringbufferAPCEnqueue(void* handle
, void* value
) {
137 auto& info
= allocEntry(RBTypeAPCHandleEnqueue
)->apcHandleInfo
;
138 info
.handle
= handle
;
142 void ringbufferAPCDelete(void* handle
, void* value
) {
143 auto& info
= allocEntry(RBTypeAPCHandleDelete
)->apcHandleInfo
;
144 info
.handle
= handle
;
148 void ringbufferGeneric(const char* name
, uint64_t data
) {
149 auto& info
= allocEntry(RBTypeGeneric
)->generic
;
154 void ringbufferGeneric(const char* name
, const void* data
) {
155 ringbufferGeneric(name
, reinterpret_cast<uint64_t>(data
));