/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.harness;
import java.util.ArrayList;
import org.mmtk.harness.options.*;
import org.mmtk.harness.scheduler.AbstractPolicy;
import org.mmtk.harness.scheduler.MMTkThread;
import org.mmtk.harness.vm.*;
import org.mmtk.utility.Log;
import org.mmtk.utility.heap.HeapGrowthManager;
import org.mmtk.utility.options.Options;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.harness.ArchitecturalWord;
import org.vmmagic.unboxed.harness.SimulatedMemory;
import org.vmutil.options.BooleanOption;
/**
* This is the central class for the MMTk test harness.
*/
public class Harness {
/** Used for processing harness and MMTk options */
public static final HarnessOptionSet options = new HarnessOptionSet();
/** Option for the MMTk plan (prefix) to use */
public static final Bits bits = new Bits();
/** Option for the number of collector threads */
public static final Collectors collectors = new Collectors();
/** Option for the MMTk plan (prefix) to use */
public static final Plan plan = new Plan();
/** Option for the initial heap size */
public static final InitHeap initHeap = new InitHeap();
/** Option for the maximum heap size */
public static final MaxHeap maxHeap = new MaxHeap();
/** Option for the maximum heap size */
public static final DumpPcode dumpPcode = new DumpPcode();
/** Trace options */
public static final Trace trace = new Trace();
/** GC stress options */
public static final GcEvery gcEvery = new GcEvery();
/** Scheduler */
public static final Scheduler scheduler = new Scheduler();
/** Scheduler policy */
public static final SchedulerPolicy policy = new SchedulerPolicy();
/** Interval for the fixed scheduler policies */
public static final YieldInterval yieldInterval = new YieldInterval();
/* Parameters for the random scheduler policy */
/** Length of the pseudo-random yield interval sequence */
public static final RandomPolicyLength randomPolicyLength = new RandomPolicyLength();
/** Seed for the pseudo-random yield interval sequence */
public static final RandomPolicySeed randomPolicySeed = new RandomPolicySeed();
/** Minimum value of each entry in the pseudo-random yield interval sequence */
public static final RandomPolicyMin randomPolicyMin = new RandomPolicyMin();
/** Maximum value of each entry in the pseudo-random yield interval sequence */
public static final RandomPolicyMax randomPolicyMax = new RandomPolicyMax();
/** Print yield policy statistics on exit */
public static final PolicyStats policyStats = new PolicyStats();
/** A set of objects to watch */
public static final WatchObject watchObject = new WatchObject();
/** A set of addresses to watch */
public static final WatchAddress watchAddress = new WatchAddress();
/** Timeout on unreasonably long GC */
public static final Timeout timeout = new Timeout();
/** Whether the Harness sanity checker uses the read barrier */
public static final BooleanOption sanityUsesReadBarrier = new SanityUsesReadBarrier();
/** Allocate during collection, to simulate JikesRVM thread iterator objects */
public static final BooleanOption allocDuringCollection = new AllocDuringCollection();
private static boolean isInitialized = false;
/**
* Start up the harness, including creating the global plan and constraints,
* and starting off the collector threads.
*
* After calling this it is possible to begin creating mutator threads.
* @param args Command-line arguments
*/
public static void init(String... args) {
if (isInitialized) {
return;
}
isInitialized = true;
/* Always use the harness factory */
System.setProperty("mmtk.hostjvm", Factory.class.getCanonicalName());
/* Options used for configuring the plan to use */
final ArrayList<String> newArgs = new ArrayList<String>();
/* If the 'bits' arg is specified, parse and apply it first */
for(String arg: args) {
if (arg.startsWith("bits=")) {
options.process(arg);
}
}
ArchitecturalWord.init(Harness.bits.getValue());
for(String arg: args) {
if (!options.process(arg)) newArgs.add(arg);
}
trace.apply();
gcEvery.apply();
org.mmtk.harness.scheduler.Scheduler.init();
for (Address watchAddr : watchAddress.getAddresses()) {
System.err.printf("Setting watch at %s%n",watchAddr);
SimulatedMemory.addWatch(watchAddr);
}
/*
* Perform MMTk initialization in a minimal environment, specifically to
* give it a per-thread 'Log' object
*/
MMTkThread m = new MMTkThread() {
@Override
public void run() {
/* Get MMTk breathing */
ActivePlan.init(plan.getValue());
ActivePlan.plan.boot();
HeapGrowthManager.boot(initHeap.getBytes(), maxHeap.getBytes());
Collector.init(collectors.getValue());
/* Override some defaults */
Options.noFinalizer.setValue(true);
Options.variableSizeHeap.setValue(false);
/* Process command line options */
for(String arg: newArgs) {
if (!options.process(arg)) {
throw new RuntimeException("Invalid option '" + arg + "'");
}
}
/* Check options */
assert Options.noFinalizer.getValue(): "noFinalizer must be true";
/* Finish starting up MMTk */
ActivePlan.plan.postBoot();
ActivePlan.plan.fullyBooted();
Log.flush();
}
};
m.start();
try {
m.join();
} catch (InterruptedException e) {
}
org.mmtk.harness.scheduler.Scheduler.initCollectors();
for (int value : watchObject.getValue()) {
System.out.printf("Setting watch for object %d%n", value);
org.mmtk.harness.vm.ObjectModel.watchObject(value);
}
/* Add exit handler to print yield stats */
if (policyStats.getValue()) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
AbstractPolicy.printStats();
}
});
}
}
/** GC stress - GC on every allocation */
private static boolean gcEveryAlloc = false;
/**
* GC stress - GC after every allocation
*/
public static void setGcEveryAlloc() {
gcEveryAlloc = true;
}
public static boolean gcEveryAlloc() {
return gcEveryAlloc;
}
static void mmtkShutdown() {
MMTkThread m = new MMTkThread() {
@Override
public void run() {
ActivePlan.plan.notifyExit(0);
}
};
m.start();
try {
m.join();
} catch (InterruptedException e) {
}
}
}