1 /*
   2  * Copyright (c) 2015, 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 package compiler.compilercontrol.jcmd;
  25 
  26 import compiler.compilercontrol.parser.HugeDirectiveUtil;
  27 import compiler.compilercontrol.share.AbstractTestBase;
  28 import compiler.compilercontrol.share.method.MethodDescriptor;
  29 import compiler.compilercontrol.share.scenario.Executor;
  30 import jdk.test.lib.OutputAnalyzer;
  31 import jdk.test.lib.TimeLimitedRunner;
  32 import jdk.test.lib.Utils;
  33 import pool.PoolHelper;
  34 
  35 import java.util.ArrayList;
  36 import java.util.List;
  37 import java.util.Random;
  38 import java.util.concurrent.TimeUnit;
  39 import java.util.stream.Collectors;
  40 
  41 public abstract class StressAddJcmdBase {
  42     private static final int DIRECTIVES_AMOUNT = Integer.getInteger(
  43             "compiler.compilercontrol.jcmd.StressAddJcmdBase.directivesAmount",
  44             200);
  45     private static final int TIMEOUT = Integer.getInteger(
  46             "compiler.compilercontrol.jcmd.StressAddJcmdBase.timeout",
  47             30);
  48     private static final List<MethodDescriptor> DESCRIPTORS = new PoolHelper()
  49             .getAllMethods().stream()
  50                     .map(pair -> AbstractTestBase
  51                             .getValidMethodDescriptor(pair.first))
  52                     .collect(Collectors.toList());
  53     private static final String DIRECTIVE_FILE = "directives.json";
  54     private static final List<String> VM_OPTIONS = new ArrayList<>();
  55     private static final Random RANDOM = Utils.getRandomInstance();
  56 
  57     static {
  58         VM_OPTIONS.add("-Xmixed");
  59         VM_OPTIONS.add("-XX:+UnlockDiagnosticVMOptions");
  60         VM_OPTIONS.add("-XX:+LogCompilation");
  61         VM_OPTIONS.add("-XX:CompilerDirectivesLimit=1001");
  62     }
  63 
  64     /**
  65      * Performs test
  66      */
  67     public void test() {
  68         HugeDirectiveUtil.createHugeFile(DESCRIPTORS, DIRECTIVE_FILE,
  69                 DIRECTIVES_AMOUNT);
  70         Executor executor = new TimeLimitedExecutor();
  71         List<OutputAnalyzer> outputAnalyzers = executor.execute();
  72         outputAnalyzers.get(0).shouldHaveExitValue(0);
  73     }
  74 
  75     /**
  76      * Makes connection to the test VM and performs a diagnostic command
  77      *
  78      * @param pid a pid of the VM under test
  79      * @return true if the test should continue invocation of this method
  80      */
  81     protected abstract boolean makeConnection(int pid);
  82 
  83     /**
  84      * Finish test executions
  85      */
  86     protected void finish() { }
  87 
  88     protected String nextCommand() {
  89         int i = RANDOM.nextInt(JcmdCommand.values().length);
  90         JcmdCommand jcmdCommand = JcmdCommand.values()[i];
  91         switch (jcmdCommand) {
  92             case ADD:
  93                 return jcmdCommand.command + " " + DIRECTIVE_FILE;
  94             case PRINT:
  95             case CLEAR:
  96             case REMOVE:
  97                 return jcmdCommand.command;
  98             default:
  99                 throw new Error("TESTBUG: incorrect command: " + jcmdCommand);
 100         }
 101     }
 102 
 103     private enum JcmdCommand {
 104         ADD("Compiler.directives_add"),
 105         PRINT("Compiler.directives_print"),
 106         CLEAR("Compiler.directives_clear"),
 107         REMOVE("Compiler.directives_remove");
 108 
 109         public final String command;
 110 
 111         JcmdCommand(String command) {
 112             this.command = command;
 113         }
 114     }
 115 
 116     private class TimeLimitedExecutor extends Executor {
 117         public TimeLimitedExecutor() {
 118             /* There are no need to check the state */
 119             super(true, VM_OPTIONS, null, null);
 120         }
 121 
 122         @Override
 123         protected OutputAnalyzer[] executeJCMD(int pid) {
 124             TimeLimitedRunner runner = new TimeLimitedRunner(
 125                     TimeUnit.SECONDS.toMillis(TIMEOUT),
 126                     Utils.TIMEOUT_FACTOR,
 127                     () -> makeConnection(pid));
 128             try {
 129                 runner.call();
 130             } catch (Exception e) {
 131                 throw new Error("Exception during the execution: " + e, e);
 132             }
 133             finish();
 134             return new OutputAnalyzer[0];
 135         }
 136     }
 137 }