/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.coverage;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.Writer;
/**
* The class used at runtime to measure the code usage and performance.
*/
public class Profile extends Thread {
private static final boolean LIST_UNVISITED = false;
private static final boolean TRACE = false;
private static final Profile MAIN = new Profile();
private static int top = 15;
private int[] count;
private int[] time;
private boolean stop;
private int maxIndex;
private int lastIndex;
private long lastTime;
private BufferedWriter trace;
private Profile() {
FileReader reader = null;
try {
reader = new FileReader("profile.txt");
LineNumberReader r = new LineNumberReader(reader);
while (r.readLine() != null) {
// nothing - just count lines
}
maxIndex = r.getLineNumber();
count = new int[maxIndex];
time = new int[maxIndex];
lastTime = System.currentTimeMillis();
Runtime.getRuntime().addShutdownHook(this);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
} finally {
closeSilently(reader);
}
}
static {
try {
String s = System.getProperty("profile.top");
if (s != null) {
top = Integer.parseInt(s);
}
} catch (Throwable e) {
// ignore SecurityExceptions
}
}
/**
* This method is called by an instrumented application whenever a line of
* code is executed.
*
* @param i the line number that is executed
*/
public static void visit(int i) {
MAIN.addVisit(i);
}
public void run() {
list();
}
/**
* Start collecting data.
*/
public static void startCollecting() {
MAIN.stop = false;
MAIN.lastTime = System.currentTimeMillis();
}
/**
* Stop collecting data.
*/
public static void stopCollecting() {
MAIN.stop = true;
}
/**
* List all captured data.
*/
public static void list() {
if (MAIN.lastIndex == 0) {
// don't list anything if no statistics collected
return;
}
try {
MAIN.listUnvisited();
MAIN.listTop("MOST CALLED", MAIN.count, top);
MAIN.listTop("MOST TIME USED", MAIN.time, top);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void closeSilently(Reader reader) {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
}
private static void closeSilently(Writer writer) {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
// ignore
}
}
}
private void addVisit(int i) {
if (stop) {
return;
}
long now = System.currentTimeMillis();
if (TRACE) {
if (trace != null) {
int duration = (int) (now - lastTime);
try {
trace.write(i + "\t" + duration + "\r\n");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
count[i]++;
time[lastIndex] += (int) (now - lastTime);
lastTime = now;
lastIndex = i;
}
private void listUnvisited() throws IOException {
printLine('=');
print("NOT COVERED");
printLine('-');
FileReader reader = null;
FileWriter fileWriter = null;
try {
reader = new FileReader("profile.txt");
LineNumberReader r = new LineNumberReader(reader);
fileWriter = new FileWriter("notCovered.txt");
BufferedWriter writer = new BufferedWriter(fileWriter);
int unvisited = 0;
int unvisitedThrow = 0;
for (int i = 0; i < maxIndex; i++) {
String line = r.readLine();
if (count[i] == 0) {
if (!line.endsWith("throw")) {
writer.write(line + "\r\n");
if (LIST_UNVISITED) {
print(line + "\r\n");
}
unvisited++;
} else {
unvisitedThrow++;
}
}
}
int percent = 100 * unvisited / maxIndex;
print("Not covered: " + percent + " % " + " (" + unvisited + " of " + maxIndex + "; throw="
+ unvisitedThrow + ")");
} finally {
closeSilently(fileWriter);
closeSilently(reader);
}
}
private void listTop(String title, int[] list, int max) throws IOException {
printLine('-');
int total = 0;
int totalLines = 0;
for (int j = 0; j < maxIndex; j++) {
int l = list[j];
if (l > 0) {
total += list[j];
totalLines++;
}
}
if (max == 0) {
max = totalLines;
}
print(title);
print("Total: " + total);
printLine('-');
String[] text = new String[max];
int[] index = new int[max];
for (int i = 0; i < max; i++) {
int big = list[0];
int bigIndex = 0;
for (int j = 1; j < maxIndex; j++) {
int l = list[j];
if (l > big) {
big = l;
bigIndex = j;
}
}
list[bigIndex] = -(big + 1);
index[i] = bigIndex;
}
FileReader reader = null;
try {
reader = new FileReader("profile.txt");
LineNumberReader r = new LineNumberReader(reader);
for (int i = 0; i < maxIndex; i++) {
String line = r.readLine();
int k = list[i];
if (k < 0) {
k = -(k + 1);
list[i] = k;
for (int j = 0; j < max; j++) {
if (index[j] == i) {
int percent = 100 * k / total;
text[j] = k + " " + percent + "%: " + line;
}
}
}
}
for (int i = 0; i < max; i++) {
print(text[i]);
}
} finally {
closeSilently(reader);
}
}
private static void print(String s) {
System.out.println(s);
}
private static void printLine(char c) {
for (int i = 0; i < 60; i++) {
System.out.print(c);
}
print("");
}
}