src/share/vm/jfr/leakprofiler/sampling/objectSampler.cpp

changeset 9885
8e875c964f41
parent 9867
150ab470bf7f
equal deleted inserted replaced
9884:1258121876f8 9885:8e875c964f41
1 /* 1 /*
2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
32 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 32 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
33 #include "jfr/support/jfrThreadLocal.hpp" 33 #include "jfr/support/jfrThreadLocal.hpp"
34 #include "jfr/utilities/jfrTryLock.hpp" 34 #include "jfr/utilities/jfrTryLock.hpp"
35 #include "memory/universe.hpp" 35 #include "memory/universe.hpp"
36 #include "oops/oop.inline.hpp" 36 #include "oops/oop.inline.hpp"
37 #include "runtime/atomic.hpp"
38 #include "runtime/orderAccess.hpp"
39 #include "runtime/safepoint.hpp"
37 #include "runtime/thread.hpp" 40 #include "runtime/thread.hpp"
41
42 static ObjectSampler* _instance = NULL;
43
44 static ObjectSampler& instance() {
45 assert(_instance != NULL, "invariant");
46 return *_instance;
47 }
38 48
39 ObjectSampler::ObjectSampler(size_t size) : 49 ObjectSampler::ObjectSampler(size_t size) :
40 _priority_queue(new SamplePriorityQueue(size)), 50 _priority_queue(new SamplePriorityQueue(size)),
41 _list(new SampleList(size)), 51 _list(new SampleList(size)),
42 _last_sweep(JfrTicks::now()), 52 _last_sweep(JfrTicks::now()),
43 _total_allocated(0), 53 _total_allocated(0),
44 _threshold(0), 54 _threshold(0),
45 _size(size), 55 _size(size),
46 _tryLock(0),
47 _dead_samples(false) {} 56 _dead_samples(false) {}
48 57
49 ObjectSampler::~ObjectSampler() { 58 ObjectSampler::~ObjectSampler() {
50 delete _priority_queue; 59 delete _priority_queue;
51 _priority_queue = NULL; 60 _priority_queue = NULL;
52 delete _list; 61 delete _list;
53 _list = NULL; 62 _list = NULL;
54 } 63 }
55 64
56 void ObjectSampler::add(HeapWord* obj, size_t allocated, JavaThread* thread) { 65 bool ObjectSampler::create(size_t size) {
57 assert(thread != NULL, "invariant"); 66 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
58 const traceid thread_id = thread->threadObj() != NULL ? thread->jfr_thread_local()->thread_id() : 0; 67 assert(_instance == NULL, "invariant");
68 _instance = new ObjectSampler(size);
69 return _instance != NULL;
70 }
71
72 bool ObjectSampler::is_created() {
73 return _instance != NULL;
74 }
75
76 ObjectSampler* ObjectSampler::sampler() {
77 assert(is_created(), "invariant");
78 return _instance;
79 }
80
81 void ObjectSampler::destroy() {
82 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
83 if (_instance != NULL) {
84 ObjectSampler* const sampler = _instance;
85 _instance = NULL;
86 delete sampler;
87 }
88 }
89
90 static volatile int _lock = 0;
91
92 ObjectSampler* ObjectSampler::acquire() {
93 assert(is_created(), "invariant");
94 while (Atomic::cmpxchg(1, &_lock, 0) == 1) {}
95 return _instance;
96 }
97
98 void ObjectSampler::release() {
99 assert(is_created(), "invariant");
100 OrderAccess::fence();
101 _lock = 0;
102 }
103
104 static traceid get_thread_id(JavaThread* thread) {
105 assert(thread != NULL, "invariant");
106 if (thread->threadObj() == NULL) {
107 return 0;
108 }
109 const JfrThreadLocal* const tl = thread->jfr_thread_local();
110 assert(tl != NULL, "invariant");
111 if (!tl->has_thread_checkpoint()) {
112 JfrCheckpointManager::create_thread_checkpoint(thread);
113 }
114 assert(tl->has_thread_checkpoint(), "invariant");
115 return tl->thread_id();
116 }
117
118 // Populates the thread local stack frames, but does not add them
119 // to the stacktrace repository (...yet, see stacktrace_id() below)
120 //
121 void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread) {
122 assert(stacktrace != NULL, "invariant");
123 assert(thread != NULL, "invariant");
124 if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
125 JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0);
126 }
127 }
128
129 // We were successful in acquiring the try lock and have been selected for adding a sample.
130 // Go ahead with installing our previously taken stacktrace into the stacktrace repository.
131 //
132 traceid ObjectSampler::stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread) {
133 assert(stacktrace != NULL, "invariant");
134 assert(stacktrace->hash() != 0, "invariant");
135 const traceid stacktrace_id = JfrStackTraceRepository::add(stacktrace, thread);
136 thread->jfr_thread_local()->set_cached_stack_trace_id(stacktrace_id, stacktrace->hash());
137 return stacktrace_id;
138 }
139
140 void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) {
141 assert(thread != NULL, "invariant");
142 assert(is_created(), "invariant");
143
144 const traceid thread_id = get_thread_id(thread);
59 if (thread_id == 0) { 145 if (thread_id == 0) {
60 return; 146 return;
61 } 147 }
62 assert(thread_id != 0, "invariant"); 148 const JfrThreadLocal* const tl = thread->jfr_thread_local();
63 149 JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
64 if (!thread->jfr_thread_local()->has_thread_checkpoint()) { 150 fill_stacktrace(&stacktrace, thread);
65 JfrCheckpointManager::create_thread_checkpoint(thread); 151
66 assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant"); 152 // try enter critical section
67 } 153 JfrTryLock tryLock(&_lock);
68
69 traceid stack_trace_id = 0;
70 unsigned int stack_trace_hash = 0;
71 if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
72 stack_trace_id = JfrStackTraceRepository::record(thread, 0, &stack_trace_hash);
73 thread->jfr_thread_local()->set_cached_stack_trace_id(stack_trace_id, stack_trace_hash);
74 }
75
76 JfrTryLock tryLock(&_tryLock);
77 if (!tryLock.has_lock()) { 154 if (!tryLock.has_lock()) {
78 if (LogJFR && Verbose) tty->print_cr("Skipping old object sample due to lock contention"); 155 if (LogJFR && Verbose) tty->print_cr("Skipping old object sample due to lock contention");
79 return; 156 return;
80 } 157 }
158
159 instance().add(obj, allocated, thread_id, &stacktrace, thread);
160 }
161
162 void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread) {
163 assert(stacktrace != NULL, "invariant");
164 assert(thread_id != 0, "invariant");
165 assert(thread != NULL, "invariant");
166 assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
81 167
82 if (_dead_samples) { 168 if (_dead_samples) {
83 scavenge(); 169 scavenge();
84 assert(!_dead_samples, "invariant"); 170 assert(!_dead_samples, "invariant");
85 } 171 }
98 } else { 184 } else {
99 sample = _list->get(); 185 sample = _list->get();
100 } 186 }
101 187
102 assert(sample != NULL, "invariant"); 188 assert(sample != NULL, "invariant");
103 assert(thread_id != 0, "invariant");
104 sample->set_thread_id(thread_id); 189 sample->set_thread_id(thread_id);
105 sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint()); 190 sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
106 191
107 if (stack_trace_id != 0) { 192 const unsigned int stacktrace_hash = stacktrace->hash();
108 sample->set_stack_trace_id(stack_trace_id); 193 if (stacktrace_hash != 0) {
109 sample->set_stack_trace_hash(stack_trace_hash); 194 sample->set_stack_trace_id(stacktrace_id(stacktrace, thread));
195 sample->set_stack_trace_hash(stacktrace_hash);
110 } 196 }
111 197
112 sample->set_span(allocated); 198 sample->set_span(allocated);
113 sample->set_object((oop)obj); 199 sample->set_object((oop)obj);
114 sample->set_allocated(allocated); 200 sample->set_allocated(allocated);
115 sample->set_allocation_time(JfrTicks::now()); 201 sample->set_allocation_time(JfrTicks::now());
116 sample->set_heap_used_at_last_gc(Universe::get_heap_used_at_last_gc()); 202 sample->set_heap_used_at_last_gc(Universe::get_heap_used_at_last_gc());
117 _priority_queue->push(sample); 203 _priority_queue->push(sample);
118 } 204 }
119 205
120 const ObjectSample* ObjectSampler::last() const { 206 void ObjectSampler::scavenge() {
121 return _list->last();
122 }
123
124 const ObjectSample* ObjectSampler::first() const {
125 return _list->first();
126 }
127
128 const ObjectSample* ObjectSampler::last_resolved() const {
129 return _list->last_resolved();
130 }
131
132 void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
133 _list->set_last_resolved(sample);
134 }
135
136 void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
137 ObjectSample* current = _list->last(); 207 ObjectSample* current = _list->last();
138 while (current != NULL) { 208 while (current != NULL) {
139 ObjectSample* next = current->next(); 209 ObjectSample* next = current->next();
140 if (!current->is_dead()) { 210 if (current->is_dead()) {
141 if (is_alive->do_object_b(current->object())) { 211 remove_dead(current);
142 // The weakly referenced object is alive, update pointer
143 f->do_oop(const_cast<oop*>(current->object_addr()));
144 } else {
145 current->set_dead();
146 _dead_samples = true;
147 }
148 } 212 }
149 current = next; 213 current = next;
150 } 214 }
151 _last_sweep = JfrTicks::now(); 215 _dead_samples = false;
152 } 216 }
153 217
154 void ObjectSampler::remove_dead(ObjectSample* sample) { 218 void ObjectSampler::remove_dead(ObjectSample* sample) {
155 assert(sample != NULL, "invariant"); 219 assert(sample != NULL, "invariant");
156 assert(sample->is_dead(), "invariant"); 220 assert(sample->is_dead(), "invariant");
163 } 227 }
164 _priority_queue->remove(sample); 228 _priority_queue->remove(sample);
165 _list->release(sample); 229 _list->release(sample);
166 } 230 }
167 231
168 void ObjectSampler::scavenge() { 232 void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
169 ObjectSample* current = _list->last(); 233 assert(is_created(), "invariant");
234 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
235 ObjectSampler& sampler = instance();
236 ObjectSample* current = sampler._list->last();
170 while (current != NULL) { 237 while (current != NULL) {
171 ObjectSample* next = current->next(); 238 ObjectSample* next = current->next();
172 if (current->is_dead()) { 239 if (!current->is_dead()) {
173 remove_dead(current); 240 if (is_alive->do_object_b(current->object())) {
241 // The weakly referenced object is alive, update pointer
242 f->do_oop(const_cast<oop*>(current->object_addr()));
243 } else {
244 current->set_dead();
245 sampler._dead_samples = true;
246 }
174 } 247 }
175 current = next; 248 current = next;
176 } 249 }
177 _dead_samples = false; 250 sampler._last_sweep = JfrTicks::now();
251 }
252
253 const ObjectSample* ObjectSampler::last() const {
254 return _list->last();
255 }
256
257 const ObjectSample* ObjectSampler::first() const {
258 return _list->first();
259 }
260
261 const ObjectSample* ObjectSampler::last_resolved() const {
262 return _list->last_resolved();
263 }
264
265 void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
266 _list->set_last_resolved(sample);
178 } 267 }
179 268
180 int ObjectSampler::item_count() const { 269 int ObjectSampler::item_count() const {
181 return _priority_queue->count(); 270 return _priority_queue->count();
182 } 271 }
186 } 275 }
187 276
188 ObjectSample* ObjectSampler::item_at(int index) { 277 ObjectSample* ObjectSampler::item_at(int index) {
189 return const_cast<ObjectSample*>( 278 return const_cast<ObjectSample*>(
190 const_cast<const ObjectSampler*>(this)->item_at(index) 279 const_cast<const ObjectSampler*>(this)->item_at(index)
191 ); 280 );
192 } 281 }
193 282
194 const JfrTicks& ObjectSampler::last_sweep() const { 283 const JfrTicks& ObjectSampler::last_sweep() const {
195 return _last_sweep; 284 return _last_sweep;
196 } 285 }

mercurial