jdk-24/test/hotspot/gtest/gc/g1/test_g1ServiceThread.cpp
Kim Barrett 028e8b3d5e 8137022: Concurrent refinement thread adjustment and (de-)activation suboptimal
8155996: Improve concurrent refinement green zone control
8134303: Introduce -XX:-G1UseConcRefinement

Reviewed-by: sjohanss, tschatzl, iwalulya, ayang
2022-10-20 20:29:19 +00:00

185 lines
5.2 KiB
C++

/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1ServiceThread.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/os.hpp"
#include "utilities/autoRestore.hpp"
#include "unittest.hpp"
class CheckTask : public G1ServiceTask {
int _execution_count;
bool _reschedule;
public:
CheckTask(const char* name) :
G1ServiceTask(name),
_execution_count(0),
_reschedule(true) { }
virtual void execute() {
_execution_count++;
if (_reschedule) {
schedule(100);
}
}
int execution_count() { return _execution_count;}
void set_reschedule(bool reschedule) { _reschedule = reschedule; }
};
static void stop_service_thread(G1ServiceThread* thread) {
ThreadInVMfromNative tvn(JavaThread::current());
thread->stop();
}
// Test that a task that is added during runtime gets run.
TEST_VM(G1ServiceThread, test_add) {
// Create thread and let it start.
G1ServiceThread* st = new G1ServiceThread();
os::naked_short_sleep(500);
CheckTask ct("AddAndRun");
st->register_task(&ct);
// Give CheckTask time to run.
os::naked_short_sleep(500);
stop_service_thread(st);
ASSERT_GT(ct.execution_count(), 0);
}
// Test that a task that is added while the service thread is
// waiting gets run in a timely manner.
TEST_VM(G1ServiceThread, test_add_while_waiting) {
// Make sure default tasks use long intervals so that the service thread
// is doing a long wait for the next execution.
AutoModifyRestore<uintx> f1(G1PeriodicGCInterval, 100000);
// Create thread and let it start.
G1ServiceThread* st = new G1ServiceThread();
os::naked_short_sleep(500);
// Register a new task that should run right away.
CheckTask ct("AddWhileWaiting");
st->register_task(&ct);
// Give CheckTask time to run.
os::naked_short_sleep(500);
stop_service_thread(st);
ASSERT_GT(ct.execution_count(), 0);
}
// Test that a task with negative timeout is not rescheduled.
TEST_VM(G1ServiceThread, test_add_run_once) {
// Create thread and let it start.
G1ServiceThread* st = new G1ServiceThread();
os::naked_short_sleep(500);
// Set reschedule to false to only run once.
CheckTask ct("AddRunOnce");
ct.set_reschedule(false);
st->register_task(&ct);
// Give CheckTask time to run.
os::naked_short_sleep(500);
stop_service_thread(st);
// Should be exactly 1 since negative timeout should
// prevent rescheduling.
ASSERT_EQ(ct.execution_count(), 1);
}
class TestTask : public G1ServiceTask {
jlong _delay_ms;
public:
TestTask(jlong delay) :
G1ServiceTask("TestTask"),
_delay_ms(delay) {
set_time(delay);
}
virtual void execute() {}
void update_time(jlong now, int multiplier) {
set_time(now + (_delay_ms * multiplier));
}
};
TEST_VM(G1ServiceTaskQueue, add_ordered) {
G1ServiceTaskQueue queue;
int num_test_tasks = 5;
for (int i = 1; i <= num_test_tasks; i++) {
// Create tasks with different timeout.
TestTask* task = new TestTask(100 * i);
queue.add_ordered(task);
}
// Now fake a run-loop, that reschedules the tasks using a
// random multiplier.
for (jlong now = 0; now < 1000000; now++) {
// Random multiplier is at least 1 to ensure progress.
int multiplier = 1 + os::random() % 10;
while (queue.front()->time() < now) {
TestTask* task = (TestTask*) queue.front();
queue.remove_front();
// Update delay multiplier.
task->execute();
task->update_time(now, multiplier);
// All additions will verify that the queue is sorted.
queue.add_ordered(task);
}
}
while (!queue.is_empty()) {
G1ServiceTask* task = queue.front();
queue.remove_front();
delete task;
}
}
#ifdef ASSERT
TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, remove_from_empty,
".*Should never try to verify empty queue") {
G1ServiceTaskQueue queue;
queue.remove_front();
}
TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, get_from_empty,
".*Should never try to verify empty queue") {
G1ServiceTaskQueue queue;
queue.front();
}
TEST_VM_ASSERT_MSG(G1ServiceTaskQueue, set_time_in_queue,
".*Not allowed to update time while in queue") {
G1ServiceTaskQueue queue;
TestTask a(100);
queue.add_ordered(&a);
// Not allowed to update time while in queue.
a.update_time(500, 1);
}
#endif