Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp
41149 views
1
/*
2
* Copyright (c) 2018, 2021, 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
#include "precompiled.hpp"
25
#include "gc/shared/oopStorage.inline.hpp"
26
#include "gc/shared/oopStorageParState.inline.hpp"
27
#include "gc/shared/workgroup.hpp"
28
#include "logging/log.hpp"
29
#include "logging/logConfiguration.hpp"
30
#include "memory/allocation.inline.hpp"
31
#include "memory/iterator.inline.hpp"
32
#include "runtime/interfaceSupport.inline.hpp"
33
#include "runtime/os.hpp"
34
#include "runtime/thread.hpp"
35
#include "runtime/vmOperations.hpp"
36
#include "runtime/vmThread.hpp"
37
#include "utilities/debug.hpp"
38
#include "utilities/formatBuffer.hpp"
39
#include "utilities/ostream.hpp"
40
#include "utilities/ticks.hpp"
41
42
#include "unittest.hpp"
43
44
// This "test" doesn't really verify much. Rather, it's mostly a
45
// microbenchmark for OopStorage parallel iteration. It executes
46
// parallel iteration with varying numbers of threads on an storage
47
// object containing a large number of entries, and logs some stats
48
// about the distribution and performance of the iteration.
49
50
const uint _max_workers = 10;
51
static uint _num_workers = 0;
52
const size_t _storage_entries = 1000000;
53
54
class OopStorageParIterPerf : public ::testing::Test {
55
public:
56
OopStorageParIterPerf();
57
~OopStorageParIterPerf();
58
59
WorkGang* workers() const;
60
61
class VM_ParStateTime;
62
class Task;
63
class Closure;
64
65
Tickspan run_task(Task* task, uint nthreads);
66
void show_task(const Task* task, Tickspan duration, uint nthreads);
67
void run_test(uint nthreads);
68
69
static WorkGang* _workers;
70
71
OopStorage _storage;
72
oop* _entries[_storage_entries];
73
};
74
75
WorkGang* OopStorageParIterPerf::_workers = NULL;
76
77
WorkGang* OopStorageParIterPerf::workers() const {
78
if (_workers == NULL) {
79
WorkGang* wg = new WorkGang("OopStorageParIterPerf workers",
80
_num_workers,
81
false,
82
false);
83
wg->initialize_workers();
84
wg->update_active_workers(_num_workers);
85
_workers = wg;
86
}
87
return _workers;
88
}
89
90
OopStorageParIterPerf::OopStorageParIterPerf() :
91
_storage("Test Storage", mtGC)
92
{
93
for (size_t i = 0; i < _storage_entries; ++i) {
94
_entries[i] = _storage.allocate();
95
}
96
_num_workers = MIN2(_max_workers, (uint)os::processor_count());
97
}
98
99
OopStorageParIterPerf::~OopStorageParIterPerf() {
100
_storage.release(_entries, ARRAY_SIZE(_entries));
101
}
102
103
class OopStorageParIterPerf::VM_ParStateTime : public VM_GTestExecuteAtSafepoint {
104
public:
105
VM_ParStateTime(WorkGang* workers, AbstractGangTask* task, uint nthreads) :
106
_workers(workers), _task(task), _nthreads(nthreads)
107
{}
108
109
void doit() {
110
_workers->run_task(_task, _nthreads);
111
}
112
113
private:
114
WorkGang* _workers;
115
AbstractGangTask* _task;
116
uint _nthreads;
117
};
118
119
class OopStorageParIterPerf::Task : public AbstractGangTask {
120
typedef OopStorage::ParState<false, false> StateType;
121
122
Tickspan* _worker_times;
123
StateType _state;
124
OopClosure* _closure;
125
126
public:
127
Task(OopStorage* storage, OopClosure* closure, uint nthreads) :
128
AbstractGangTask("OopStorageParIterPerf::Task"),
129
_worker_times(NULL),
130
_state(storage, nthreads),
131
_closure(closure)
132
{
133
Tickspan* wtimes = NEW_C_HEAP_ARRAY(Tickspan, _num_workers, mtInternal);
134
for (uint i = 0; i < _num_workers; ++i) {
135
new (&wtimes[i]) Tickspan();
136
}
137
_worker_times = wtimes;
138
}
139
140
~Task() {
141
FREE_C_HEAP_ARRAY(Tickspan, _worker_times);
142
}
143
144
virtual void work(uint worker_id) {
145
Ticks start_time = Ticks::now();
146
_state.oops_do(_closure);
147
_worker_times[worker_id] = Ticks::now() - start_time;
148
}
149
150
const Tickspan* worker_times() const { return _worker_times; }
151
};
152
153
class OopStorageParIterPerf::Closure : public OopClosure {
154
public:
155
virtual void do_oop(oop* p) { guarantee(*p == NULL, "expected NULL"); }
156
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
157
};
158
159
Tickspan OopStorageParIterPerf::run_task(Task* task, uint nthreads) {
160
tty->print_cr("Running test with %u threads", nthreads);
161
VM_ParStateTime op(workers(), task, nthreads);
162
ThreadInVMfromNative invm(JavaThread::current());
163
Ticks start_time = Ticks::now();
164
VMThread::execute(&op);
165
return Ticks::now() - start_time;
166
}
167
168
void OopStorageParIterPerf::show_task(const Task* task, Tickspan duration, uint nthreads) {
169
tty->print_cr("Run test with %u threads: " JLONG_FORMAT, nthreads, duration.value());
170
const Tickspan* wtimes = task->worker_times();
171
for (uint i = 0; i < _num_workers; ++i) {
172
if (wtimes[i] != Tickspan()) {
173
tty->print_cr(" %u: " JLONG_FORMAT, i, wtimes[i].value());
174
}
175
}
176
tty->cr();
177
}
178
179
void OopStorageParIterPerf::run_test(uint nthreads) {
180
if (nthreads <= _num_workers) {
181
SCOPED_TRACE(err_msg("Running test with %u threads", nthreads).buffer());
182
Closure closure;
183
Task task(&_storage, &closure, nthreads);
184
Tickspan t = run_task(&task, nthreads);
185
show_task(&task, t, nthreads);
186
}
187
}
188
189
TEST_VM_F(OopStorageParIterPerf, test) {
190
// Enable additional interesting logging.
191
#define TEST_TAGS oopstorage, blocks, stats
192
// There isn't an obvious way to capture the old log level so it
193
// can be restored here, so just use Warning as the "default".
194
LogLevelType old_level = LogLevel::Warning;
195
if (log_is_enabled(Debug, TEST_TAGS)) {
196
old_level = LogLevel::Debug;
197
} else if (log_is_enabled(Info, TEST_TAGS)) {
198
old_level = LogLevel::Info;
199
}
200
bool debug_enabled = old_level == LogLevel::Debug;
201
if (!debug_enabled) {
202
LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(TEST_TAGS));
203
}
204
205
run_test(1);
206
run_test(2);
207
run_test(3);
208
run_test(4);
209
run_test(6);
210
run_test(8);
211
run_test(10);
212
213
if (!debug_enabled) {
214
LogConfiguration::configure_stdout(old_level, true, LOG_TAGS(TEST_TAGS));
215
}
216
}
217
218