Skip to content
Permalink
Browse files
8252219: C2: Randomize IGVN worklist for stress testing
Add 'StressIGVN' option to let C2 randomize IGVN worklist order. When enabled,
the worklist is shuffled before each main run of the IGVN loop. Also add
'StressSeed=N' option to specify the seed. If the seed is not specified, a
random one is generated. In either case, the seed is logged if 'LogCompilation'
is enabled. The new options are declared as production+diagnostic for
consistency with the existing 'StressLCM' and 'StressGCM' options.

Reviewed-by: kvn, chagedorn, thartmann
  • Loading branch information
robcasloz authored and TobiHartmann committed Sep 28, 2020
1 parent 625a935 commit fed3636f12b442ee80375025301f137c950625c4
@@ -49,6 +49,14 @@
product(bool, StressGCM, false, DIAGNOSTIC, \
"Randomize instruction scheduling in GCM") \
\
product(bool, StressIGVN, false, DIAGNOSTIC, \
"Randomize worklist traversal in IGVN") \
\
product(uint, StressSeed, 0, DIAGNOSTIC, \
"Seed for IGVN stress testing (if unset, a random one is " \
"generated") \
range(0, max_juint) \
\
develop(bool, StressMethodHandleLinkerInlining, false, \
"Stress inlining through method handle linkers") \
\
@@ -70,6 +70,7 @@
#include "opto/type.hpp"
#include "opto/vectornode.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
@@ -523,6 +524,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
#endif
_has_method_handle_invokes(false),
_clinit_barrier_on_entry(false),
_stress_seed(0),
_comp_arena(mtCompiler),
_barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())),
_env(ci_env),
@@ -727,6 +729,18 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
if (failing()) return;
NOT_PRODUCT( verify_graph_edges(); )

// If IGVN is randomized for stress testing, seed random number
// generation and log the seed for repeatability.
if (StressIGVN) {
_stress_seed = FLAG_IS_DEFAULT(StressSeed) ?
static_cast<uint>(Ticks::now().nanoseconds()) : StressSeed;
if (_log != NULL) {
_log->elem("stress_test seed='%u'", _stress_seed);
} else if (FLAG_IS_DEFAULT(StressSeed)) {
tty->print_cr("Warning: set +LogCompilation to log the seed.");
}
}

// Now optimize
Optimize();
if (failing()) return;
@@ -809,6 +823,7 @@ Compile::Compile( ciEnv* ci_env,
#endif
_has_method_handle_invokes(false),
_clinit_barrier_on_entry(false),
_stress_seed(0),
_comp_arena(mtCompiler),
_barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())),
_env(ci_env),
@@ -4436,8 +4451,13 @@ void Compile::remove_speculative_types(PhaseIterGVN &igvn) {
}
}

// Auxiliary method to support randomized stressing/fuzzing.
//
// Auxiliary methods to support randomized stressing/fuzzing.

int Compile::random() {
_stress_seed = os::next_random(_stress_seed);
return static_cast<int>(_stress_seed);
}

// This method can be called the arbitrary number of times, with current count
// as the argument. The logic allows selecting a single candidate from the
// running list of candidates as follows:
@@ -300,6 +300,7 @@ class Compile : public Phase {
RTMState _rtm_state; // State of Restricted Transactional Memory usage
int _loop_opts_cnt; // loop opts round
bool _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry
uint _stress_seed; // Seed for stress testing

// Compilation environment.
Arena _comp_arena; // Arena with lifetime equivalent to Compile
@@ -1136,7 +1137,8 @@ class Compile : public Phase {
// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);

// Auxiliary method for randomized fuzzing/stressing
// Auxiliary methods for randomized fuzzing/stressing
int random();
static bool randomized_select(int count);

// supporting clone_map
@@ -975,6 +975,14 @@ PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn),
}
}

void PhaseIterGVN::shuffle_worklist() {
if (_worklist.size() < 2) return;
for (uint i = _worklist.size() - 1; i >= 1; i--) {
uint j = C->random() % (i + 1);
swap(_worklist.adr()[i], _worklist.adr()[j]);
}
}

