Path: blob/master/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp
41149 views
/*1* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "gc/shared/oopStorage.inline.hpp"25#include "gc/shared/oopStorageParState.inline.hpp"26#include "gc/shared/workgroup.hpp"27#include "logging/log.hpp"28#include "logging/logConfiguration.hpp"29#include "memory/allocation.inline.hpp"30#include "memory/iterator.inline.hpp"31#include "runtime/interfaceSupport.inline.hpp"32#include "runtime/os.hpp"33#include "runtime/thread.hpp"34#include "runtime/vmOperations.hpp"35#include "runtime/vmThread.hpp"36#include "utilities/debug.hpp"37#include "utilities/formatBuffer.hpp"38#include "utilities/ostream.hpp"39#include "utilities/ticks.hpp"4041#include "unittest.hpp"4243// This "test" doesn't really verify much. Rather, it's mostly a44// microbenchmark for OopStorage parallel iteration. It executes45// parallel iteration with varying numbers of threads on an storage46// object containing a large number of entries, and logs some stats47// about the distribution and performance of the iteration.4849const uint _max_workers = 10;50static uint _num_workers = 0;51const size_t _storage_entries = 1000000;5253class OopStorageParIterPerf : public ::testing::Test {54public:55OopStorageParIterPerf();56~OopStorageParIterPerf();5758WorkGang* workers() const;5960class VM_ParStateTime;61class Task;62class Closure;6364Tickspan run_task(Task* task, uint nthreads);65void show_task(const Task* task, Tickspan duration, uint nthreads);66void run_test(uint nthreads);6768static WorkGang* _workers;6970OopStorage _storage;71oop* _entries[_storage_entries];72};7374WorkGang* OopStorageParIterPerf::_workers = NULL;7576WorkGang* OopStorageParIterPerf::workers() const {77if (_workers == NULL) {78WorkGang* wg = new WorkGang("OopStorageParIterPerf workers",79_num_workers,80false,81false);82wg->initialize_workers();83wg->update_active_workers(_num_workers);84_workers = wg;85}86return _workers;87}8889OopStorageParIterPerf::OopStorageParIterPerf() :90_storage("Test Storage", mtGC)91{92for (size_t i = 0; i < _storage_entries; ++i) {93_entries[i] = _storage.allocate();94}95_num_workers = MIN2(_max_workers, (uint)os::processor_count());96}9798OopStorageParIterPerf::~OopStorageParIterPerf() {99_storage.release(_entries, ARRAY_SIZE(_entries));100}101102class OopStorageParIterPerf::VM_ParStateTime : public VM_GTestExecuteAtSafepoint {103public:104VM_ParStateTime(WorkGang* workers, AbstractGangTask* task, uint nthreads) :105_workers(workers), _task(task), _nthreads(nthreads)106{}107108void doit() {109_workers->run_task(_task, _nthreads);110}111112private:113WorkGang* _workers;114AbstractGangTask* _task;115uint _nthreads;116};117118class OopStorageParIterPerf::Task : public AbstractGangTask {119typedef OopStorage::ParState<false, false> StateType;120121Tickspan* _worker_times;122StateType _state;123OopClosure* _closure;124125public:126Task(OopStorage* storage, OopClosure* closure, uint nthreads) :127AbstractGangTask("OopStorageParIterPerf::Task"),128_worker_times(NULL),129_state(storage, nthreads),130_closure(closure)131{132Tickspan* wtimes = NEW_C_HEAP_ARRAY(Tickspan, _num_workers, mtInternal);133for (uint i = 0; i < _num_workers; ++i) {134new (&wtimes[i]) Tickspan();135}136_worker_times = wtimes;137}138139~Task() {140FREE_C_HEAP_ARRAY(Tickspan, _worker_times);141}142143virtual void work(uint worker_id) {144Ticks start_time = Ticks::now();145_state.oops_do(_closure);146_worker_times[worker_id] = Ticks::now() - start_time;147}148149const Tickspan* worker_times() const { return _worker_times; }150};151152class OopStorageParIterPerf::Closure : public OopClosure {153public:154virtual void do_oop(oop* p) { guarantee(*p == NULL, "expected NULL"); }155virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }156};157158Tickspan OopStorageParIterPerf::run_task(Task* task, uint nthreads) {159tty->print_cr("Running test with %u threads", nthreads);160VM_ParStateTime op(workers(), task, nthreads);161ThreadInVMfromNative invm(JavaThread::current());162Ticks start_time = Ticks::now();163VMThread::execute(&op);164return Ticks::now() - start_time;165}166167void OopStorageParIterPerf::show_task(const Task* task, Tickspan duration, uint nthreads) {168tty->print_cr("Run test with %u threads: " JLONG_FORMAT, nthreads, duration.value());169const Tickspan* wtimes = task->worker_times();170for (uint i = 0; i < _num_workers; ++i) {171if (wtimes[i] != Tickspan()) {172tty->print_cr(" %u: " JLONG_FORMAT, i, wtimes[i].value());173}174}175tty->cr();176}177178void OopStorageParIterPerf::run_test(uint nthreads) {179if (nthreads <= _num_workers) {180SCOPED_TRACE(err_msg("Running test with %u threads", nthreads).buffer());181Closure closure;182Task task(&_storage, &closure, nthreads);183Tickspan t = run_task(&task, nthreads);184show_task(&task, t, nthreads);185}186}187188TEST_VM_F(OopStorageParIterPerf, test) {189// Enable additional interesting logging.190#define TEST_TAGS oopstorage, blocks, stats191// There isn't an obvious way to capture the old log level so it192// can be restored here, so just use Warning as the "default".193LogLevelType old_level = LogLevel::Warning;194if (log_is_enabled(Debug, TEST_TAGS)) {195old_level = LogLevel::Debug;196} else if (log_is_enabled(Info, TEST_TAGS)) {197old_level = LogLevel::Info;198}199bool debug_enabled = old_level == LogLevel::Debug;200if (!debug_enabled) {201LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(TEST_TAGS));202}203204run_test(1);205run_test(2);206run_test(3);207run_test(4);208run_test(6);209run_test(8);210run_test(10);211212if (!debug_enabled) {213LogConfiguration::configure_stdout(old_level, true, LOG_TAGS(TEST_TAGS));214}215}216217218