/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.btrace.profiling;
import com.sun.btrace.Profiler;
import com.sun.btrace.Profiler.Record;
import com.sun.btrace.Profiler.Snapshot;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author jb198685
*/
public class MethodInvocationProfilerTest {
public MethodInvocationProfilerTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
}
@AfterClass
public static void tearDownClass() throws Exception {
}
private volatile Profiler p;
@Before
public void setUp() {
p = new MethodInvocationProfiler(5);
}
@After
public void tearDown() {
p = null;
}
@Test
public void testEmptySnapshot() {
System.out.println("testEmptySnapshot()");
Snapshot s = p.snapshot();
assertNotNull(s);
assertTrue(s.timeStamp > -1);
assertNotNull(s.total);
assertTrue(s.total.length == 0);
}
@Test
public void testOneRecord() {
System.out.println("testOneRecord()");
Record[] expected = new Record[]{new Record("r")};
expected[0].invocations = 1;
expected[0].selfTime = 1000;
expected[0].wallTime = 1000;
p.recordEntry("r");
p.recordExit("r", 1000);
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testOneLevelRecordsNoCompacting() {
System.out.println("testOneLevelRecordsNoCompacting()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 20;
expected[0].selfTime = 200;
expected[0].wallTime = 200;
expected[1].invocations = 20;
expected[1].selfTime = 200;
expected[1].wallTime = 200;
for (int i = 0; i < 20; i++) {
p.recordEntry("r1");
p.recordExit("r1", 10);
p.recordEntry("r2");
p.recordExit("r2", 10);
}
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testOneLevelRecordsNoCompactingMultiThread() throws Exception {
System.out.println("testOneLevelRecordsNoCompactingMultiThread()");
Record r1 = new Record("r1");
Record r2 = new Record("r2");
r1.invocations = 20;
r1.selfTime = 200;
r1.wallTime = 200;
r2.invocations = 20;
r2.selfTime = 200;
r2.wallTime = 200;
Set<Record> expected = new HashSet<Record>();
expected.add(r1);
expected.add(r2);
final Phaser ph = new Phaser(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ph.arriveAndAwaitAdvance();
for (int i = 0; i < 20; i++) {
p.recordEntry("r1");
p.recordExit("r1", 10);
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
ph.arriveAndAwaitAdvance();
for (int i = 0; i < 20; i++) {
p.recordEntry("r2");
p.recordExit("r2", 10);
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
Snapshot s = p.snapshot();
for (Record r : s.total) {
if (!expected.remove(r)) {
fail("Unexpected record: " + r);
}
}
if (!expected.isEmpty()) {
System.err.println("The following records were not matched:");
for (Record r : expected) {
System.err.println(r);
}
fail();
}
}
@Test
public void testOneLevelRecordsCompacting() {
System.out.println("testOneLevelRecordsCompacting()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 200;
expected[0].selfTime = 2000;
expected[0].wallTime = 2000;
expected[1].invocations = 200;
expected[1].selfTime = 2000;
expected[1].wallTime = 2000;
for (int i = 0; i < 200; i++) {
p.recordEntry("r1");
p.recordExit("r1", 10);
p.recordEntry("r2");
p.recordExit("r2", 10);
}
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testOneLevelRecordsCompactingMultiThread() throws Exception {
System.out.println("testOneLevelRecordsCompactingMultiThread()");
Record r1 = new Record("r1");
Record r2 = new Record("r2");
r1.invocations = 200;
r1.selfTime = 2000;
r1.wallTime = 2000;
r2.invocations = 200;
r2.selfTime = 2000;
r2.wallTime = 2000;
Set<Record> expected = new HashSet<Record>();
expected.add(r1);
expected.add(r2);
final Phaser ph = new Phaser(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ph.arriveAndAwaitAdvance();
for (int i = 0; i < 200; i++) {
p.recordEntry("r1");
p.recordExit("r1", 10);
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
ph.arriveAndAwaitAdvance();
for (int i = 0; i < 200; i++) {
p.recordEntry("r2");
p.recordExit("r2", 10);
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
Snapshot s = p.snapshot();
for (Record r : s.total) {
if (!expected.remove(r)) {
fail("Unexpected record: " + r);
}
}
if (!expected.isEmpty()) {
System.err.println("The following records were not matched:");
for (Record r : expected) {
System.err.println(r);
}
fail();
}
}
@Test
public void testTwoLevelsRecordsNoCompacting() {
System.out.println("testTwoLevelsRecordsNoCompacting()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 20;
expected[0].selfTime = 200;
expected[0].wallTime = 400;
expected[1].invocations = 20;
expected[1].selfTime = 200;
expected[1].wallTime = 200;
for (int i = 0; i < 20; i++) {
p.recordEntry("r1");
p.recordEntry("r2");
p.recordExit("r2", 10);
p.recordExit("r1", 20);
}
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testTwoLevelsRecordsCompacting() {
System.out.println("testTwoLevelsRecordsCompacting()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 200;
expected[0].selfTime = 2000;
expected[0].wallTime = 4000;
expected[1].invocations = 200;
expected[1].selfTime = 2000;
expected[1].wallTime = 2000;
for (int i = 0; i < 200; i++) {
p.recordEntry("r1");
p.recordEntry("r2");
p.recordExit("r2", 10);
p.recordExit("r1", 20);
}
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testSnapshotWithMethodsOnStackNoCompacting() {
System.out.println("testSnapshotWithMethodsOnStackNoCompacting()");
Record[] expected = new Record[]{new Record("r3")};
expected[0].invocations = 1;
expected[0].selfTime = 10;
expected[0].wallTime = 10;
p.recordEntry("r1");
p.recordEntry("r2");
p.recordEntry("r3");
p.recordExit("r3", 10);
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testSnapshotWithMethodsOnStackCompacting() {
System.out.println("testSnapshotWithMethodsOnStackCompacting()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 12;
expected[0].selfTime = 120;
expected[0].wallTime = 240;
expected[1].invocations = 13;
expected[1].selfTime = 130;
expected[1].wallTime = 130;
for (int i = 0; i < 12; i++) {
p.recordEntry("r1");
p.recordEntry("r2");
p.recordExit("r2", 10);
p.recordExit("r1", 20);
}
p.recordEntry("r1");
p.recordEntry("r2");
p.recordExit("r2", 10);
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testSnapshotRecursiveWallTime() {
System.out.println("testSnapshotRecursiveWallTime()");
Record[] expected = new Record[]{new Record("r1"), new Record("r2")};
expected[0].invocations = 3;
expected[0].wallTime = 40;
expected[0].selfTime = 30;
expected[1].invocations = 1;
expected[1].wallTime = 30;
expected[1].selfTime = 10;
p.recordEntry("r1");
p.recordEntry("r2");
p.recordEntry("r1");
p.recordExit("r1", 10);
p.recordEntry("r1");
p.recordExit("r1", 10);
p.recordExit("r2", 30);
p.recordExit("r1", 40);
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testSnapshotReset() {
System.out.println("testSnapshotReset()");
Record[] expected = new Record[]{new Record("r1")};
expected[0].invocations = 1;
expected[0].selfTime = 10;
expected[0].wallTime = 10;
p.recordEntry("r1");
p.recordExit("r1", 10);
p.reset();
p.recordEntry("r1");
p.recordExit("r1", 10);
Snapshot s = p.snapshot();
assertArrayEquals(expected, s.total);
}
@Test
public void testSnapshotMultiThread() throws Exception {
System.out.println("testSnapshotResetMultiThread()");
// this is just a sanity test to make sure that invoking "reset()"
// will not throw any exceptions
Record[] expected = new Record[]{new Record("r1")};
expected[0].invocations = 1;
expected[0].selfTime = 10;
expected[0].wallTime = 10;
final AtomicBoolean finished = new AtomicBoolean(false);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
while (!finished.get()) {
p.recordEntry("r1");
p.recordExit("r1", 10);
Thread.sleep(7);
}
} catch (InterruptedException e) {
}
}
});
t.start();
for (int i = 0; i < 50; i++) {
p.snapshot();
Thread.sleep(13);
}
finished.set(true);
t.join();
}
}