Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / apc-stats.cpp
blobe0d2aabdc34fe71afceb67d455958c3f98e9d877
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
32 namespace HPHP {
34 TRACE_SET_MOD(apc);
37 ///////////////////////////////////////////////////////////////////////////////
39 namespace {
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()");
56 return 0;
61 size_t getMemSize(const APCHandle* handle) {
62 switch (handle->kind()) {
63 case APCKind::Uninit:
64 case APCKind::Null:
65 case APCKind::Bool:
66 case APCKind::Int:
67 case APCKind::Double:
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");
117 return 0;
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));
128 } else {
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);
137 return memSize;
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);
149 return size;
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);
161 return size;
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);
175 return size;
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);
187 continue;
189 size += ptr->hasStrKey() ? getMemSize(ptr->skey) : sizeof(int64_t);
190 size += getMemSize(&ptr->data, recurse);
192 return size;
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);
204 } else {
205 size += elm.hasStrKey() ? getMemSize(elm.strKey()) : sizeof(int64_t);
208 return size;
210 case ArrayData::ArrayKind::kEmptyKind:
211 return sizeof(ArrayData);
212 default:
213 assert(!"Unsupported Array type in getMemSize");
215 return 0;
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)
229 , m_keySize(nullptr)
230 , m_inFileSize(nullptr)
231 , m_livePrimedSize(nullptr)
232 , m_pendingDeleteSize(nullptr)
233 , m_entries(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");
250 m_uncountedBlocks =
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()) +
264 "\nKey size: " +
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();
287 return info + "\n";
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 {
302 stats.insert(
303 std::pair<const StringData*, int64_t>(s_num_entries.get(),
304 m_entries->getValue()));
305 stats.insert(
306 std::pair<const StringData*, int64_t>(s_primedEntries.get(),
307 m_primedEntries->getValue()));
308 stats.insert(
309 std::pair<const StringData*, int64_t>(s_primedLiveEntries.get(),
310 m_livePrimedEntries->getValue()));
311 stats.insert(
312 std::pair<const StringData*, int64_t>( s_uncountedEntries.get(),
313 m_uncountedEntries->getValue()));
314 stats.insert(
315 std::pair<const StringData*, int64_t> ( s_uncountedBlocks.get(),
316 m_uncountedBlocks->getValue()));
317 stats.insert(
318 std::pair<const StringData*, int64_t>(s_valuesSize.get(),
319 m_valueSize->getValue()));
320 stats.insert(
321 std::pair<const StringData*, int64_t>(s_keysSize.get(),
322 m_keySize->getValue()));
323 stats.insert(
324 std::pair<const StringData*, int64_t>(s_primedInFileSize.get(),
325 m_inFileSize->getValue()));
326 stats.insert(
327 std::pair<const StringData*, int64_t>(s_primeLiveSize.get(),
328 m_livePrimedSize->getValue()));
329 stats.insert(
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)
341 , m_serVec(nullptr)
342 , m_serDict(nullptr)
343 , m_serKeyset(nullptr)
344 , m_apcArray(nullptr)
345 , m_apcVec(nullptr)
346 , m_apcDict(nullptr)
347 , m_apcKeyset(nullptr)
348 , m_uncArray(nullptr)
349 , m_uncVec(nullptr)
350 , m_uncDict(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()) +
439 "\add count: " +
440 std::to_string(m_setValues->getValue()) +
441 "\ndelete count: " +
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()) +
447 "\n";
450 void APCDetailedStats::collectStats(
451 std::map<const StringData*, int64_t>& stats) const {
452 stats.insert(
453 std::pair<const StringData*, int64_t>(s_typeUncounted.get(),
454 m_uncounted->getValue()));
455 stats.insert(
456 std::pair<const StringData*, int64_t>(s_typeAPCString.get(),
457 m_apcString->getValue()));
458 stats.insert(
459 std::pair<const StringData*, int64_t>(s_typeUncountedString.get(),
460 m_uncString->getValue()));
461 stats.insert(
462 std::pair<const StringData*, int64_t>(s_typeSerArray.get(),
463 m_serArray->getValue()));
464 stats.insert(
465 std::pair<const StringData*, int64_t>(s_typeSerVec.get(),
466 m_serVec->getValue()));
467 stats.insert(
468 std::pair<const StringData*, int64_t>(s_typeSerDict.get(),
469 m_serDict->getValue()));
470 stats.insert(
471 std::pair<const StringData*, int64_t>(s_typeSerKeyset.get(),
472 m_serKeyset->getValue()));
473 stats.insert(
474 std::pair<const StringData*, int64_t>(s_typeAPCArray.get(),
475 m_apcArray->getValue()));
476 stats.insert(
477 std::pair<const StringData*, int64_t>(s_typeAPCVec.get(),
478 m_apcVec->getValue()));
479 stats.insert(
480 std::pair<const StringData*, int64_t>(s_typeAPCDict.get(),
481 m_apcDict->getValue()));
482 stats.insert(
483 std::pair<const StringData*, int64_t>(s_typeAPCKeyset.get(),
484 m_apcKeyset->getValue()));
485 stats.insert(
486 std::pair<const StringData*, int64_t>(s_typUncountedArray.get(),
487 m_uncArray->getValue()));
488 stats.insert(
489 std::pair<const StringData*, int64_t>(s_typUncountedVec.get(),
490 m_uncVec->getValue()));
491 stats.insert(
492 std::pair<const StringData*, int64_t>(s_typUncountedDict.get(),
493 m_uncDict->getValue()));
494 stats.insert(
495 std::pair<const StringData*, int64_t>(s_typUncountedKeyset.get(),
496 m_uncKeyset->getValue()));
497 stats.insert(
498 std::pair<const StringData*, int64_t>(s_typeSerObject.get(),
499 m_serObject->getValue()));
500 stats.insert(
501 std::pair<const StringData*, int64_t>(s_typeAPCObject.get(),
502 m_apcObject->getValue()));
503 stats.insert(
504 std::pair<const StringData*, int64_t>(s_setValueCount.get(),
505 m_setValues->getValue()));
506 stats.insert(
507 std::pair<const StringData*, int64_t>(s_deleteValuesCount.get(),
508 m_delValues->getValue()));
509 stats.insert(
510 std::pair<const StringData*, int64_t>(s_replacedValueCount.get(),
511 m_replValues->getValue()));
512 stats.insert(
513 std::pair<const StringData*, int64_t>(s_expiredValueCount.get(),
514 m_expValues->getValue()));
517 void APCDetailedStats::addAPCValue(APCHandle* handle) {
518 m_setValues->increment();
519 addType(handle);
522 void APCDetailedStats::updateAPCValue(APCHandle* handle,
523 APCHandle* oldHandle,
524 bool expired) {
525 removeType(oldHandle);
526 addType(handle);
527 if (expired) {
528 m_expValues->increment();
529 } else {
530 m_replValues->increment();
534 void APCDetailedStats::removeAPCValue(APCHandle* handle, bool expired) {
535 removeType(handle);
536 if (expired) {
537 m_expValues->increment();
538 } else {
539 m_delValues->increment();
543 ServiceData::ExportedCounter*
544 APCDetailedStats::counterFor(const APCHandle* handle) {
545 switch (handle->kind()) {
546 case APCKind::Uninit:
547 case APCKind::Null:
548 case APCKind::Bool:
549 case APCKind::Int:
550 case APCKind::Double:
551 case APCKind::StaticString:
552 case APCKind::StaticArray:
553 case APCKind::StaticVec:
554 case APCKind::StaticDict:
555 case APCKind::StaticKeyset:
556 return m_uncounted;
558 case APCKind::UncountedString:
559 return m_uncString;
561 case APCKind::SharedString:
562 return m_apcString;
564 case APCKind::UncountedArray:
565 return m_uncArray;
567 case APCKind::UncountedVec:
568 return m_uncVec;
570 case APCKind::UncountedDict:
571 return m_uncDict;
573 case APCKind::UncountedKeyset:
574 return m_uncKeyset;
576 case APCKind::SerializedArray:
577 return m_serArray;
579 case APCKind::SerializedVec:
580 return m_serVec;
582 case APCKind::SerializedDict:
583 return m_serDict;
585 case APCKind::SerializedKeyset:
586 return m_serKeyset;
588 case APCKind::SharedArray:
589 case APCKind::SharedPackedArray:
590 case APCKind::SharedVArray:
591 case APCKind::SharedDArray:
592 return m_apcArray;
594 case APCKind::SharedVec:
595 return m_apcVec;
597 case APCKind::SharedDict:
598 return m_apcDict;
600 case APCKind::SharedKeyset:
601 return m_apcKeyset;
603 case APCKind::SerializedObject:
604 return m_serObject;
606 case APCKind::SharedObject:
607 case APCKind::SharedCollection:
608 return m_apcObject;
610 not_reached();
613 void APCDetailedStats::addType(const APCHandle* handle) {
614 counterFor(handle)->increment();
617 void APCDetailedStats::removeType(const APCHandle* handle) {
618 counterFor(handle)->decrement();
621 ///////////////////////////////////////////////////////////////////////////////