Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/runtime/Thread/TestThreadDumpMonitorContention.java
32285 views
/*1* Copyright (c) 2014, 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/*24* @test25* @bug 803682326* @bug 804628727* @summary Creates two threads contending for the same lock and checks28* whether jstack reports "locked" by more than one thread.29*30* @library /testlibrary31* @run main/othervm TestThreadDumpMonitorContention32*/3334import java.io.BufferedReader;35import java.io.InputStreamReader;36import java.lang.management.ManagementFactory;37import java.lang.management.RuntimeMXBean;38import java.util.ArrayList;39import java.util.List;40import java.util.regex.Matcher;41import java.util.regex.Pattern;4243import com.oracle.java.testlibrary.*;4445public class TestThreadDumpMonitorContention {46// jstack tends to be closely bound to the VM that we are running47// so use getTestJDKTool() instead of getCompileJDKTool() or even48// getJDKTool() which can fall back to "compile.jdk".49final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack");50final static String PID = getPid();5152// looking for header lines with these patterns:53// "ContendingThread-1" #19 prio=5 os_prio=64 tid=0x000000000079c000 nid=0x23 runnable [0xffff80ffb8b87000]54// "ContendingThread-2" #21 prio=5 os_prio=64 tid=0x0000000000780000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000]55// "ContendingThread-2" #24 prio=5 os_prio=64 tid=0x0000000000ec8800 nid=0x31 waiting on condition [0xfffffd7bbfffe000]56final static Pattern HEADER_PREFIX_PATTERN = Pattern.compile(57"^\"ContendingThread-.*");58final static Pattern HEADER_WAITING_PATTERN1 = Pattern.compile(59"^\"ContendingThread-.* waiting for monitor entry .*");60final static Pattern HEADER_WAITING_PATTERN2 = Pattern.compile(61"^\"ContendingThread-.* waiting on condition .*");62final static Pattern HEADER_RUNNABLE_PATTERN = Pattern.compile(63"^\"ContendingThread-.* runnable .*");6465// looking for thread state lines with these patterns:66// java.lang.Thread.State: RUNNABLE67// java.lang.Thread.State: BLOCKED (on object monitor)68final static Pattern THREAD_STATE_PREFIX_PATTERN = Pattern.compile(69" *java\\.lang\\.Thread\\.State: .*");70final static Pattern THREAD_STATE_BLOCKED_PATTERN = Pattern.compile(71" *java\\.lang\\.Thread\\.State: BLOCKED \\(on object monitor\\)");72final static Pattern THREAD_STATE_RUNNABLE_PATTERN = Pattern.compile(73" *java\\.lang\\.Thread\\.State: RUNNABLE");7475// looking for duplicates of this pattern:76// - locked <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1)77final static Pattern LOCK_PATTERN = Pattern.compile(78".* locked \\<.*\\(a TestThreadDumpMonitorContention.*");7980// sanity checking header and thread state lines associated81// with this pattern:82// - waiting to lock <0x000000076ac59e20> (a TestThreadDumpMonitorContention$1)83final static Pattern WAITING_PATTERN = Pattern.compile(84".* waiting to lock \\<.*\\(a TestThreadDumpMonitorContention.*");8586final static Object barrier = new Object();87volatile static boolean done = false;8889static int barrier_cnt = 0;90static int blank_line_match_cnt = 0;91static int error_cnt = 0;92static boolean have_header_line = false;93static boolean have_thread_state_line = false;94static String header_line = null;95static int header_prefix_match_cnt = 0;96static int locked_line_match_cnt = 0;97static String[] locked_match_list = new String[2];98static int n_samples = 15;99static int sum_both_running_cnt = 0;100static int sum_both_waiting_cnt = 0;101static int sum_contended_cnt = 0;102static int sum_locked_hdr_runnable_cnt = 0;103static int sum_locked_hdr_waiting1_cnt = 0;104static int sum_locked_hdr_waiting2_cnt = 0;105static int sum_locked_thr_state_blocked_cnt = 0;106static int sum_locked_thr_state_runnable_cnt = 0;107static int sum_one_waiting_cnt = 0;108static int sum_uncontended_cnt = 0;109static int sum_waiting_hdr_waiting1_cnt = 0;110static int sum_waiting_thr_state_blocked_cnt = 0;111static String thread_state_line = null;112static boolean verbose = false;113static int waiting_line_match_cnt = 0;114115public static void main(String[] args) throws Exception {116if (args.length != 0) {117int arg_i = 0;118if (args[arg_i].equals("-v")) {119verbose = true;120arg_i++;121}122123try {124n_samples = Integer.parseInt(args[arg_i]);125} catch (NumberFormatException nfe) {126System.err.println(nfe);127usage();128}129}130131Runnable runnable = new Runnable() {132public void run() {133synchronized (barrier) {134// let the main thread know we're running135barrier_cnt++;136barrier.notify();137}138while (!done) {139synchronized (this) { }140}141}142};143Thread[] thread_list = new Thread[2];144thread_list[0] = new Thread(runnable, "ContendingThread-1");145thread_list[1] = new Thread(runnable, "ContendingThread-2");146synchronized (barrier) {147thread_list[0].start();148thread_list[1].start();149150// Wait until the contending threads are running so that151// we don't sample any thread init states.152while (barrier_cnt < 2) {153barrier.wait();154}155}156157doSamples();158159done = true;160161thread_list[0].join();162thread_list[1].join();163164if (error_cnt == 0) {165System.out.println("Test PASSED.");166} else {167System.out.println("Test FAILED.");168throw new AssertionError("error_cnt=" + error_cnt);169}170}171172// Reached a blank line which is the end of the173// stack trace without matching either LOCK_PATTERN174// or WAITING_PATTERN. Rare, but it's not an error.175//176// Example:177// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000]178// java.lang.Thread.State: RUNNABLE179// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)180// at java.lang.Thread.run(Thread.java:745)181//182static boolean checkBlankLine(String line) {183if (line.length() == 0) {184blank_line_match_cnt++;185have_header_line = false;186have_thread_state_line = false;187return true;188}189190return false;191}192193// Process the locked line here if we found one.194//195// Example 1:196// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f runnable [0xfffffd7fc1111000]197// java.lang.Thread.State: RUNNABLE198// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)199// - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)200// at java.lang.Thread.run(Thread.java:745)201//202// Example 2:203// "ContendingThread-1" #21 prio=5 os_prio=64 tid=0x00000000007b9000 nid=0x2f waiting for monitor entry [0xfffffd7fc1111000]204// java.lang.Thread.State: BLOCKED (on object monitor)205// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)206// - locked <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)207// at java.lang.Thread.run(Thread.java:745)208//209// Example 3:210// "ContendingThread-2" #24 prio=5 os_prio=64 tid=0x0000000000ec8800 nid=0x31 waiting on condition [0xfffffd7bbfffe000]211// java.lang.Thread.State: RUNNABLE212// JavaThread state: _thread_blocked213// Thread: 0x0000000000ec8800 [0x31] State: _at_safepoint _has_called_back 0 _at_poll_safepoint 0214// JavaThread state: _thread_blocked215// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)216// - locked <0xfffffd7e6d03eb28> (a TestThreadDumpMonitorContention$1)217// at java.lang.Thread.run(Thread.java:745)218//219static boolean checkLockedLine(String line) {220Matcher matcher = LOCK_PATTERN.matcher(line);221if (matcher.matches()) {222if (verbose) {223System.out.println("locked_line='" + line + "'");224}225locked_match_list[locked_line_match_cnt] = new String(line);226locked_line_match_cnt++;227228matcher = HEADER_RUNNABLE_PATTERN.matcher(header_line);229if (matcher.matches()) {230sum_locked_hdr_runnable_cnt++;231} else {232// It's strange, but a locked line can also233// match the HEADER_WAITING_PATTERN{1,2}.234matcher = HEADER_WAITING_PATTERN1.matcher(header_line);235if (matcher.matches()) {236sum_locked_hdr_waiting1_cnt++;237} else {238matcher = HEADER_WAITING_PATTERN2.matcher(header_line);239if (matcher.matches()) {240sum_locked_hdr_waiting2_cnt++;241} else {242System.err.println();243System.err.println("ERROR: header line does " +244"not match runnable or waiting patterns.");245System.err.println("ERROR: header_line='" +246header_line + "'");247System.err.println("ERROR: locked_line='" + line +248"'");249error_cnt++;250}251}252}253254matcher = THREAD_STATE_RUNNABLE_PATTERN.matcher(thread_state_line);255if (matcher.matches()) {256sum_locked_thr_state_runnable_cnt++;257} else {258// It's strange, but a locked line can also259// match the THREAD_STATE_BLOCKED_PATTERN.260matcher = THREAD_STATE_BLOCKED_PATTERN.matcher(261thread_state_line);262if (matcher.matches()) {263sum_locked_thr_state_blocked_cnt++;264} else {265System.err.println();266System.err.println("ERROR: thread state line does not " +267"match runnable or waiting patterns.");268System.err.println("ERROR: " + "thread_state_line='" +269thread_state_line + "'");270System.err.println("ERROR: locked_line='" + line + "'");271error_cnt++;272}273}274275// Have everything we need from this thread stack276// that matches the LOCK_PATTERN.277have_header_line = false;278have_thread_state_line = false;279return true;280}281282return false;283}284285// Process the waiting line here if we found one.286//287// Example:288// "ContendingThread-2" #22 prio=5 os_prio=64 tid=0x00000000007b9800 nid=0x30 waiting for monitor entry [0xfffffd7fc1010000]289// java.lang.Thread.State: BLOCKED (on object monitor)290// at TestThreadDumpMonitorContention$1.run(TestThreadDumpMonitorContention.java:140)291// - waiting to lock <0xfffffd7e6a2912f8> (a TestThreadDumpMonitorContention$1)292// at java.lang.Thread.run(Thread.java:745)293//294static boolean checkWaitingLine(String line) {295Matcher matcher = WAITING_PATTERN.matcher(line);296if (matcher.matches()) {297waiting_line_match_cnt++;298if (verbose) {299System.out.println("waiting_line='" + line + "'");300}301302matcher = HEADER_WAITING_PATTERN1.matcher(header_line);303if (matcher.matches()) {304sum_waiting_hdr_waiting1_cnt++;305} else {306System.err.println();307System.err.println("ERROR: header line does " +308"not match a waiting pattern.");309System.err.println("ERROR: header_line='" + header_line + "'");310System.err.println("ERROR: waiting_line='" + line + "'");311error_cnt++;312}313314matcher = THREAD_STATE_BLOCKED_PATTERN.matcher(thread_state_line);315if (matcher.matches()) {316sum_waiting_thr_state_blocked_cnt++;317} else {318System.err.println();319System.err.println("ERROR: thread state line " +320"does not match a waiting pattern.");321System.err.println("ERROR: thread_state_line='" +322thread_state_line + "'");323System.err.println("ERROR: waiting_line='" + line + "'");324error_cnt++;325}326327// Have everything we need from this thread stack328// that matches the WAITING_PATTERN.329have_header_line = false;330have_thread_state_line = false;331return true;332}333334return false;335}336337static void doSamples() throws Exception {338for (int count = 0; count < n_samples; count++) {339blank_line_match_cnt = 0;340header_prefix_match_cnt = 0;341locked_line_match_cnt = 0;342waiting_line_match_cnt = 0;343// verbose mode or an error has a lot of output so add more space344if (verbose || error_cnt > 0) System.out.println();345System.out.println("Sample #" + count);346347// We don't use the ProcessTools, OutputBuffer or348// OutputAnalyzer classes from the testlibrary because349// we have a complicated multi-line parse to perform350// on a narrow subset of the JSTACK output.351//352// - we only care about stack traces that match353// HEADER_PREFIX_PATTERN; only two should match354// - we care about at most three lines from each stack trace355// - if both stack traces match LOCKED_PATTERN, then that's356// a failure and we report it357// - for a stack trace that matches LOCKED_PATTERN, we verify:358// - the header line matches HEADER_RUNNABLE_PATTERN359// or HEADER_WAITING_PATTERN{1,2}360// - the thread state line matches THREAD_STATE_BLOCKED_PATTERN361// or THREAD_STATE_RUNNABLE_PATTERN362// - we report any mismatches as failures363// - for a stack trace that matches WAITING_PATTERN, we verify:364// - the header line matches HEADER_WAITING_PATTERN1365// - the thread state line matches THREAD_STATE_BLOCKED_PATTERN366// - we report any mismatches as failures367// - the stack traces that match HEADER_PREFIX_PATTERN may368// not match either LOCKED_PATTERN or WAITING_PATTERN369// because we might observe the thread outside of370// monitor operations; this is not considered a failure371//372// When we do observe LOCKED_PATTERN or WAITING_PATTERN,373// then we are checking the header and thread state patterns374// that occurred earlier in the current stack trace that375// matched HEADER_PREFIX_PATTERN. We don't use data from376// stack traces that don't match HEADER_PREFIX_PATTERN and377// we don't mix data between the two stack traces that do378// match HEADER_PREFIX_PATTERN.379//380Process process = new ProcessBuilder(JSTACK, PID)381.redirectErrorStream(true).start();382383BufferedReader reader = new BufferedReader(new InputStreamReader(384process.getInputStream()));385String line;386while ((line = reader.readLine()) != null) {387Matcher matcher = null;388389// process the header line here390if (!have_header_line) {391matcher = HEADER_PREFIX_PATTERN.matcher(line);392if (matcher.matches()) {393header_prefix_match_cnt++;394if (verbose) {395System.out.println();396System.out.println("header='" + line + "'");397}398header_line = new String(line);399have_header_line = true;400continue;401}402continue; // skip until have a header line403}404405// process the thread state line here406if (!have_thread_state_line) {407matcher = THREAD_STATE_PREFIX_PATTERN.matcher(line);408if (matcher.matches()) {409if (verbose) {410System.out.println("thread_state='" + line + "'");411}412thread_state_line = new String(line);413have_thread_state_line = true;414continue;415}416continue; // skip until we have a thread state line417}418419// process the locked line here if we find one420if (checkLockedLine(line)) {421continue;422}423424// process the waiting line here if we find one425if (checkWaitingLine(line)) {426continue;427}428429// process the blank line here if we find one430if (checkBlankLine(line)) {431continue;432}433}434process.waitFor();435436if (header_prefix_match_cnt != 2) {437System.err.println();438System.err.println("ERROR: should match exactly two headers.");439System.err.println("ERROR: header_prefix_match_cnt=" +440header_prefix_match_cnt);441error_cnt++;442}443444if (locked_line_match_cnt == 2) {445if (locked_match_list[0].equals(locked_match_list[1])) {446System.err.println();447System.err.println("ERROR: matching lock lines:");448System.err.println("ERROR: line[0]'" +449locked_match_list[0] + "'");450System.err.println("ERROR: line[1]'" +451locked_match_list[1] + "'");452error_cnt++;453}454}455456if (locked_line_match_cnt == 1) {457// one thread has the lock458if (waiting_line_match_cnt == 1) {459// and the other contended for it460sum_contended_cnt++;461} else {462// and the other is just running463sum_uncontended_cnt++;464}465} else if (waiting_line_match_cnt == 1) {466// one thread is waiting467sum_one_waiting_cnt++;468} else if (waiting_line_match_cnt == 2) {469// both threads are waiting470sum_both_waiting_cnt++;471} else {472// both threads are running473sum_both_running_cnt++;474}475476// slight delay between jstack launches477Thread.sleep(500);478}479480if (error_cnt != 0) {481// skip summary info since there were errors482return;483}484485System.out.println("INFO: Summary for all samples:");486System.out.println("INFO: both_running_cnt=" + sum_both_running_cnt);487System.out.println("INFO: both_waiting_cnt=" + sum_both_waiting_cnt);488System.out.println("INFO: contended_cnt=" + sum_contended_cnt);489System.out.println("INFO: one_waiting_cnt=" + sum_one_waiting_cnt);490System.out.println("INFO: uncontended_cnt=" + sum_uncontended_cnt);491System.out.println("INFO: locked_hdr_runnable_cnt=" +492sum_locked_hdr_runnable_cnt);493System.out.println("INFO: locked_hdr_waiting1_cnt=" +494sum_locked_hdr_waiting1_cnt);495System.out.println("INFO: locked_hdr_waiting2_cnt=" +496sum_locked_hdr_waiting2_cnt);497System.out.println("INFO: locked_thr_state_blocked_cnt=" +498sum_locked_thr_state_blocked_cnt);499System.out.println("INFO: locked_thr_state_runnable_cnt=" +500sum_locked_thr_state_runnable_cnt);501System.out.println("INFO: waiting_hdr_waiting1_cnt=" +502sum_waiting_hdr_waiting1_cnt);503System.out.println("INFO: waiting_thr_state_blocked_cnt=" +504sum_waiting_thr_state_blocked_cnt);505506if (sum_contended_cnt == 0) {507System.err.println("WARNING: the primary scenario for 8036823" +508" has not been exercised by this test run.");509}510}511512// This helper relies on RuntimeMXBean.getName() returning a string513// that looks like this: 5436@mt-haku514//515// The testlibrary has tryFindJvmPid(), but that uses a separate516// process which is much more expensive for finding out your own PID.517//518static String getPid() {519RuntimeMXBean runtimebean = ManagementFactory.getRuntimeMXBean();520String vmname = runtimebean.getName();521int i = vmname.indexOf('@');522if (i != -1) {523vmname = vmname.substring(0, i);524}525return vmname;526}527528static void usage() {529System.err.println("Usage: " +530"java TestThreadDumpMonitorContention [-v] [n_samples]");531System.exit(1);532}533}534535536