1 /*
   2  * Copyright (c) 2013, 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 /* @test TestLargePagesFlags
  25  * @summary Tests how large pages are choosen depending on the given large pages flag combinations.
  26  * @library /testlibrary
  27  * @build com.oracle.java.testlibrary.*
  28  * @run main TestLargePagesFlags
  29  */
  30 
  31 import com.oracle.java.testlibrary.OutputAnalyzer;
  32 import com.oracle.java.testlibrary.Platform;
  33 import com.oracle.java.testlibrary.ProcessTools;
  34 import java.util.ArrayList;
  35 
  36 public class TestLargePagesFlags {
  37 
  38   public static void main(String [] args) throws Exception {
  39     if (!Platform.isLinux()) {
  40       System.out.println("Skipping. TestLargePagesFlags has only been implemented for Linux.");
  41       return;
  42     }
  43 
  44     testUseTransparentHugePages();
  45     testUseHugeTLBFS();
  46     testUseSHM();
  47     testCombinations();
  48   }
  49 
  50   public static void testUseTransparentHugePages() throws Exception {
  51     if (!canUse(UseTransparentHugePages(true))) {
  52       System.out.println("Skipping testUseTransparentHugePages");
  53       return;
  54     }
  55 
  56     // -XX:-UseLargePages overrides all other flags.
  57     new FlagTester()
  58       .use(UseLargePages(false),
  59            UseTransparentHugePages(true))
  60       .expect(
  61            UseLargePages(false),
  62            UseTransparentHugePages(false),
  63            UseHugeTLBFS(false),
  64            UseSHM(false));
  65 
  66     // Explicitly turn on UseTransparentHugePages.
  67     new FlagTester()
  68       .use(UseTransparentHugePages(true))
  69       .expect(
  70            UseLargePages(true),
  71            UseTransparentHugePages(true),
  72            UseHugeTLBFS(false),
  73            UseSHM(false));
  74 
  75     new FlagTester()
  76       .use(UseLargePages(true),
  77            UseTransparentHugePages(true))
  78       .expect(
  79            UseLargePages(true),
  80            UseTransparentHugePages(true),
  81            UseHugeTLBFS(false),
  82            UseSHM(false));
  83 
  84     // Setting a specific large pages flag will turn
  85     // off heuristics to choose large pages type.
  86     new FlagTester()
  87       .use(UseLargePages(true),
  88            UseTransparentHugePages(false))
  89       .expect(
  90            UseLargePages(false),
  91            UseTransparentHugePages(false),
  92            UseHugeTLBFS(false),
  93            UseSHM(false));
  94 
  95     // Don't turn on UseTransparentHugePages
  96     // unless the user explicitly asks for them.
  97     new FlagTester()
  98       .use(UseLargePages(true))
  99       .expect(
 100            UseTransparentHugePages(false));
 101   }
 102 
 103   public static void testUseHugeTLBFS() throws Exception {
 104     if (!canUse(UseHugeTLBFS(true))) {
 105       System.out.println("Skipping testUseHugeTLBFS");
 106       return;
 107     }
 108 
 109     // -XX:-UseLargePages overrides all other flags.
 110     new FlagTester()
 111       .use(UseLargePages(false),
 112            UseHugeTLBFS(true))
 113       .expect(
 114            UseLargePages(false),
 115            UseTransparentHugePages(false),
 116            UseHugeTLBFS(false),
 117            UseSHM(false));
 118 
 119     // Explicitly turn on UseHugeTLBFS.
 120     new FlagTester()
 121       .use(UseHugeTLBFS(true))
 122       .expect(
 123            UseLargePages(true),
 124            UseTransparentHugePages(false),
 125            UseHugeTLBFS(true),
 126            UseSHM(false));
 127 
 128     new FlagTester()
 129       .use(UseLargePages(true),
 130            UseHugeTLBFS(true))
 131       .expect(
 132            UseLargePages(true),
 133            UseTransparentHugePages(false),
 134            UseHugeTLBFS(true),
 135            UseSHM(false));
 136 
 137     // Setting a specific large pages flag will turn
 138     // off heuristics to choose large pages type.
 139     new FlagTester()
 140       .use(UseLargePages(true),
 141            UseHugeTLBFS(false))
 142       .expect(
 143            UseLargePages(false),
 144            UseTransparentHugePages(false),
 145            UseHugeTLBFS(false),
 146            UseSHM(false));
 147 
 148     // Using UseLargePages will default to UseHugeTLBFS large pages.
 149     new FlagTester()
 150       .use(UseLargePages(true))
 151       .expect(
 152            UseLargePages(true),
 153            UseTransparentHugePages(false),
 154            UseHugeTLBFS(true),
 155            UseSHM(false));
 156   }
 157 
 158   public static void testUseSHM() throws Exception {
 159     if (!canUse(UseSHM(true))) {
 160       System.out.println("Skipping testUseSHM");
 161       return;
 162     }
 163 
 164     // -XX:-UseLargePages overrides all other flags.
 165     new FlagTester()
 166       .use(UseLargePages(false),
 167            UseSHM(true))
 168       .expect(
 169            UseLargePages(false),
 170            UseTransparentHugePages(false),
 171            UseHugeTLBFS(false),
 172            UseSHM(false));
 173 
 174     // Explicitly turn on UseSHM.
 175     new FlagTester()
 176       .use(UseSHM(true))
 177       .expect(
 178            UseLargePages(true),
 179            UseTransparentHugePages(false),
 180            UseHugeTLBFS(false),
 181            UseSHM(true)) ;
 182 
 183     new FlagTester()
 184       .use(UseLargePages(true),
 185            UseSHM(true))
 186       .expect(
 187            UseLargePages(true),
 188            UseTransparentHugePages(false),
 189            UseHugeTLBFS(false),
 190            UseSHM(true)) ;
 191 
 192     // Setting a specific large pages flag will turn
 193     // off heuristics to choose large pages type.
 194     new FlagTester()
 195       .use(UseLargePages(true),
 196            UseSHM(false))
 197       .expect(
 198            UseLargePages(false),
 199            UseTransparentHugePages(false),
 200            UseHugeTLBFS(false),
 201            UseSHM(false));
 202 
 203     // Setting UseLargePages can allow the system to choose
 204     // UseHugeTLBFS instead of UseSHM, but never UseTransparentHugePages.
 205     new FlagTester()
 206       .use(UseLargePages(true))
 207       .expect(
 208            UseLargePages(true),
 209            UseTransparentHugePages(false));
 210   }
 211 
 212   public static void testCombinations() throws Exception {
 213     if (!canUse(UseSHM(true)) || !canUse(UseHugeTLBFS(true))) {
 214       System.out.println("Skipping testUseHugeTLBFSAndUseSHMCombination");
 215       return;
 216     }
 217 
 218     // UseHugeTLBFS takes precedence over SHM.
 219 
 220     new FlagTester()
 221       .use(UseLargePages(true),
 222            UseHugeTLBFS(true),
 223            UseSHM(true))
 224       .expect(
 225            UseLargePages(true),
 226            UseTransparentHugePages(false),
 227            UseHugeTLBFS(true),
 228            UseSHM(false));
 229 
 230     new FlagTester()
 231       .use(UseLargePages(true),
 232            UseHugeTLBFS(false),
 233            UseSHM(true))
 234       .expect(
 235            UseLargePages(true),
 236            UseTransparentHugePages(false),
 237            UseHugeTLBFS(false),
 238            UseSHM(true));
 239 
 240     new FlagTester()
 241       .use(UseLargePages(true),
 242            UseHugeTLBFS(true),
 243            UseSHM(false))
 244       .expect(
 245            UseLargePages(true),
 246            UseTransparentHugePages(false),
 247            UseHugeTLBFS(true),
 248            UseSHM(false));
 249 
 250     new FlagTester()
 251       .use(UseLargePages(true),
 252            UseHugeTLBFS(false),
 253            UseSHM(false))
 254       .expect(
 255            UseLargePages(false),
 256            UseTransparentHugePages(false),
 257            UseHugeTLBFS(false),
 258            UseSHM(false));
 259 
 260 
 261     if (!canUse(UseTransparentHugePages(true))) {
 262       return;
 263     }
 264 
 265     // UseTransparentHugePages takes precedence.
 266 
 267     new FlagTester()
 268       .use(UseLargePages(true),
 269            UseTransparentHugePages(true),
 270            UseHugeTLBFS(true),
 271            UseSHM(true))
 272       .expect(
 273            UseLargePages(true),
 274            UseTransparentHugePages(true),
 275            UseHugeTLBFS(false),
 276            UseSHM(false));
 277 
 278     new FlagTester()
 279       .use(UseTransparentHugePages(true),
 280            UseHugeTLBFS(true),
 281            UseSHM(true))
 282       .expect(
 283            UseLargePages(true),
 284            UseTransparentHugePages(true),
 285            UseHugeTLBFS(false),
 286            UseSHM(false));
 287   }
 288 
 289   private static class FlagTester {
 290     private Flag [] useFlags;
 291 
 292     public FlagTester use(Flag... useFlags) {
 293       this.useFlags = useFlags;
 294       return this;
 295     }
 296 
 297     public void expect(Flag... expectedFlags) throws Exception {
 298       if (useFlags == null) {
 299         throw new IllegalStateException("Must run use() before expect()");
 300       }
 301 
 302       OutputAnalyzer output = executeNewJVM(useFlags);
 303 
 304       for (Flag flag : expectedFlags) {
 305         System.out.println("Looking for: " + flag.flagString());
 306         String strValue = output.firstMatch(".* " + flag.name() +  " .* :?= (\\S+).*", 1);
 307 
 308         if (strValue == null) {
 309           throw new RuntimeException("Flag " + flag.name() + " couldn't be found");
 310         }
 311 
 312         if (!flag.value().equals(strValue)) {
 313           throw new RuntimeException("Wrong value for: " + flag.name()
 314                                      + " expected: " + flag.value()
 315                                      + " got: " + strValue);
 316         }
 317       }
 318 
 319       output.shouldHaveExitValue(0);
 320     }
 321   }
 322 
 323   private static OutputAnalyzer executeNewJVM(Flag... flags) throws Exception {
 324     ArrayList<String> args = new ArrayList<>();
 325     for (Flag flag : flags) {
 326       args.add(flag.flagString());
 327     }
 328     args.add("-XX:+PrintFlagsFinal");
 329     args.add("-version");
 330 
 331     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()]));
 332     OutputAnalyzer output = new OutputAnalyzer(pb.start());
 333 
 334     return output;
 335   }
 336 
 337   private static boolean canUse(Flag flag) {
 338     try {
 339       new FlagTester().use(flag).expect(flag);
 340     } catch (Exception e) {
 341       return false;
 342     }
 343 
 344     return true;
 345   }
 346 
 347   private static Flag UseLargePages(boolean value) {
 348     return new BooleanFlag("UseLargePages", value);
 349   }
 350 
 351   private static Flag UseTransparentHugePages(boolean value) {
 352     return new BooleanFlag("UseTransparentHugePages", value);
 353   }
 354 
 355   private static Flag UseHugeTLBFS(boolean value) {
 356     return new BooleanFlag("UseHugeTLBFS", value);
 357   }
 358 
 359   private static Flag UseSHM(boolean value) {
 360     return new BooleanFlag("UseSHM", value);
 361   }
 362 
 363   private static class BooleanFlag implements Flag {
 364     private String name;
 365     private boolean value;
 366 
 367     BooleanFlag(String name, boolean value) {
 368       this.name = name;
 369       this.value = value;
 370     }
 371 
 372     public String flagString() {
 373       return "-XX:" + (value ? "+" : "-") + name;
 374     }
 375 
 376     public String name() {
 377       return name;
 378     }
 379 
 380     public String value() {
 381       return Boolean.toString(value);
 382     }
 383   }
 384 
 385   private static interface Flag {
 386     public String flagString();
 387     public String name();
 388     public String value();
 389   }
 390 }