/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed 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.
*/
package org.keycloak.testsuite.util;
import org.apache.commons.io.IOUtils;
import org.jboss.logging.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
/**
*
* @author tkyjovsk
*/
public class Timer {
public static final Timer DEFAULT = new Timer();
protected final Logger log = Logger.getLogger(Timer.class);
protected static final File DATA_DIR = new File(PROJECT_BUILD_DIRECTORY, "stats/data");
protected static final File CHARTS_DIR = new File(PROJECT_BUILD_DIRECTORY, "stats/charts");
public static final String DEFAULT_OPERATION = "DEFAULT_OPERATION";
private Long time;
private String operation = DEFAULT_OPERATION;
private final Map<String, List<Long>> stats = new TreeMap<>();
public long elapsedTime() {
long elapsedTime = 0;
if (time == null) {
} else {
elapsedTime = new Date().getTime() - time;
}
return elapsedTime;
}
public void reset() {
reset(operation); // log last operation
}
public void reset(String operation) {
reset(operation, true);
}
public void reset(String newOperation, boolean logOperationOnChange) {
if (time != null) {
if (operation.equals(newOperation) || logOperationOnChange) {
logOperation(operation, elapsedTime());
}
}
time = new Date().getTime();
if (!operation.equals(newOperation)) {
operation = newOperation;
log.info(String.format("Operation '%s' started.", newOperation));
}
}
private void logOperation(String operation, long duration) {
if (!stats.containsKey(operation)) {
stats.put(operation, new ArrayList<Long>());
}
stats.get(operation).add(duration);
log.info(String.format("Operation '%s' took: %s ms", operation, duration));
}
public void clearStats() {
clearStats(true, true, true);
}
public void clearStats(boolean logStats, boolean saveData, boolean saveCharts) {
if (logStats) {
log.info("Timer Statistics:");
for (String op : stats.keySet()) {
long sum = 0;
for (Long duration : stats.get(op)) {
sum += duration;
}
log.info(String.format("Operation '%s' average: %s ms", op, sum / stats.get(op).size()));
}
}
if (PROJECT_BUILD_DIRECTORY.exists()) {
DATA_DIR.mkdirs();
CHARTS_DIR.mkdirs();
for (String op : stats.keySet()) {
if (saveData) {
saveData(op);
}
if (saveCharts) {
saveChart(op);
}
}
}
stats.clear();
}
private void saveData(String op) {
try {
File f = new File(DATA_DIR, op.replace(" ", "_") + ".txt");
if (!f.createNewFile()) {
throw new IOException("Couldn't create file: " + f);
}
OutputStream stream = new BufferedOutputStream(new FileOutputStream(f));
for (Long duration : stats.get(op)) {
IOUtils.write(duration.toString(), stream);
IOUtils.write("\n", stream);
}
stream.flush();
IOUtils.closeQuietly(stream);
} catch (IOException ex) {
log.error("Unable to save data for operation '" + op + "'", ex);
}
}
private void saveChart(String op) {
XYSeries series = new XYSeries(op);
int i = 0;
for (Long duration : stats.get(op)) {
series.add(++i, duration);
}
final XYSeriesCollection data = new XYSeriesCollection(series);
final JFreeChart chart = ChartFactory.createXYLineChart(
op,
"Operations",
"Duration (ms)",
data,
PlotOrientation.VERTICAL,
true,
true,
false
);
try {
ChartUtilities.saveChartAsPNG(
new File(CHARTS_DIR, op.replace(" ", "_") + ".png"),
chart, 640, 480);
} catch (IOException ex) {
log.warn("Unable to save chart for operation '" + op + "'.");
}
}
}