-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathcounters.h
More file actions
295 lines (276 loc) · 15.9 KB
/
Copy pathcounters.h
File metadata and controls
295 lines (276 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
* Copyright 2023 Datadog, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef JAVA_PROFILER_LIBRARY_COUNTERS_H
#define JAVA_PROFILER_LIBRARY_COUNTERS_H
#include "arch.h"
#include <cstring>
#include <vector>
#define DD_COUNTER_TABLE(X) \
X(DICTIONARY_BYTES, "dictionary_bytes") \
X(DICTIONARY_CLASSES_BYTES, "dictionary_classes_bytes") \
X(DICTIONARY_ENDPOINTS_BYTES, "dictionary_endpoints_bytes") \
X(DICTIONARY_CONTEXT_BYTES, "dictionary_context_bytes") \
X(DICTIONARY_PAGES, "dictionary_pages") \
X(DICTIONARY_CLASSES_PAGES, "dictionary_classes_pages") \
X(DICTIONARY_ENDPOINTS_PAGES, "dictionary_endpoints_pages") \
X(DICTIONARY_CONTEXT_PAGES, "dictionary_context_pages") \
X(DICTIONARY_KEYS, "dictionary_keys") \
X(DICTIONARY_CLASSES_KEYS, "dictionary_classes_keys") \
X(DICTIONARY_ENDPOINTS_KEYS, "dictionary_endpoints_keys") \
X(DICTIONARY_CONTEXT_KEYS, "dictionary_context_keys") \
X(DICTIONARY_KEYS_BYTES, "dictionary_keys_bytes") \
X(DICTIONARY_CLASSES_KEYS_BYTES, "dictionary_classes_keys_bytes") \
X(DICTIONARY_ENDPOINTS_KEYS_BYTES, "dictionary_endpoints_keys_bytes") \
X(DICTIONARY_CONTEXT_KEYS_BYTES, "dictionary_context_keys_bytes") \
X(DICTIONARY_ARENA_WASTE_BYTES, "dictionary_arena_waste_bytes") \
X(DICTIONARY_CLASSES_ARENA_WASTE_BYTES, "dictionary_classes_arena_waste_bytes") \
X(DICTIONARY_ENDPOINTS_ARENA_WASTE_BYTES, "dictionary_endpoints_arena_waste_bytes") \
X(DICTIONARY_CONTEXT_ARENA_WASTE_BYTES, "dictionary_context_arena_waste_bytes") \
X(DICTIONARY_DRAIN_TIMEOUTS, "dictionary_drain_timeouts") \
X(CLASS_MAP_AT_CAPACITY, "class_map_at_capacity_drops") \
X(CONTEXT_STORAGE_BYTES, "context_storage_bytes") \
X(CONTEXT_STORAGE_PAGES, "context_storage_pages") \
X(CONTEXT_BOUNDS_MISS_INITS, "context_bounds_miss_inits") \
X(CONTEXT_BOUNDS_MISS_GETS, "context_bounds_miss_gets") \
X(CONTEXT_NULL_PAGE_GETS, "context_null_page_gets") \
X(CONTEXT_ALLOC_FAILS, "context_alloc_fails") \
X(CALLTRACE_STORAGE_BYTES, "calltrace_storage_bytes") \
X(CALLTRACE_STORAGE_TRACES, "calltrace_storage_traces") \
X(LINEAR_ALLOCATOR_BYTES, "linear_allocator_bytes") \
X(LINEAR_ALLOCATOR_CHUNKS, "linear_allocator_chunks") \
X(NATIVE_MEM_LIVE_BYTES, "native_mem_live_bytes") \
X(NATIVE_MEM_MAX_BYTES, "native_mem_max_bytes") \
X(NATIVE_MEM_AVG_BYTES, "native_mem_avg_bytes") \
X(THREAD_IDS_COUNT, "thread_ids_count") \
X(THREAD_NAMES_COUNT, "thread_names_count") \
X(THREAD_FILTER_PAGES, "thread_filter_pages") \
X(THREAD_FILTER_BYTES, "thread_filter_bytes") \
X(JMETHODID_SKIPPED, "jmethodid_skipped_count") \
X(CODECACHE_NATIVE_SIZE_BYTES, "codecache_native_size_bytes") \
X(CODECACHE_NATIVE_COUNT, "native_codecache_count") \
X(CODECACHE_RUNTIME_STUBS_SIZE_BYTES, "codecache_runtime_stubs_size_bytes") \
X(AGCT_NOT_REGISTERED_IN_TLS, "agct_not_registered_in_tls") \
X(AGCT_NOT_JAVA, "agct_not_java") \
X(AGCT_NATIVE_NO_JAVA_CONTEXT, "agct_native_no_java_context") \
X(AGCT_BLOCKED_IN_VM, "agct_blocked_in_vm") \
X(SKIPPED_WALLCLOCK_UNWINDS, "skipped_wallclock_unwinds") \
X(WC_SIGNAL_SUPPRESSED_SAMPLED_RUN, "wc_signals_suppressed_sampled_run") \
X(WC_UNOWNED_BLOCKED_SUPPRESSED, "wc_unowned_blocked_suppressed") \
X(WC_UNOWNED_BLOCKED_RECORDED, "wc_unowned_blocked_recorded") \
X(WC_SIGNAL_QUEUE_FULL, "wc_signals_queue_full") \
X(UNWINDING_TIME_ASYNC, "unwinding_ticks_async") \
X(UNWINDING_TIME_JVMTI, "unwinding_ticks_jvmti") \
X(CALLTRACE_STORAGE_DROPPED, "calltrace_storage_dropped_traces") \
X(CALLTRACE_STORAGE_EXPANSION_SKIPPED, "calltrace_storage_expansion_skipped") \
X(LINE_NUMBER_TABLES, "line_number_tables") \
X(LINE_NUMBER_TABLE_UNREADABLE, "line_number_table_unreadable") \
X(REMOTE_SYMBOLICATION_FRAMES, "remote_symbolication_frames") \
X(REMOTE_SYMBOLICATION_LIBS_WITH_BUILD_ID, "remote_symbolication_libs_with_build_id") \
X(REMOTE_SYMBOLICATION_BUILD_ID_CACHE_HITS, "remote_symbolication_build_id_cache_hits") \
X(VTABLE_RECEIVER_RESOLVE_FAILED, "vtable_receiver_resolve_failed") \
X(THREAD_ENTRY_MARK_DETECTIONS, "thread_entry_mark_detections") \
X(WALKVM_THREAD_INACCESSIBLE, "walkvm_thread_inaccessible") \
X(WALKVM_ANCHOR_NULL, "walkvm_anchor_null") \
X(WALKVM_CACHED_NOT_JAVA, "walkvm_cached_not_java") \
X(WALKVM_NO_VMTHREAD, "walkvm_no_vmthread") \
X(WALKVM_VMTHREAD_OK, "walkvm_vmthread_ok") \
X(WALKVM_ANCHOR_USED_INLINE, "walkvm_anchor_used_inline") \
X(WALKVM_ANCHOR_FALLBACK, "walkvm_anchor_fallback") \
X(WALKVM_CODEH_NO_VM, "walkvm_codeh_no_vm") \
X(WALKVM_DEPTH_ZERO, "walkvm_depth_zero") \
X(WALKVM_HIT_CODEHEAP, "walkvm_hit_codeheap") \
X(WALKVM_ANCHOR_FALLBACK_FAIL, "walkvm_anchor_fallback_fail") \
X(WALKVM_ANCHOR_CONSUMED, "walkvm_anchor_consumed") \
X(WALKVM_BREAK_INTERPRETED, "walkvm_break_interpreted") \
X(WALKVM_BREAK_COMPILED, "walkvm_break_compiled") \
X(WALKVM_JAVA_FRAME_OK, "walkvm_java_frame_ok") \
X(WALKVM_ANCHOR_INLINE_NO_ANCHOR, "walkvm_anchor_inline_no_anchor") \
X(WALKVM_ANCHOR_INLINE_NO_SP, "walkvm_anchor_inline_no_sp") \
X(WALKVM_ANCHOR_INLINE_BAD_SP, "walkvm_anchor_inline_bad_sp") \
X(WALKVM_SAVED_ANCHOR_USED, "walkvm_saved_anchor_used") \
X(WALKVM_STUB_GENERIC_UNWIND, "walkvm_stub_generic_unwind") \
X(WALKVM_STUB_FRAMESIZE_FALLBACK, "walkvm_stub_framesize_fallback") \
X(WALKVM_FP_CHAIN_ATTEMPT, "walkvm_fp_chain_attempt") \
X(WALKVM_FP_CHAIN_REACHED_CODEHEAP, "walkvm_fp_chain_reached_codeheap") \
X(WALKVM_ANCHOR_NOT_IN_JAVA, "walkvm_anchor_not_in_java") \
X(WALKVM_CONT_BARRIER_HIT, "walkvm_cont_barrier_hit") \
X(WALKVM_ENTER_SPECIAL_HIT, "walkvm_enter_special_hit") \
X(WALKVM_CONT_SPECULATIVE_HIT,"walkvm_cont_speculative_hit") \
X(WALKVM_CONT_ENTRY_NULL, "walkvm_cont_entry_null") \
X(NATIVE_LIBS_DROPPED, "native_libs_dropped") \
X(SIGACTION_PATCHED_LIBS, "sigaction_patched_libs") \
X(SIGACTION_INTERCEPTED, "sigaction_intercepted") \
X(CTIMER_SIGNAL_OWN, "ctimer_signal_own") \
X(CTIMER_SIGNAL_FOREIGN, "ctimer_signal_foreign") \
X(WALLCLOCK_SIGNAL_OWN, "wallclock_signal_own") \
X(WALLCLOCK_SIGNAL_FOREIGN, "wallclock_signal_foreign") \
X(JVMTI_STACKS_INIT_OK, "jvmti_stacks_init_ok") \
X(JVMTI_STACKS_INIT_FAILED, "jvmti_stacks_init_failed") \
X(JVMTI_STACKS_REQUESTED, "jvmti_stacks_requested") \
X(NATIVE_TRACE_HOOK_PREFIX_NOT_FOUND, "native_trace_hook_prefix_not_found") \
X(NATIVE_HOOK_MARK_RESOLVE_FAILED, "native_hook_mark_resolve_failed") \
X(JVMTI_STACKS_FAILED_WRONG_PHASE, "jvmti_stacks_failed_wrong_phase") \
X(JVMTI_STACKS_FAILED_OTHER, "jvmti_stacks_failed_other") \
/* Delegated stacks dropped at slot-lock. Rec-lock drops from all recording \
* paths (delegated and direct) go into SAMPLES_DROPPED_REC_LOCK. */ \
X(JVMTI_STACKS_DROPPED_LOCK, "jvmti_stacks_dropped_lock") \
X(SAMPLES_DROPPED_REC_LOCK, "samples_dropped_rec_lock") \
X(SAMPLES_DROPPED_THREAD_LOCAL, "samples_dropped_thread_local") \
X(SAFECOPY_FAILED, "safecopy_failed") \
X(SAFEFETCH_FAILED, "safefetch_failed") \
X(STACKWALK_LONGJMP_RECOVERED, "stackwalk_longjmp_recovered") \
/* writeElement() guards against a corrupted/dangling JfrMetadata tree. \
* Root cause is still unconfirmed, so these counters are the durable \
* signal for spotting a recurrence. */ \
X(METADATA_TREE_NULL_CHILD, "metadata_tree_null_child") \
X(METADATA_TREE_DEPTH_EXCEEDED, "metadata_tree_depth_exceeded") \
/* A resolved datadog.ReferenceChain could not be cached in \
* ReferenceChainTracker::_resolved_chains (referenceChains.h): a brand-new \
* leak-candidate klass arrived with the cache already at \
* MAX_RESOLVED_CHAINS, so its chain is dropped rather than evicting some \
* other still-live sample's chain. See that constant's own comment. */ \
X(REFERENCE_CHAIN_EVENTS_DROPPED, "reference_chain_events_dropped") \
/* ReferenceChainTracker::releaseSearchTags() (referenceChains.cpp) failed \
* to call GetObjectsWithTags() for at least one batch - the search's tag \
* release is retried on a later call rather than proceeding, but this \
* counts how often that retry path is taken. */ \
X(REFERENCE_CHAIN_TAG_RELEASE_FAILED, "reference_chain_tag_release_failed") \
/* Profiler::writeReferenceChain() (profiler.cpp) could not acquire a \
* sample-record lock within its bounded retry budget and dropped the \
* already-dequeued datadog.ReferenceChain event for this dump - not \
* permanently lost, since ReferenceChainTracker::_resolved_chains (see \
* REFERENCE_CHAIN_EVENTS_DROPPED above) keeps the resolved chain cached \
* and re-emits it on a later dump while the leak candidate is still \
* live. */ \
X(REFERENCE_CHAIN_WRITE_DROPPED, "reference_chain_write_dropped") \
/* FrontierTable's own calloc/realloc-backed storage (referenceChains.cpp) - \
* outside NMT's visibility since it bypasses os::malloc, so this is the only \
* way to attribute its native RSS contribution. */ \
X(REFERENCE_CHAIN_FRONTIER_TABLE_BYTES, "reference_chain_frontier_table_bytes") \
X(REFERENCE_CHAIN_FRONTIER_TABLE_CAPACITY, "reference_chain_frontier_table_capacity") \
DD_COUNTER_TABLE_FAULT_INJECTION(X) \
DD_COUNTER_TABLE_FI_DEBUG(X) \
DD_COUNTER_TABLE_DEBUG(X)
// Fault-injection-only counter: number of faults actually injected. Only
// compiled in when __FAULT_INJECTION__ is defined, so it occupies no enum slot
// and adds no storage in normal builds.
#ifdef __FAULT_INJECTION__
#define DD_COUNTER_TABLE_FAULT_INJECTION(X) \
X(FAULTS_INJECTED, "faults_injected")
#else
#define DD_COUNTER_TABLE_FAULT_INJECTION(X)
#endif
// Fault-injection + debug only: faults injected while the current thread was
// NOT inside a walkVM siglongjmp-protected region. Such a site relies solely on
// safefetch (or would genuinely crash if the poisoned pointer is raw-dereferenced
// outside any recovery), so a non-zero value flags injection sites that are not
// covered by siglongjmp protection. Compiled in only when both __FAULT_INJECTION__
// and DEBUG are defined.
#if defined(__FAULT_INJECTION__) && defined(DEBUG)
#define DD_COUNTER_TABLE_FI_DEBUG(X) \
X(FAULTS_INJECTED_UNPROTECTED, "faults_injected_unprotected")
#else
#define DD_COUNTER_TABLE_FI_DEBUG(X)
#endif
// Debug-only counters: SafeAccess reads/copies issued while the thread is
// already inside a walkVM siglongjmp-protected region (redundant safefetch
// overhead). Not compiled into release builds at all, so they occupy no enum
// slot and add no storage there.
#ifdef DEBUG
#define DD_COUNTER_TABLE_DEBUG(X) \
X(SAFEFETCH_WHILE_PROTECTED, "safefetch_while_protected") \
X(SAFECOPY_WHILE_PROTECTED, "safecopy_while_protected")
#else
#define DD_COUNTER_TABLE_DEBUG(X)
#endif
#define X_ENUM(a, b) a,
typedef enum CounterId : int {
DD_COUNTER_TABLE(X_ENUM) DD_NUM_COUNTERS
} CounterId;
#undef X_ENUM
class Counters {
private:
static const u32 ALIGNMENT = 16;
volatile long long *_counters;
static long long *init();
Counters() : _counters() {
#ifdef COUNTERS
_counters = Counters::init();
#endif // COUNTERS
}
public:
static Counters &instance() {
static Counters instance;
return instance;
}
Counters(Counters const &) = delete;
void operator=(Counters const &) = delete;
static constexpr int address(int index) { return index * ALIGNMENT; }
static constexpr int size() {
return address(DD_NUM_COUNTERS * sizeof(long long));
}
static long long *getCounters() {
#ifdef COUNTERS
return const_cast<long long *>(Counters::instance()._counters);
#else
return nullptr;
#endif // COUNTERS
}
static long long getCounter(CounterId counter, int offset = 0) {
#ifdef COUNTERS
return Counters::instance()
._counters[address(static_cast<int>(counter) + offset)];
#else
return 0;
#endif // COUNTERS
}
static void set(CounterId counter, long long value, int offset = 0) {
#ifdef COUNTERS
storeRelease(Counters::instance()
._counters[address(static_cast<int>(counter) + offset)],
value);
#endif // COUNTERS
}
static void increment(CounterId counter, long long delta = 1,
int offset = 0) {
#ifdef COUNTERS
atomicIncRelaxed(Counters::instance()
._counters[address(static_cast<int>(counter) + offset)],
delta);
#endif // COUNTERS
}
static void decrement(CounterId counter, long long delta = 1,
int offset = 0) {
#ifdef COUNTERS
increment(counter, -delta, offset);
#endif // COUNTERS
}
static std::vector<const char *> describeCounters() {
#ifdef COUNTERS
#define X_NAME(a, b) b,
return {DD_COUNTER_TABLE(X_NAME)};
#undef X_NAME
#else
return {};
#endif // COUNTERS
}
static void reset() {
#ifdef COUNTERS
memset((void *)Counters::instance()._counters, 0, size());
#endif // COUNTERS
}
};
#endif // JAVA_PROFILER_LIBRARY_COUNTERS_H