/*
* Copyright (c) 2013-2015 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
// Demo class to generate an example hotspot.log
// run with VM arguments
// -XX:+UnlockDiagnosticVMOptions
// -XX:+TraceClassLoading
// -XX:+LogCompilation
// -XX:+PrintAssembly
// If you prefer Intel assembly syntax to AT&T
// -XX:PrintAssemblyOptions=intel
// Disable TieredCompilation on Java 8 (optional)
// -XX:-TieredCompilation
public class MakeHotSpotLog
{
private static final Logger logger = LoggerFactory.getLogger(MakeHotSpotLog.class);
public MakeHotSpotLog(int iterations)
{
addVariable(iterations);
addConstant(iterations);
randomBranchTest(iterations);
changingBranchTest(iterations);
intrinsicTest(iterations);
intrinsicTestMin(iterations);
tooBigToInline(iterations);
testSort(iterations);
testCallChain(iterations);
testOptimizedVCall(iterations);
long result = testCallChainReturn(iterations);
// ensure code not eliminated by using result
System.out.println("testCallChainReturn: " + result);
testCallChain3();
testLeaf(iterations);
testToUpperCase(iterations);
testLoopUnrolling(iterations);
padMethod();
}
private void addVariable(int iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = add(count, i);
}
System.out.println("addVariable: " + count);
}
private void addConstant(int iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = add(count, 1);
}
System.out.println("addConstant: " + count);
}
private void randomBranchTest(int iterations)
{
long count = 0;
int adds = 0;
int subs = 0;
for (int i = 0; i < iterations; i++)
{
if (Math.random() < 0.5)
{
count = add(count, 1);
adds++;
}
else
{
count = sub(count, 1);
subs++;
}
}
System.out.println("randomBranchTest: " + count + " " + adds + " " + subs);
}
private void changingBranchTest(int iterations)
{
long count = 0;
int adds = 0;
int subs = 0;
for (int i = 0; i < iterations * 2; i++)
{
if (i < iterations)
{
count = add(count, 1);
adds++;
}
else
{
count = sub(count, 1);
subs++;
}
}
System.out.println("changingBranchTest: " + count + " " + adds + " " + subs);
}
private void intrinsicTest(int iterations)
{
long dstSum = 0;
int[] src = new int[] { 1, 2, 3, 4, 5 };
int[] dst = new int[src.length];
for (int i = 0; i < iterations; i++)
{
// x86 has intrinsic for System.arrayCopy
System.arraycopy(src, 0, dst, 0, src.length);
for (int dstVal : dst)
{
dstSum += add(dstSum, dstVal);
}
}
System.out.println("intrinsicTest: " + dstSum);
}
// http://openjdk.5641.n7.nabble.com/Intrinsics-for-Math-min-and-max-td183747.html
private void intrinsicTestMin(int iterations)
{
long sum = 0;
for (int i = 0; i < iterations; i++)
{
// x86 has intrinsic for Math.min
sum = Math.min(i, i + 1);
}
System.out.println("intrinsicTest: " + sum);
}
private long add(long a, long b)
{
return a + b;
}
private long sub(long a, long b)
{
return a - b;
}
public void tooBigToInline(int iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = bigMethod(count, i);
}
System.out.println("tooBigToInline: " + count);
}
private long bigMethod(long count, int i)
{
long a, b, c, d, e, f, g;
a = count;
b = count;
c = count;
d = count;
e = count;
f = count;
g = count;
a += i;
b += i;
c += i;
d += i;
e += i;
f += i;
g += i;
a += 1;
b += 2;
c += 3;
d += 4;
e += 5;
f += 6;
g += 7;
a += i;
b += i;
c += i;
d += i;
e += i;
f += i;
g += i;
a -= 7;
b -= 6;
c -= 5;
d -= 4;
e -= 3;
f -= 2;
g -= 1;
a++;
b++;
c++;
d++;
e++;
f++;
g++;
a /= 2;
b /= 2;
c /= 2;
d /= 2;
e /= 2;
f /= 2;
g /= 2;
long result = a + b + c + d + e + f + g;
return result;
}
private void testSort(long iterations)
{
long sum = 0;
// ensure sort is JIT compiled
for (int i = 0; i < iterations; i++)
{
Random random = new Random();
int count = 1000;
List<Integer> list = new ArrayList<>();
for (int j = 0; j < count; j++)
{
list.add(random.nextInt());
}
Collections.sort(list);
for (int j = 0; j < count; j++)
{
sum += list.get(j);
}
}
System.out.println("list sum: " + sum);
}
private void testCallChain(long iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = chainA1(count);
count = chainB1(count);
}
System.out.println("testCallChain: " + count);
}
/*
* Test bimorphic dispatch is inlined
*/
private void testOptimizedVCall(long iterations)
{
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new LinkedList<>();
List<Integer> ref;
for (int i = 0; i < iterations; i++)
{
if (i % 2 == 0)
{
ref = list1;
}
else
{
ref = list2;
}
ref.add(i);
// list2.add(i);
}
System.out.println("list sizes: " + list1.size() + "/" + list2.size());
}
private long chainA1(long count)
{
return 1 + chainA2(count);
}
private long chainA2(long count)
{
return 2 + chainA3(count);
}
private long chainA3(long count)
{
return 3 + chainA4(count);
}
private long chainA4(long count)
{
// last link will not be inlined
return bigMethod(count, 4);
}
private long chainB1(long count)
{
return chainB2(count) - 1;
}
private long chainB2(long count)
{
return chainB3(count) - 2;
}
private long chainB3(long count)
{
return count - 3;
}
public long testCallChainReturn(long iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = chainA1(count);
count = chainB1(count);
}
return count;
}
private boolean test(int count, int iterations)
{
return count < (0.9 * (double) iterations);
}
private void testCallChain3()
{
long count = 0;
int iterations = 100_000;
for (int i = 0; i < iterations; i++)
{
if (test(i, iterations))
{
count = chainC1(count);
}
else
{
count = chainC2(count);
}
}
System.out.println("testCallChain3: " + count);
}
private long chainC1(long inCount)
{
long count = inCount;
count += chainC2(count);
return chainC3(count);
}
private long chainC2(long count)
{
return 2 + count;
}
private long chainC3(long count)
{
return 3 + count;
}
private void testLeaf(long iterations)
{
long count = 0;
for (int i = 0; i < iterations; i++)
{
count = leaf1(count);
count = leaf2(count);
count = leaf3(count);
count = leaf4(count);
}
System.out.println("testLeaf: " + count);
}
private long leaf1(long count)
{
return count + 1;
}
private long leaf2(long count)
{
return count + 2;
}
private long leaf3(long count)
{
return count + 3;
}
private long leaf4(long count)
{
return count + 4;
}
private void testToUpperCase(long iterations)
{
String sentence = "The quick brown fox jumps over the lazy dog\n";
String[] lcWords = sentence.split(" ");
int wordCount = lcWords.length;
String[] ucWords = new String[wordCount];
for (long l = 0; l < iterations; l++)
{
toUpper(lcWords, ucWords, wordCount);
}
}
private void toUpper(String[] lcWords, String[] ucWords, int wordCount)
{
for (int w = 0; w < wordCount; w++)
{
ucWords[w] = lcWords[w].toUpperCase();
}
}
private void testLoopUnrolling(long iterations)
{
long result = 0;
int toAdd = 4;
for (long l = 0; l < iterations; l++)
{
result += timesTen(toAdd);
}
for (long l = 0; l < iterations; l++)
{
result += timesHundred(toAdd);
}
System.out.println("testLoopUnrolling: " + result);
}
private int timesTen(int number)
{
int result = 0;
for (int i = 0; i < 10; i++)
{
result += number;
}
return result;
}
private int timesHundred(int number)
{
int result = 0;
for (int i = 0; i < 100; i++)
{
result += number;
}
return result;
}
// sacrificial dummy method
// in case hotspot truncates the LogCompilation output
// as it exits and produces a <fragment>
private void padMethod()
{
try
{
Thread.sleep(500);
System.out.println("done");
}
catch (InterruptedException ie)
{
logger.error("", ie);
}
}
public static void main(String[] args)
{
int iterations = 20_000;
if (args.length == 1)
{
try
{
iterations = Integer.parseInt(args[0]);
}
catch (NumberFormatException nfe)
{
System.out.println("usage: MakeHotSpotLog [iterations]");
}
}
new MakeHotSpotLog(iterations);
}
}