2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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/runtime/base/apc-stats.h"
19 #include "hphp/runtime/base/typed-value.h"
20 #include "hphp/runtime/base/array-data.h"
21 #include "hphp/runtime/base/packed-array.h"
22 #include "hphp/runtime/base/packed-array-defs.h"
23 #include "hphp/runtime/base/mixed-array-defs.h"
24 #include "hphp/runtime/base/apc-handle.h"
25 #include "hphp/runtime/base/apc-array.h"
26 #include "hphp/runtime/base/apc-object.h"
27 #include "hphp/runtime/ext/apc/ext_apc.h"
29 #include "hphp/util/trace.h"
37 ///////////////////////////////////////////////////////////////////////////////
41 size_t getMemSize(const TypedValue
* tv
, bool recurse
= true) {
42 const auto& v
= tvAsCVarRef(tv
);
43 auto type
= v
.getType();
44 if (isArrayLikeType(type
)) {
45 if (!recurse
) return 0;
46 auto a
= v
.getArrayData();
47 return a
->isStatic() ? sizeof(v
) : getMemSize(a
);
49 if (type
== KindOfString
) {
50 return getMemSize(v
.getStringData());
52 if (!isRefcountedType(type
)) {
53 return sizeof(Variant
);
55 assert(!"Unsupported Variant type for getMemSize()");
61 size_t getMemSize(const APCHandle
* handle
) {
62 switch (handle
->kind()) {
68 case APCKind::StaticString
:
69 case APCKind::StaticArray
:
70 case APCKind::StaticVec
:
71 case APCKind::StaticDict
:
72 case APCKind::StaticKeyset
:
73 return sizeof(APCHandle
);
75 case APCKind::UncountedString
:
76 return sizeof(APCTypedValue
) +
77 getMemSize(APCTypedValue::fromHandle(handle
)->getStringData());
78 case APCKind::SharedString
:
79 return getMemSize(APCString::fromHandle(handle
));
81 case APCKind::SerializedArray
:
82 case APCKind::SerializedVec
:
83 case APCKind::SerializedDict
:
84 case APCKind::SerializedKeyset
:
85 return getMemSize(APCString::fromHandle(handle
));
87 case APCKind::UncountedArray
:
88 return sizeof(APCTypedValue
) +
89 getMemSize(APCTypedValue::fromHandle(handle
)->getArrayData());
90 case APCKind::UncountedVec
:
91 return sizeof(APCTypedValue
) +
92 getMemSize(APCTypedValue::fromHandle(handle
)->getVecData());
93 case APCKind::UncountedDict
:
94 return sizeof(APCTypedValue
) +
95 getMemSize(APCTypedValue::fromHandle(handle
)->getDictData());
96 case APCKind::UncountedKeyset
:
97 return sizeof(APCTypedValue
) +
98 getMemSize(APCTypedValue::fromHandle(handle
)->getKeysetData());
100 case APCKind::SharedArray
:
101 case APCKind::SharedPackedArray
:
102 case APCKind::SharedVec
:
103 case APCKind::SharedDict
:
104 case APCKind::SharedKeyset
:
105 case APCKind::SharedVArray
:
106 case APCKind::SharedDArray
:
107 return getMemSize(APCArray::fromHandle(handle
));
109 case APCKind::SerializedObject
:
110 return getMemSize(APCString::fromHandle(handle
));
112 case APCKind::SharedObject
:
113 case APCKind::SharedCollection
:
114 return getMemSize(APCObject::fromHandle(handle
));
116 assert(!"Unsupported APCHandle Type in getMemSize");
120 size_t getMemSize(const APCArray
* arr
) {
121 auto memSize
= sizeof(APCArray
);
122 auto size
= arr
->size();
123 if (arr
->isPacked()) {
124 memSize
+= sizeof(APCHandle
*) * size
;
125 for (auto i
= 0; i
< size
; i
++) {
126 memSize
+= getMemSize(arr
->getValue(i
));
129 memSize
+= sizeof(int) * (arr
->m
.m_capacity_mask
+ 1) +
130 sizeof(APCArray::Bucket
) * size
;
131 auto b
= arr
->buckets();
132 for (auto i
= 0; i
< size
; i
++) {
133 memSize
+= getMemSize(b
[i
].key
);
134 memSize
+= getMemSize(b
[i
].val
);
140 size_t getMemSize(const APCObject
* obj
) {
141 if (obj
->isPersistent()) {
142 auto size
= sizeof(APCObject
) +
143 sizeof(APCHandle
*) * obj
->m_propCount
;
144 auto prop
= obj
->persistentProps();
145 auto const propEnd
= prop
+ obj
->m_propCount
;
146 for (; prop
!= propEnd
; ++prop
) {
147 if (*prop
) size
+= getMemSize(*prop
);
152 auto size
= sizeof(APCObject
) +
153 sizeof(APCObject::Prop
) * obj
->m_propCount
;
154 auto prop
= obj
->props();
155 auto const propEnd
= prop
+ obj
->m_propCount
;
156 // we don't add property names and class names (or Class*) in Prop
157 // assuming that is static data not owned or accounted by the APCObject
158 for (; prop
!= propEnd
; ++prop
) {
159 if (prop
->val
) size
+= getMemSize(prop
->val
);
164 size_t getMemSize(const ArrayData
* arr
, bool recurse
) {
165 switch (arr
->kind()) {
166 case ArrayData::ArrayKind::kPackedKind
:
167 case ArrayData::ArrayKind::kVecKind
: {
168 // we want to measure just the overhead of the array
169 auto size
= PackedArray::heapSize(arr
) - (sizeof(TypedValue
) * arr
->m_size
);
170 auto const values
= packedData(arr
);
171 auto const last
= values
+ arr
->m_size
;
172 for (auto ptr
= values
; ptr
!= last
; ++ptr
) {
173 size
+= getMemSize(ptr
, recurse
);
177 case ArrayData::ArrayKind::kDictKind
:
178 case ArrayData::ArrayKind::kMixedKind
: {
179 auto const mixed
= MixedArray::asMixed(arr
);
180 auto size
= sizeof(MixedArray
) +
181 sizeof(MixedArray::Elm
) * (mixed
->capacity() - mixed
->m_used
);
182 auto elms
= mixed
->data();
183 auto last
= elms
+ mixed
->m_used
;
184 for (auto ptr
= elms
; ptr
!= last
; ++ptr
) {
185 if (MixedArray::isTombstone(ptr
->data
.m_type
)) {
186 size
+= sizeof(MixedArray::Elm
);
189 size
+= ptr
->hasStrKey() ? getMemSize(ptr
->skey
) : sizeof(int64_t);
190 size
+= getMemSize(&ptr
->data
, recurse
);
194 case ArrayData::ArrayKind::kKeysetKind
: {
195 auto const set
= SetArray::asSet(arr
);
196 auto size
= sizeof(SetArray
) +
197 sizeof(SetArray::Elm
) + (set
->capacity() - set
->m_used
);
198 auto const elms
= set
->data();
199 auto const used
= set
->m_used
;
200 for (uint32_t i
= 0; i
< used
; ++i
) {
201 auto const& elm
= elms
[i
];
202 if (elm
.isTombstone()) {
203 size
+= sizeof(SetArray::Elm
);
205 size
+= elm
.hasStrKey() ? getMemSize(elm
.strKey()) : sizeof(int64_t);
210 case ArrayData::ArrayKind::kEmptyKind
:
211 return sizeof(ArrayData
);
213 assert(!"Unsupported Array type in getMemSize");
218 ///////////////////////////////////////////////////////////////////////////////
220 std::unique_ptr
<APCStats
> APCStats::s_apcStats
= nullptr;
222 void APCStats::Create() {
223 FTRACE(3, "APCStats::Create() called\n");
225 s_apcStats
= std::make_unique
<APCStats
>();
228 APCStats::APCStats() : m_valueSize(nullptr)
230 , m_inFileSize(nullptr)
231 , m_livePrimedSize(nullptr)
232 , m_pendingDeleteSize(nullptr)
234 , m_primedEntries(nullptr)
235 , m_livePrimedEntries(nullptr)
236 , m_uncountedEntries(nullptr)
237 , m_uncountedBlocks(nullptr)
238 , m_detailedStats(nullptr) {
239 m_valueSize
= ServiceData::createCounter("apc.value_size.sum");
240 m_keySize
= ServiceData::createCounter("apc.key_size.sum");
241 m_inFileSize
= ServiceData::createCounter("apc.in_file_size.sum");
242 m_livePrimedSize
= ServiceData::createCounter("apc.primed_live_size.sum");
243 m_pendingDeleteSize
=
244 ServiceData::createCounter("apc.pending_delete_size.sum");
245 m_entries
= ServiceData::createCounter("apc.entries");
246 m_primedEntries
= ServiceData::createCounter("apc.primed_entries");
247 m_livePrimedEntries
=
248 ServiceData::createCounter("apc.primed_live_entries");
249 m_uncountedEntries
= ServiceData::createCounter("apc.uncounted_entries");
251 ServiceData::createCounter("apc.uncounted_blocks.mayNotBeAPCValues");
252 if (RuntimeOption::EnableAPCStats
) {
253 m_detailedStats
= new APCDetailedStats();
257 APCStats::~APCStats() {
258 if (m_detailedStats
) delete m_detailedStats
;
261 std::string
APCStats::getStatsInfo() const {
262 std::string
info("APC info\nValue size: ");
263 info
+= std::to_string(m_valueSize
->getValue()) +
265 std::to_string(m_keySize
->getValue()) +
266 "\nMapped to file data size: " +
267 std::to_string(m_inFileSize
->getValue()) +
268 "\nIn memory primed data size: " +
269 std::to_string(m_livePrimedSize
->getValue()) +
270 "\nEntries count: " +
271 std::to_string(m_entries
->getValue()) +
272 "\nPrimed entries count: " +
273 std::to_string(m_primedEntries
->getValue()) +
274 "\nIn memory primed entries count: " +
275 std::to_string(m_livePrimedEntries
->getValue()) +
276 "\nIn total uncounted entries count: " +
277 std::to_string(m_uncountedEntries
->getValue()) +
278 "\nIn memory uncounted blocks: " +
279 std::to_string(m_uncountedBlocks
->getValue());
280 if (apcExtension::UseUncounted
) {
281 info
+= "\nPending deletes via treadmill size: " +
282 std::to_string(m_pendingDeleteSize
->getValue());
284 if (m_detailedStats
) {
285 info
+= m_detailedStats
->getStatsInfo();
290 const StaticString
s_num_entries("num_entries");
291 const StaticString
s_primedEntries("primed_entries");
292 const StaticString
s_primedLiveEntries("primed_live_entries");
293 const StaticString
s_valuesSize("values_size");
294 const StaticString
s_keysSize("keys_size");
295 const StaticString
s_primedInFileSize("primed_in_file_size");
296 const StaticString
s_primeLiveSize("primed_live_size");
297 const StaticString
s_pendingDeleteSize("pending_delete_size");
298 const StaticString
s_uncountedEntries("uncounted_entires");
299 const StaticString
s_uncountedBlocks("uncounted_blocks");
301 void APCStats::collectStats(std::map
<const StringData
*, int64_t>& stats
) const {
303 std::pair
<const StringData
*, int64_t>(s_num_entries
.get(),
304 m_entries
->getValue()));
306 std::pair
<const StringData
*, int64_t>(s_primedEntries
.get(),
307 m_primedEntries
->getValue()));
309 std::pair
<const StringData
*, int64_t>(s_primedLiveEntries
.get(),
310 m_livePrimedEntries
->getValue()));
312 std::pair
<const StringData
*, int64_t>( s_uncountedEntries
.get(),
313 m_uncountedEntries
->getValue()));
315 std::pair
<const StringData
*, int64_t> ( s_uncountedBlocks
.get(),
316 m_uncountedBlocks
->getValue()));
318 std::pair
<const StringData
*, int64_t>(s_valuesSize
.get(),
319 m_valueSize
->getValue()));
321 std::pair
<const StringData
*, int64_t>(s_keysSize
.get(),
322 m_keySize
->getValue()));
324 std::pair
<const StringData
*, int64_t>(s_primedInFileSize
.get(),
325 m_inFileSize
->getValue()));
327 std::pair
<const StringData
*, int64_t>(s_primeLiveSize
.get(),
328 m_livePrimedSize
->getValue()));
330 std::pair
<const StringData
*, int64_t>(s_pendingDeleteSize
.get(),
331 m_pendingDeleteSize
->getValue()));
332 if (m_detailedStats
) {
333 m_detailedStats
->collectStats(stats
);
337 APCDetailedStats::APCDetailedStats() : m_uncounted(nullptr)
338 , m_apcString(nullptr)
339 , m_uncString(nullptr)
340 , m_serArray(nullptr)
343 , m_serKeyset(nullptr)
344 , m_apcArray(nullptr)
347 , m_apcKeyset(nullptr)
348 , m_uncArray(nullptr)
351 , m_uncKeyset(nullptr)
352 , m_serObject(nullptr)
353 , m_apcObject(nullptr)
354 , m_setValues(nullptr)
355 , m_delValues(nullptr)
356 , m_replValues(nullptr)
357 , m_expValues(nullptr) {
358 m_uncounted
= ServiceData::createCounter("apc.type_uncounted");
359 m_apcString
= ServiceData::createCounter("apc.type_apc_string");
360 m_uncString
= ServiceData::createCounter("apc.type_unc_string");
361 m_serArray
= ServiceData::createCounter("apc.type_ser_array");
362 m_serVec
= ServiceData::createCounter("apc.type_ser_vec");
363 m_serDict
= ServiceData::createCounter("apc.type_ser_dict");
364 m_serKeyset
= ServiceData::createCounter("apc.type_ser_keyset");
365 m_apcArray
= ServiceData::createCounter("apc.type_apc_array");
366 m_apcVec
= ServiceData::createCounter("apc.type_apc_vec");
367 m_apcDict
= ServiceData::createCounter("apc.type_apc_dict");
368 m_apcKeyset
= ServiceData::createCounter("apc.type_apc_keyset");
369 m_uncArray
= ServiceData::createCounter("apc.type_unc_array");
370 m_uncVec
= ServiceData::createCounter("apc.type_unc_vec");
371 m_uncDict
= ServiceData::createCounter("apc.type_unc_dict");
372 m_uncKeyset
= ServiceData::createCounter("apc.type_unc_keyset");
373 m_serObject
= ServiceData::createCounter("apc.type_ser_object");
374 m_apcObject
= ServiceData::createCounter("apc.type_apc_object");
376 m_setValues
= ServiceData::createCounter("apc.set_values");
377 m_delValues
= ServiceData::createCounter("apc.deleted_values");
378 m_replValues
= ServiceData::createCounter("apc.replaced_values");
379 m_expValues
= ServiceData::createCounter("apc.expired_values");
382 const StaticString
s_typeUncounted("type_uncounted");
383 const StaticString
s_typeAPCString("type_apc_string");
384 const StaticString
s_typeUncountedString("type_unc_string");
385 const StaticString
s_typeSerArray("type_ser_array");
386 const StaticString
s_typeSerVec("type_ser_vec");
387 const StaticString
s_typeSerDict("type_ser_dict");
388 const StaticString
s_typeSerKeyset("type_ser_keyset");
389 const StaticString
s_typeAPCArray("type_apc_array");
390 const StaticString
s_typeAPCVec("type_apc_vec");
391 const StaticString
s_typeAPCDict("type_apc_dict");
392 const StaticString
s_typeAPCKeyset("type_apc_keyset");
393 const StaticString
s_typUncountedArray("type_unc_array");
394 const StaticString
s_typUncountedVec("type_unc_vec");
395 const StaticString
s_typUncountedDict("type_unc_dict");
396 const StaticString
s_typUncountedKeyset("type_unc_keyset");
397 const StaticString
s_typeSerObject("type_ser_object");
398 const StaticString
s_typeAPCObject("type_apc_object");
399 const StaticString
s_setValueCount("set_values_count");
400 const StaticString
s_deleteValuesCount("deleted_values_count");
401 const StaticString
s_replacedValueCount("replaced_values_count");
402 const StaticString
s_expiredValueCount("expired_values_count");
404 std::string
APCDetailedStats::getStatsInfo() const {
405 return "\nPrimitve and static strings count: " +
406 std::to_string(m_uncounted
->getValue()) +
407 "\nAPC strings count: " +
408 std::to_string(m_apcString
->getValue()) +
409 "\nUncounted strings count: " +
410 std::to_string(m_uncString
->getValue()) +
411 "\nSerialized array count: " +
412 std::to_string(m_serArray
->getValue()) +
413 "\nSerialized vec count: " +
414 std::to_string(m_serVec
->getValue()) +
415 "\nSerialized dict count: " +
416 std::to_string(m_serDict
->getValue()) +
417 "\nSerialized keyset count: " +
418 std::to_string(m_serKeyset
->getValue()) +
419 "\nAPC array count: " +
420 std::to_string(m_apcArray
->getValue()) +
421 "\nAPC vec count: " +
422 std::to_string(m_apcVec
->getValue()) +
423 "\nAPC dict count: " +
424 std::to_string(m_apcDict
->getValue()) +
425 "\nAPC keyset count: " +
426 std::to_string(m_apcKeyset
->getValue()) +
427 "\nUncounted array count: " +
428 std::to_string(m_uncArray
->getValue()) +
429 "\nUncounted vec count: " +
430 std::to_string(m_uncVec
->getValue()) +
431 "\nUncounted dict count: " +
432 std::to_string(m_uncDict
->getValue()) +
433 "\nUncounted keyset count: " +
434 std::to_string(m_uncKeyset
->getValue()) +
435 "\nSerialized object count: " +
436 std::to_string(m_serObject
->getValue()) +
437 "\nAPC object count: " +
438 std::to_string(m_apcObject
->getValue()) +
440 std::to_string(m_setValues
->getValue()) +
442 std::to_string(m_delValues
->getValue()) +
443 "\nreplaced count: " +
444 std::to_string(m_replValues
->getValue()) +
445 "\nexpired count: " +
446 std::to_string(m_expValues
->getValue()) +
450 void APCDetailedStats::collectStats(
451 std::map
<const StringData
*, int64_t>& stats
) const {
453 std::pair
<const StringData
*, int64_t>(s_typeUncounted
.get(),
454 m_uncounted
->getValue()));
456 std::pair
<const StringData
*, int64_t>(s_typeAPCString
.get(),
457 m_apcString
->getValue()));
459 std::pair
<const StringData
*, int64_t>(s_typeUncountedString
.get(),
460 m_uncString
->getValue()));
462 std::pair
<const StringData
*, int64_t>(s_typeSerArray
.get(),
463 m_serArray
->getValue()));
465 std::pair
<const StringData
*, int64_t>(s_typeSerVec
.get(),
466 m_serVec
->getValue()));
468 std::pair
<const StringData
*, int64_t>(s_typeSerDict
.get(),
469 m_serDict
->getValue()));
471 std::pair
<const StringData
*, int64_t>(s_typeSerKeyset
.get(),
472 m_serKeyset
->getValue()));
474 std::pair
<const StringData
*, int64_t>(s_typeAPCArray
.get(),
475 m_apcArray
->getValue()));
477 std::pair
<const StringData
*, int64_t>(s_typeAPCVec
.get(),
478 m_apcVec
->getValue()));
480 std::pair
<const StringData
*, int64_t>(s_typeAPCDict
.get(),
481 m_apcDict
->getValue()));
483 std::pair
<const StringData
*, int64_t>(s_typeAPCKeyset
.get(),
484 m_apcKeyset
->getValue()));
486 std::pair
<const StringData
*, int64_t>(s_typUncountedArray
.get(),
487 m_uncArray
->getValue()));
489 std::pair
<const StringData
*, int64_t>(s_typUncountedVec
.get(),
490 m_uncVec
->getValue()));
492 std::pair
<const StringData
*, int64_t>(s_typUncountedDict
.get(),
493 m_uncDict
->getValue()));
495 std::pair
<const StringData
*, int64_t>(s_typUncountedKeyset
.get(),
496 m_uncKeyset
->getValue()));
498 std::pair
<const StringData
*, int64_t>(s_typeSerObject
.get(),
499 m_serObject
->getValue()));
501 std::pair
<const StringData
*, int64_t>(s_typeAPCObject
.get(),
502 m_apcObject
->getValue()));
504 std::pair
<const StringData
*, int64_t>(s_setValueCount
.get(),
505 m_setValues
->getValue()));
507 std::pair
<const StringData
*, int64_t>(s_deleteValuesCount
.get(),
508 m_delValues
->getValue()));
510 std::pair
<const StringData
*, int64_t>(s_replacedValueCount
.get(),
511 m_replValues
->getValue()));
513 std::pair
<const StringData
*, int64_t>(s_expiredValueCount
.get(),
514 m_expValues
->getValue()));
517 void APCDetailedStats::addAPCValue(APCHandle
* handle
) {
518 m_setValues
->increment();
522 void APCDetailedStats::updateAPCValue(APCHandle
* handle
,
523 APCHandle
* oldHandle
,
525 removeType(oldHandle
);
528 m_expValues
->increment();
530 m_replValues
->increment();
534 void APCDetailedStats::removeAPCValue(APCHandle
* handle
, bool expired
) {
537 m_expValues
->increment();
539 m_delValues
->increment();
543 ServiceData::ExportedCounter
*
544 APCDetailedStats::counterFor(const APCHandle
* handle
) {
545 switch (handle
->kind()) {
546 case APCKind::Uninit
:
550 case APCKind::Double
:
551 case APCKind::StaticString
:
552 case APCKind::StaticArray
:
553 case APCKind::StaticVec
:
554 case APCKind::StaticDict
:
555 case APCKind::StaticKeyset
:
558 case APCKind::UncountedString
:
561 case APCKind::SharedString
:
564 case APCKind::UncountedArray
:
567 case APCKind::UncountedVec
:
570 case APCKind::UncountedDict
:
573 case APCKind::UncountedKeyset
:
576 case APCKind::SerializedArray
:
579 case APCKind::SerializedVec
:
582 case APCKind::SerializedDict
:
585 case APCKind::SerializedKeyset
:
588 case APCKind::SharedArray
:
589 case APCKind::SharedPackedArray
:
590 case APCKind::SharedVArray
:
591 case APCKind::SharedDArray
:
594 case APCKind::SharedVec
:
597 case APCKind::SharedDict
:
600 case APCKind::SharedKeyset
:
603 case APCKind::SerializedObject
:
606 case APCKind::SharedObject
:
607 case APCKind::SharedCollection
:
613 void APCDetailedStats::addType(const APCHandle
* handle
) {
614 counterFor(handle
)->increment();
617 void APCDetailedStats::removeType(const APCHandle
* handle
) {
618 counterFor(handle
)->decrement();
621 ///////////////////////////////////////////////////////////////////////////////