#ifndef PRODUCT
void PhaseIterGVN::verify_step(Node* n) {
if (VerifyIterativeGVN) {
@@ -1127,6 +1135,9 @@ void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) {
void PhaseIterGVN::optimize() {
DEBUG_ONLY(uint num_processed = 0;)
NOT_PRODUCT(init_verifyPhaseIterGVN();)
if (StressIGVN) {
shuffle_worklist();
}

uint loop_count = 0;
// Pull from worklist and transform the node. If the node has changed,
@@ -458,6 +458,9 @@ class PhaseIterGVN : public PhaseGVN {

protected:

// Shuffle worklist, for stress testing
void shuffle_worklist();

virtual const Type* saturate(const Type* new_type, const Type* old_type,
const Type* limit_type) const;
// Usually returns new_type. Returns old_type if new_type is only a slight
@@ -815,7 +815,7 @@ void os::init_random(unsigned int initval) {
}


static int random_helper(unsigned int rand_seed) {
int os::next_random(unsigned int rand_seed) {
/* standard, well-known linear congruential random generator with
* next_rand = (16807*seed) mod (2**31-1)
* see
@@ -853,7 +853,7 @@ int os::random() {
// Make updating the random seed thread safe.
while (true) {
unsigned int seed = _rand_seed;
unsigned int rand = random_helper(seed);
unsigned int rand = next_random(seed);
if (Atomic::cmpxchg(&_rand_seed, seed, rand) == seed) {
return static_cast<int>(rand);
}
@@ -765,6 +765,7 @@ class os: AllStatic {

// random number generation
static int random(); // return 32bit pseudorandom number
static int next_random(unsigned int rand_seed); // pure version of random()
static void init_random(unsigned int initval); // initialize random sequence

// Structured OS Exception support
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, 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.
*/

/*
* @test
* @bug 8252219
* @requires vm.compiler2.enabled
* @summary Tests that different combinations of the options -XX:+StressIGVN and
* -XX:StressSeed=N are accepted.
* @run main/othervm -XX:+StressIGVN
* compiler.arguments.TestStressIGVNOptions
* @run main/othervm -XX:+StressIGVN -XX:StressSeed=42
* compiler.arguments.TestStressIGVNOptions
*/

package compiler.arguments;

public class TestStressIGVNOptions {

static public void main(String[] args) {
System.out.println("Passed");
}
}

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2020, 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.
*/

package compiler.debug;

import java.nio.file.Paths;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Asserts;

/*
* @test
* @bug 8252219
* @requires vm.compiler2.enabled
* @summary Tests that using -XX:+StressIGVN without -XX:StressSeed=N generates
* and logs a random seed.
* @library /test/lib /
* @run driver compiler.debug.TestGenerateStressSeed
*/

public class TestGenerateStressSeed {

static void sum(int n) {
int acc = 0;
for (int i = 0; i < n; i++) acc += i;
System.out.println(acc);
}

public static void main(String[] args) throws Exception {
if (args.length == 0) {
String className = TestGenerateStressSeed.class.getName();
String log = "test.log";
String[] procArgs = {
"-Xcomp", "-XX:-TieredCompilation",
"-XX:CompileOnly=" + className + "::sum", "-XX:+StressIGVN",
"-XX:+LogCompilation", "-XX:LogFile=" + log, className, "10"};
ProcessTools.createJavaProcessBuilder(procArgs).start().waitFor();
new OutputAnalyzer(Paths.get(log))
.shouldContain("stress_test seed");
} else if (args.length > 0) {
sum(Integer.parseInt(args[0]));
}
}
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, 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.
*/

package compiler.debug;

import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.Asserts;

/*
* @test
* @bug 8252219
* @requires vm.compiler2.enabled
* @summary Tests that compilations with the same seed yield the same IGVN
* trace, and compilations with different seeds yield different IGVN
* traces.
* @library /test/lib /
* @run driver compiler.debug.TestStressIGVN
*/

public class TestStressIGVN {

static String igvnTrace(int stressSeed) throws Exception {
String className = TestStressIGVN.class.getName();
String[] procArgs = {
"-Xcomp", "-XX:-TieredCompilation",
"-XX:CompileOnly=" + className + "::sum", "-XX:+TraceIterativeGVN",
"-XX:+StressIGVN", "-XX:StressSeed=" + stressSeed,
className, "10"};
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs);
OutputAnalyzer out = new OutputAnalyzer(pb.start());
return out.getStdout();
}

static void sum(int n) {
int acc = 0;
for (int i = 0; i < n; i++) acc += i;
System.out.println(acc);
}

public static void main(String[] args) throws Exception {
if (args.length == 0) {
Asserts.assertEQ(igvnTrace(10), igvnTrace(10),
"got different IGVN traces for the same seed");
Asserts.assertNE(igvnTrace(10), igvnTrace(20),
"got the same IGVN trace for different seeds");
} else if (args.length > 0) {
sum(Integer.parseInt(args[0]));
}
}
}

1 comment on commit fed3636

@bridgekeeper

This comment has been minimized.

Copy link

@bridgekeeper bridgekeeper bot commented on fed3636 Sep 28, 2020

Please sign in to comment.