1 | /* |
2 | * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | */ |
23 | |
24 | #ifndef SHARE_GC_Z_ZSTAT_HPP |
25 | #define SHARE_GC_Z_ZSTAT_HPP |
26 | |
27 | #include "gc/shared/concurrentGCThread.hpp" |
28 | #include "gc/shared/gcTimer.hpp" |
29 | #include "gc/z/zMetronome.hpp" |
30 | #include "logging/logHandle.hpp" |
31 | #include "memory/allocation.hpp" |
32 | #include "utilities/numberSeq.hpp" |
33 | #include "utilities/ticks.hpp" |
34 | |
35 | class ZPage; |
36 | class ZStatSampler; |
37 | class ZStatSamplerHistory; |
38 | struct ZStatCounterData; |
39 | struct ZStatSamplerData; |
40 | |
41 | // |
42 | // Stat unit printers |
43 | // |
44 | typedef void (*ZStatUnitPrinter)(LogTargetHandle log, const ZStatSampler&, const ZStatSamplerHistory&); |
45 | |
46 | void ZStatUnitTime(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history); |
47 | void ZStatUnitBytes(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history); |
48 | void ZStatUnitThreads(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history); |
49 | void ZStatUnitBytesPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history); |
50 | void ZStatUnitOpsPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history); |
51 | |
52 | // |
53 | // Stat value |
54 | // |
55 | class ZStatValue { |
56 | private: |
57 | static uintptr_t _base; |
58 | static uint32_t _cpu_offset; |
59 | |
60 | const char* const _group; |
61 | const char* const _name; |
62 | const uint32_t _id; |
63 | const uint32_t _offset; |
64 | |
65 | protected: |
66 | ZStatValue(const char* group, |
67 | const char* name, |
68 | uint32_t id, |
69 | uint32_t size); |
70 | |
71 | template <typename T> T* get_cpu_local(uint32_t cpu) const; |
72 | |
73 | public: |
74 | static void initialize(); |
75 | |
76 | const char* group() const; |
77 | const char* name() const; |
78 | uint32_t id() const; |
79 | }; |
80 | |
81 | // |
82 | // Stat iterable value |
83 | // |
84 | template <typename T> |
85 | class ZStatIterableValue : public ZStatValue { |
86 | private: |
87 | static uint32_t _count; |
88 | static T* _first; |
89 | |
90 | T* _next; |
91 | |
92 | T* insert() const; |
93 | |
94 | protected: |
95 | ZStatIterableValue(const char* group, |
96 | const char* name, |
97 | uint32_t size); |
98 | |
99 | public: |
100 | static uint32_t count() { |
101 | return _count; |
102 | } |
103 | |
104 | static T* first() { |
105 | return _first; |
106 | } |
107 | |
108 | T* next() const { |
109 | return _next; |
110 | } |
111 | }; |
112 | |
113 | // |
114 | // Stat sampler |
115 | // |
116 | class ZStatSampler : public ZStatIterableValue<ZStatSampler> { |
117 | private: |
118 | const ZStatUnitPrinter _printer; |
119 | |
120 | public: |
121 | ZStatSampler(const char* group, |
122 | const char* name, |
123 | ZStatUnitPrinter printer); |
124 | |
125 | ZStatSamplerData* get() const; |
126 | ZStatSamplerData collect_and_reset() const; |
127 | |
128 | ZStatUnitPrinter printer() const; |
129 | }; |
130 | |
131 | // |
132 | // Stat counter |
133 | // |
134 | class ZStatCounter : public ZStatIterableValue<ZStatCounter> { |
135 | private: |
136 | const ZStatSampler _sampler; |
137 | |
138 | public: |
139 | ZStatCounter(const char* group, |
140 | const char* name, |
141 | ZStatUnitPrinter printer); |
142 | |
143 | ZStatCounterData* get() const; |
144 | void sample_and_reset() const; |
145 | }; |
146 | |
147 | // |
148 | // Stat unsampled counter |
149 | // |
150 | class ZStatUnsampledCounter : public ZStatIterableValue<ZStatUnsampledCounter> { |
151 | public: |
152 | ZStatUnsampledCounter(const char* name); |
153 | |
154 | ZStatCounterData* get() const; |
155 | ZStatCounterData collect_and_reset() const; |
156 | }; |
157 | |
158 | // |
159 | // Stat MMU (Minimum Mutator Utilization) |
160 | // |
161 | class ZStatMMUPause { |
162 | private: |
163 | double _start; |
164 | double _end; |
165 | |
166 | public: |
167 | ZStatMMUPause(); |
168 | ZStatMMUPause(const Ticks& start, const Ticks& end); |
169 | |
170 | double end() const; |
171 | double overlap(double start, double end) const; |
172 | }; |
173 | |
174 | class ZStatMMU { |
175 | private: |
176 | static size_t _next; |
177 | static size_t _npauses; |
178 | static ZStatMMUPause _pauses[200]; // Record the last 200 pauses |
179 | |
180 | static double _mmu_2ms; |
181 | static double _mmu_5ms; |
182 | static double _mmu_10ms; |
183 | static double _mmu_20ms; |
184 | static double _mmu_50ms; |
185 | static double _mmu_100ms; |
186 | |
187 | static const ZStatMMUPause& pause(size_t index); |
188 | static double calculate_mmu(double time_slice); |
189 | |
190 | public: |
191 | static void register_pause(const Ticks& start, const Ticks& end); |
192 | |
193 | static void print(); |
194 | }; |
195 | |
196 | // |
197 | // Stat phases |
198 | // |
199 | class ZStatPhase { |
200 | private: |
201 | static ConcurrentGCTimer _timer; |
202 | |
203 | protected: |
204 | const ZStatSampler _sampler; |
205 | |
206 | ZStatPhase(const char* group, const char* name); |
207 | |
208 | void log_start(LogTargetHandle log, bool thread = false) const; |
209 | void log_end(LogTargetHandle log, const Tickspan& duration, bool thread = false) const; |
210 | |
211 | public: |
212 | static ConcurrentGCTimer* timer(); |
213 | |
214 | const char* name() const; |
215 | |
216 | virtual void register_start(const Ticks& start) const = 0; |
217 | virtual void register_end(const Ticks& start, const Ticks& end) const = 0; |
218 | }; |
219 | |
220 | class ZStatPhaseCycle : public ZStatPhase { |
221 | public: |
222 | ZStatPhaseCycle(const char* name); |
223 | |
224 | virtual void register_start(const Ticks& start) const; |
225 | virtual void register_end(const Ticks& start, const Ticks& end) const; |
226 | }; |
227 | |
228 | class ZStatPhasePause : public ZStatPhase { |
229 | private: |
230 | static Tickspan _max; // Max pause time |
231 | |
232 | public: |
233 | ZStatPhasePause(const char* name); |
234 | |
235 | static const Tickspan& max(); |
236 | |
237 | virtual void register_start(const Ticks& start) const; |
238 | virtual void register_end(const Ticks& start, const Ticks& end) const; |
239 | }; |
240 | |
241 | class ZStatPhaseConcurrent : public ZStatPhase { |
242 | public: |
243 | ZStatPhaseConcurrent(const char* name); |
244 | |
245 | virtual void register_start(const Ticks& start) const; |
246 | virtual void register_end(const Ticks& start, const Ticks& end) const; |
247 | }; |
248 | |
249 | class ZStatSubPhase : public ZStatPhase { |
250 | public: |
251 | ZStatSubPhase(const char* name); |
252 | |
253 | virtual void register_start(const Ticks& start) const; |
254 | virtual void register_end(const Ticks& start, const Ticks& end) const; |
255 | }; |
256 | |
257 | class ZStatCriticalPhase : public ZStatPhase { |
258 | private: |
259 | const ZStatCounter _counter; |
260 | const bool _verbose; |
261 | |
262 | public: |
263 | ZStatCriticalPhase(const char* name, bool verbose = true); |
264 | |
265 | virtual void register_start(const Ticks& start) const; |
266 | virtual void register_end(const Ticks& start, const Ticks& end) const; |
267 | }; |
268 | |
269 | // |
270 | // Stat timer |
271 | // |
272 | class ZStatTimerDisable : public StackObj { |
273 | private: |
274 | static __thread uint32_t _active; |
275 | |
276 | public: |
277 | ZStatTimerDisable() { |
278 | _active++; |
279 | } |
280 | |
281 | ~ZStatTimerDisable() { |
282 | _active--; |
283 | } |
284 | |
285 | static bool is_active() { |
286 | return _active > 0; |
287 | } |
288 | }; |
289 | |
290 | class ZStatTimer : public StackObj { |
291 | private: |
292 | const bool _enabled; |
293 | const ZStatPhase& _phase; |
294 | const Ticks _start; |
295 | |
296 | public: |
297 | ZStatTimer(const ZStatPhase& phase) : |
298 | _enabled(!ZStatTimerDisable::is_active()), |
299 | _phase(phase), |
300 | _start(Ticks::now()) { |
301 | if (_enabled) { |
302 | _phase.register_start(_start); |
303 | } |
304 | } |
305 | |
306 | ~ZStatTimer() { |
307 | if (_enabled) { |
308 | const Ticks end = Ticks::now(); |
309 | _phase.register_end(_start, end); |
310 | } |
311 | } |
312 | }; |
313 | |
314 | // |
315 | // Stat sample/increment |
316 | // |
317 | void ZStatSample(const ZStatSampler& sampler, uint64_t value, bool trace = ZStatisticsForceTrace); |
318 | void ZStatInc(const ZStatCounter& counter, uint64_t increment = 1, bool trace = ZStatisticsForceTrace); |
319 | void ZStatInc(const ZStatUnsampledCounter& counter, uint64_t increment = 1); |
320 | |
321 | // |
322 | // Stat allocation rate |
323 | // |
324 | class ZStatAllocRate : public AllStatic { |
325 | private: |
326 | static const ZStatUnsampledCounter _counter; |
327 | static TruncatedSeq _rate; // B/s |
328 | static TruncatedSeq _rate_avg; // B/s |
329 | |
330 | public: |
331 | static const uint64_t sample_window_sec = 1; // seconds |
332 | static const uint64_t sample_hz = 10; |
333 | |
334 | static const ZStatUnsampledCounter& counter(); |
335 | static uint64_t sample_and_reset(); |
336 | |
337 | static double avg(); |
338 | static double avg_sd(); |
339 | }; |
340 | |
341 | // |
342 | // Stat thread |
343 | // |
344 | class ZStat : public ConcurrentGCThread { |
345 | private: |
346 | static const uint64_t sample_hz = 1; |
347 | |
348 | ZMetronome _metronome; |
349 | |
350 | void sample_and_collect(ZStatSamplerHistory* history) const; |
351 | bool should_print(LogTargetHandle log) const; |
352 | void print(LogTargetHandle log, const ZStatSamplerHistory* history) const; |
353 | |
354 | protected: |
355 | virtual void run_service(); |
356 | virtual void stop_service(); |
357 | |
358 | public: |
359 | ZStat(); |
360 | }; |
361 | |
362 | // |
363 | // Stat cycle |
364 | // |
365 | class ZStatCycle : public AllStatic { |
366 | private: |
367 | static uint64_t _ncycles; |
368 | static Ticks _start_of_last; |
369 | static Ticks _end_of_last; |
370 | static NumberSeq _normalized_duration; |
371 | |
372 | public: |
373 | static void at_start(); |
374 | static void at_end(double boost_factor); |
375 | |
376 | static uint64_t ncycles(); |
377 | static const AbsSeq& normalized_duration(); |
378 | static double time_since_last(); |
379 | }; |
380 | |
381 | // |
382 | // Stat load |
383 | // |
384 | class ZStatLoad : public AllStatic { |
385 | public: |
386 | static void print(); |
387 | }; |
388 | |
389 | // |
390 | // Stat mark |
391 | // |
392 | class ZStatMark : public AllStatic { |
393 | private: |
394 | static size_t _nstripes; |
395 | static size_t _nproactiveflush; |
396 | static size_t _nterminateflush; |
397 | static size_t _ntrycomplete; |
398 | static size_t _ncontinue; |
399 | |
400 | public: |
401 | static void set_at_mark_start(size_t nstripes); |
402 | static void set_at_mark_end(size_t nproactiveflush, |
403 | size_t nterminateflush, |
404 | size_t ntrycomplete, |
405 | size_t ncontinue); |
406 | |
407 | static void print(); |
408 | }; |
409 | |
410 | // |
411 | // Stat relocation |
412 | // |
413 | class ZStatRelocation : public AllStatic { |
414 | private: |
415 | static size_t _relocating; |
416 | static bool _success; |
417 | |
418 | public: |
419 | static void set_at_select_relocation_set(size_t relocating); |
420 | static void set_at_relocate_end(bool success); |
421 | |
422 | static void print(); |
423 | }; |
424 | |
425 | // |
426 | // Stat nmethods |
427 | // |
428 | class ZStatNMethods : public AllStatic { |
429 | public: |
430 | static void print(); |
431 | }; |
432 | |
433 | // |
434 | // Stat metaspace |
435 | // |
436 | class ZStatMetaspace : public AllStatic { |
437 | public: |
438 | static void print(); |
439 | }; |
440 | |
441 | // |
442 | // Stat references |
443 | // |
444 | class ZStatReferences : public AllStatic { |
445 | private: |
446 | static struct ZCount { |
447 | size_t encountered; |
448 | size_t discovered; |
449 | size_t enqueued; |
450 | } _soft, _weak, _final, _phantom; |
451 | |
452 | static void set(ZCount* count, size_t encountered, size_t discovered, size_t enqueued); |
453 | static void print(const char* name, const ZCount& ref); |
454 | |
455 | public: |
456 | static void set_soft(size_t encountered, size_t discovered, size_t enqueued); |
457 | static void set_weak(size_t encountered, size_t discovered, size_t enqueued); |
458 | static void set_final(size_t encountered, size_t discovered, size_t enqueued); |
459 | static void set_phantom(size_t encountered, size_t discovered, size_t enqueued); |
460 | |
461 | static void print(); |
462 | }; |
463 | |
464 | // |
465 | // Stat heap |
466 | // |
467 | class ZStatHeap : public AllStatic { |
468 | private: |
469 | static struct ZAtInitialize { |
470 | size_t min_capacity; |
471 | size_t max_capacity; |
472 | size_t max_reserve; |
473 | } _at_initialize; |
474 | |
475 | static struct ZAtMarkStart { |
476 | size_t soft_max_capacity; |
477 | size_t capacity; |
478 | size_t reserve; |
479 | size_t used; |
480 | size_t free; |
481 | } _at_mark_start; |
482 | |
483 | static struct ZAtMarkEnd { |
484 | size_t capacity; |
485 | size_t reserve; |
486 | size_t allocated; |
487 | size_t used; |
488 | size_t free; |
489 | size_t live; |
490 | size_t garbage; |
491 | } _at_mark_end; |
492 | |
493 | static struct ZAtRelocateStart { |
494 | size_t capacity; |
495 | size_t reserve; |
496 | size_t garbage; |
497 | size_t allocated; |
498 | size_t reclaimed; |
499 | size_t used; |
500 | size_t free; |
501 | } _at_relocate_start; |
502 | |
503 | static struct ZAtRelocateEnd { |
504 | size_t capacity; |
505 | size_t capacity_high; |
506 | size_t capacity_low; |
507 | size_t reserve; |
508 | size_t reserve_high; |
509 | size_t reserve_low; |
510 | size_t garbage; |
511 | size_t allocated; |
512 | size_t reclaimed; |
513 | size_t used; |
514 | size_t used_high; |
515 | size_t used_low; |
516 | size_t free; |
517 | size_t free_high; |
518 | size_t free_low; |
519 | } _at_relocate_end; |
520 | |
521 | static size_t available(size_t used); |
522 | static size_t reserve(size_t used); |
523 | static size_t free(size_t used); |
524 | |
525 | public: |
526 | static void set_at_initialize(size_t min_capacity, |
527 | size_t max_capacity, |
528 | size_t max_reserve); |
529 | static void set_at_mark_start(size_t soft_max_capacity, |
530 | size_t capacity, |
531 | size_t used); |
532 | static void set_at_mark_end(size_t capacity, |
533 | size_t allocated, |
534 | size_t used); |
535 | static void set_at_select_relocation_set(size_t live, |
536 | size_t garbage, |
537 | size_t reclaimed); |
538 | static void set_at_relocate_start(size_t capacity, |
539 | size_t allocated, |
540 | size_t used); |
541 | static void set_at_relocate_end(size_t capacity, |
542 | size_t allocated, |
543 | size_t reclaimed, |
544 | size_t used, |
545 | size_t used_high, |
546 | size_t used_low); |
547 | |
548 | static size_t max_capacity(); |
549 | static size_t used_at_mark_start(); |
550 | static size_t used_at_relocate_end(); |
551 | |
552 | static void print(); |
553 | }; |
554 | |
555 | #endif // SHARE_GC_Z_ZSTAT_HPP |
556 | |