Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp
41155 views
1
/*
2
* Copyright (c) 2019, 2020, 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
25
#include "precompiled.hpp"
26
#include "jfr/jfrEvents.hpp"
27
#include "jfr/leakprofiler/chains/edgeStore.hpp"
28
#include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp"
29
#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"
30
#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
31
#include "jfr/leakprofiler/sampling/objectSample.hpp"
32
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
33
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
34
#include "logging/log.hpp"
35
#include "memory/resourceArea.hpp"
36
#include "oops/markWord.hpp"
37
#include "oops/oop.inline.hpp"
38
#include "runtime/mutexLocker.hpp"
39
#include "runtime/thread.inline.hpp"
40
#include "runtime/vmThread.hpp"
41
42
EventEmitter::EventEmitter(const JfrTicks& start_time, const JfrTicks& end_time) :
43
_start_time(start_time),
44
_end_time(end_time),
45
_thread(Thread::current()),
46
_jfr_thread_local(_thread->jfr_thread_local()),
47
_thread_id(_thread->jfr_thread_local()->thread_id()) {}
48
49
EventEmitter::~EventEmitter() {
50
// restore / reset thread local stack trace and thread id
51
_jfr_thread_local->set_thread_id(_thread_id);
52
_jfr_thread_local->clear_cached_stack_trace();
53
}
54
55
void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all, bool skip_bfs) {
56
assert(sampler != NULL, "invariant");
57
ResourceMark rm;
58
EdgeStore edge_store;
59
if (cutoff_ticks <= 0) {
60
// no reference chains
61
JfrTicks time_stamp = JfrTicks::now();
62
EventEmitter emitter(time_stamp, time_stamp);
63
emitter.write_events(sampler, &edge_store, emit_all);
64
return;
65
}
66
// events emitted with reference chains require a safepoint operation
67
PathToGcRootsOperation op(sampler, &edge_store, cutoff_ticks, emit_all, skip_bfs);
68
VMThread::execute(&op);
69
}
70
71
size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) {
72
assert(_thread == Thread::current(), "invariant");
73
assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant");
74
assert(object_sampler != NULL, "invariant");
75
assert(edge_store != NULL, "invariant");
76
77
const jlong last_sweep = emit_all ? max_jlong : ObjectSampler::last_sweep();
78
size_t count = 0;
79
80
// First pass associates a live sample with its immediate edge
81
// in preparation for writing checkpoint information.
82
const ObjectSample* current = object_sampler->first();
83
while (current != NULL) {
84
ObjectSample* prev = current->prev();
85
if (current->is_alive_and_older_than(last_sweep)) {
86
link_sample_with_edge(current, edge_store);
87
++count;
88
}
89
current = prev;
90
}
91
if (count > 0) {
92
// We need to serialize the associated checkpoints and potential chains
93
// before writing the events to ensure constants are available for resolution
94
// at the time old object sample events appear in the stream.
95
ObjectSampleCheckpoint::write(object_sampler, edge_store, emit_all, _thread);
96
97
// Now we are ready to write the events
98
const ObjectSample* current = object_sampler->first();
99
while (current != NULL) {
100
ObjectSample* prev = current->prev();
101
if (current->is_alive_and_older_than(last_sweep)) {
102
write_event(current, edge_store);
103
}
104
current = prev;
105
}
106
}
107
return count;
108
}
109
110
static int array_size(const oop object) {
111
assert(object != NULL, "invariant");
112
if (object->is_array()) {
113
return arrayOop(object)->length();
114
}
115
return min_jint;
116
}
117
118
void EventEmitter::link_sample_with_edge(const ObjectSample* sample, EdgeStore* edge_store) {
119
assert(sample != NULL, "invariant");
120
assert(!sample->is_dead(), "invariant");
121
assert(edge_store != NULL, "invariant");
122
if (SafepointSynchronize::is_at_safepoint()) {
123
if (!sample->object()->mark().is_marked()) {
124
// Associated with an edge (chain) already during heap traversal.
125
return;
126
}
127
}
128
// In order to dump out a representation of the event
129
// even though the sample object was found not reachable / too long to reach,
130
// we need to register a top level edge.
131
edge_store->put(UnifiedOopRef::encode_in_native(sample->object_addr()));
132
}
133
134
void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store) {
135
assert(sample != NULL, "invariant");
136
assert(!sample->is_dead(), "invariant");
137
assert(edge_store != NULL, "invariant");
138
assert(_jfr_thread_local != NULL, "invariant");
139
140
traceid gc_root_id = 0;
141
const Edge* edge = NULL;
142
if (SafepointSynchronize::is_at_safepoint()) {
143
if (!sample->object()->mark().is_marked()) {
144
edge = (const Edge*)(sample->object())->mark().to_pointer();
145
}
146
}
147
if (edge == NULL) {
148
edge = edge_store->get(UnifiedOopRef::encode_in_native(sample->object_addr()));
149
} else {
150
gc_root_id = edge_store->gc_root_id(edge);
151
}
152
assert(edge != NULL, "invariant");
153
const traceid object_id = edge_store->get_id(edge);
154
assert(object_id != 0, "invariant");
155
156
Tickspan object_age = Ticks(_start_time.value()) - sample->allocation_time();
157
158
EventOldObjectSample e(UNTIMED);
159
e.set_starttime(_start_time);
160
e.set_endtime(_end_time);
161
e.set_allocationTime(sample->allocation_time());
162
e.set_objectAge(object_age);
163
e.set_lastKnownHeapUsage(sample->heap_used_at_last_gc());
164
e.set_object(object_id);
165
e.set_arrayElements(array_size(edge->pointee()));
166
e.set_root(gc_root_id);
167
168
// Temporarily assigning both the stack trace id and thread id
169
// onto the thread local data structure of the emitter thread (for the duration
170
// of the commit() call). This trick provides a means to override
171
// the event generation mechanism by injecting externally provided id's.
172
// At this particular location, it allows us to emit an old object event
173
// supplying information from where the actual sampling occurred.
174
_jfr_thread_local->set_cached_stack_trace_id(sample->stack_trace_id());
175
assert(sample->has_thread(), "invariant");
176
_jfr_thread_local->set_thread_id(sample->thread_id());
177
e.commit();
178
}
179
180