/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
// Yet another contended object monitor throughput test
// adapted from bug reports
package org.apache.geode.internal.util.concurrent.cm;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.test.junit.categories.IntegrationTest;
import org.apache.geode.util.JSR166TestCase;
@Category(IntegrationTest.class)
public class RLJBarJUnitTest extends JSR166TestCase { // TODO: reformat
public static final int ITERS = 10;
public static boolean OneKey = false; // alloc once or once per iteration
public static boolean UseBar = false;
public static int nThreads = 100;
public static int nUp = 0;
public static int nDead = 0;
public static ReentrantLock bar = new ReentrantLock();
public static Condition barCondition = bar.newCondition();
public static long epoch;
public static ReentrantLock DeathRow = new ReentrantLock();
public static ReentrantLock End = new ReentrantLock();
public static int quiesce = 0;
public static Condition EndCondition = End.newCondition();
@Test
public void testRLJBar() throws Exception {
main(new String[0]);
}
public static void main(String[] args) {
int argix = 0;
if (argix < args.length && args[argix].equals("-o")) {
++argix;
OneKey = true;
System.out.println("OneKey");
}
if (argix < args.length && args[argix].equals("-b")) {
++argix;
UseBar = true;
System.out.println("UseBar");
}
if (argix < args.length && args[argix].equals("-q")) {
++argix;
if (argix < args.length) {
quiesce = Integer.parseInt(args[argix++]);
System.out.println("Quiesce " + quiesce + " msecs");
}
}
for (int k = 0; k < ITERS; ++k)
oneRun();
}
public static void oneRun() {
DeathRow = new ReentrantLock();
End = new ReentrantLock();
EndCondition = End.newCondition();
nDead = nUp = 0;
long cyBase = System.currentTimeMillis();
DeathRow.lock();
try {
for (int i = 1; i <= nThreads; i++) {
new Producer("Producer" + i).start();
}
try {
End.lock();
try {
while (nDead != nThreads)
EndCondition.await();
} finally {
End.unlock();
}
} catch (Exception ex) {
System.out.println("Exception in End: " + ex);
}
} finally {
DeathRow.unlock();
}
System.out.println("Outer time: " + (System.currentTimeMillis() - cyBase));
// Let workers quiesce/exit.
try {
Thread.sleep(1000);
} catch (Exception ex) {
} ;
}
}
class Producer extends Thread {
// private static Hashtable buddiesOnline = new Hashtable();
private static final Map buddiesOnline;
public Producer(String name) {
super(name);
}
static {
try {
buddiesOnline = (Map) JSR166TestCase.MAP_CLASS.newInstance();
} catch (Exception ex) {
throw new ExceptionInInitializerError(ex);
}
}
public void run() {
Object key = null;
final ReentrantLock dr = RLJBarJUnitTest.DeathRow;
final ReentrantLock bar = RLJBarJUnitTest.bar;
final ReentrantLock end = RLJBarJUnitTest.End;
final Condition endCondition = RLJBarJUnitTest.EndCondition;
if (RLJBarJUnitTest.OneKey)
key = new Integer(0); // per-thread v. per iteration
// The barrier has a number of interesting effects:
// 1. It enforces full LWP provisioning on T1.
// (nearly all workers park concurrently).
// 2. It gives the C2 compiler thread(s) a chance to run.
// By transiently quiescing the workings the C2 threads
// might avoid starvation.
//
try {
bar.lock();
try {
++RLJBarJUnitTest.nUp;
if (RLJBarJUnitTest.nUp == RLJBarJUnitTest.nThreads) {
if (RLJBarJUnitTest.quiesce != 0) {
RLJBarJUnitTest.barCondition.await(RLJBarJUnitTest.quiesce * 1000000,
TimeUnit.NANOSECONDS);
}
RLJBarJUnitTest.epoch = System.currentTimeMillis();
RLJBarJUnitTest.barCondition.signalAll();
// System.out.print ("Consensus ") ;
}
if (RLJBarJUnitTest.UseBar) {
while (RLJBarJUnitTest.nUp != RLJBarJUnitTest.nThreads) {
RLJBarJUnitTest.barCondition.await();
}
}
} finally {
bar.unlock();
}
} catch (Exception ex) {
System.out.println("Exception in barrier: " + ex);
}
// Main execution time ... the code being timed ...
// HashTable.get() is highly contended (serial).
for (int loop = 1; loop < 100000; loop++) {
if (!RLJBarJUnitTest.OneKey)
key = new Integer(0);
buddiesOnline.get(key);
}
// Mutator epilog:
// The following code determines if the test will/wont include (measure)
// thread death time.
end.lock();
try {
++RLJBarJUnitTest.nDead;
if (RLJBarJUnitTest.nDead == RLJBarJUnitTest.nUp) {
// System.out.print((System.currentTimeMillis()-RLJBar.epoch) + " ms") ;
endCondition.signalAll();
}
} finally {
end.unlock();
}
dr.lock();
dr.unlock();
}
}