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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/vm/ringbuffer-print.h"
20 #include <folly/Format.h>
22 #include "hphp/runtime/vm/jit/service-requests.h"
23 #include "hphp/runtime/vm/srckey.h"
25 namespace HPHP
{ namespace Trace
{
27 void dumpEntry(const RingBufferEntry
* e
) {
28 if (e
->type
== RBTypeUninit
) return;
31 folly::format("{:#x} {:10} {:20}",
32 e
->threadId
, e
->seq
, ringbufferName(e
->type
));
33 auto const msgFormat
= "{:50} {:#16x}\n";
36 case RBTypeUninit
: return;
38 case RBTypeFuncPrologue
: {
40 // The strings in thread-private ring buffers are not null-terminated;
41 // we also can't trust their length, since they might wrap around.
42 auto len
= std::min(size_t(info
.len
), strlen(info
.msg
));
44 // We append our own newline so ignore any newlines in the msg.
45 while (len
> 0 && info
.msg
[len
- 1] == '\n') --len
;
47 folly::format(msgFormat
,
48 folly::StringPiece(info
.msg
, info
.msg
+ len
),
53 case RBTypeFuncExit
: {
54 static __thread
int indentDepth
= 0;
55 // Quick and dirty attempt at dtrace -F style function nesting.
58 // ... FuncEntry caller
59 // ... FuncEntry callee
60 // ... FuncExit callee
61 // ... FuncExit caller
63 // Take this indentation with a grain of salt; it's only reliable
64 // within a single thread, and since we still miss some function
65 // entries and exits can get confused.
67 indentDepth
-= e
->type
== RBTypeFuncExit
;
68 if (indentDepth
< 0) indentDepth
= 0;
69 auto const indentedName
=
70 folly::sformat("{}{}", std::string(indentDepth
* 4, ' '), info
.msg
);
71 std::cerr
<< folly::format(msgFormat
,
72 indentedName
, info
.truncatedRip
);
73 indentDepth
+= e
->type
== RBTypeFuncEntry
;
76 case RBTypeServiceReq
: {
77 auto& info
= e
->vmPoint
;
78 auto req
= static_cast<jit::ServiceRequest
>(info
.sk
);
79 std::cerr
<< folly::format(msgFormat
,
80 jit::svcreq::to_name(req
), info
.data
);
84 auto& info
= e
->generic
;
85 std::cerr
<< folly::format(msgFormat
, info
.name
, info
.data
);
88 case RBTypeAPCHandleEnqueue
:
90 auto& info
= e
->apcHandleInfo
;
91 std::cerr
<< " (" << info
.handle
<< ", " << info
.value
<< ")\n";
94 case RBTypeAPCHandleDelete
:
96 auto& info
= e
->apcHandleInfo
;
97 std::cerr
<< " (" << info
.handle
<< ", " << info
.value
<< ")\n";
101 auto& info
= e
->vmPoint
;
103 folly::format(msgFormat
,
104 showShort(SrcKey::fromAtomicInt(info
.sk
)),
112 // (gdb) set language c++
113 // (gdb) call HPHP::Trace::dumpRingBuffer(100)
117 // (gdb) call HPHP::Trace::dumpRingBufferMasked(100,
118 // (1 << HPHP::Trace::RBTypeFuncEntry))
119 void dumpRingBufferMasked(int numEntries
, uint32_t types
, uint32_t threadId
) {
120 if (!g_ring_ptr
) return;
121 int startIdx
= (g_ringIdx
.load() - numEntries
) % kMaxRBEntries
;
122 while (startIdx
< 0) {
123 startIdx
+= kMaxRBEntries
;
125 assertx(startIdx
>= 0 && startIdx
< kMaxRBEntries
);
127 for (int i
= 0; i
< kMaxRBEntries
&& numDumped
< numEntries
; i
++) {
128 RingBufferEntry
* rb
= &g_ring_ptr
[(startIdx
+ i
) % kMaxRBEntries
];
129 if ((1 << rb
->type
) & types
&&
130 (!threadId
|| threadId
== rb
->threadId
)) {
138 void dumpRingBuffer(int numEntries
, uint32_t threadId
) {
139 dumpRingBufferMasked(numEntries
, -1u, threadId
);