blob: aea70c06c25337ce316cdd8359a693741158a0fc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2019 The University of York.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Dimitrios Kolovos - initial API and implementation
* Sina Madani - Refactoring and enhancements
******************************************************************************/
package org.eclipse.epsilon.eol.execute.control;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.epsilon.common.module.ModuleElement;
import static org.eclipse.epsilon.common.util.profiling.BenchmarkUtils.formatDuration;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
public class ExecutionProfiler implements ExecutionController, IExecutionListener {
protected final Map<ModuleElement, Duration> executionTimes = new HashMap<>();
private ModuleElement currentAst;
private long currentStart;
/**
* Determines whether the ModuleElement should be profiled.
*
* @param ast The ModuleElement under scrutiny.
* @param context The context passed to {@link #control(ModuleElement, IEolContext)}
* @return <code>true</code> if the ModuleElement should be profiled, <code>false</code> otherwise.
* @since 1.6
*/
protected boolean screenAST(ModuleElement ast, IEolContext context) {
return true;
}
@Override
public void control(ModuleElement ast, IEolContext context) {
if (ast != null && screenAST(ast, context)) {
currentAst = ast;
currentStart = System.nanoTime();
}
}
@Override
public void done(ModuleElement ast, IEolContext context) {
if (ast == null || ast != currentAst) return;
long execTime = System.nanoTime() - currentStart;
Duration currentDuration = executionTimes.get(ast);
executionTimes.put(
currentAst,
currentDuration != null ? currentDuration.plusNanos(execTime) : Duration.ofNanos(execTime)
);
currentAst = null;
}
@Override
public void dispose() {
executionTimes.clear();
currentAst = null;
currentStart = 0;
}
@Override
public void report(IEolContext context) {
context.getErrorStream().println(this.toString());
}
@Override
public String toString() {
return getExecutionTimes()
.entrySet()
.stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.map(entry -> "'"+entry.getKey()+"' took "+formatDuration(entry.getValue()))
.collect(Collectors.joining(","+System.lineSeparator()));
}
@SafeVarargs
public final void mergeExecutionTimes(Map<? extends ModuleElement, Duration>... others) {
for (Map<? extends ModuleElement, Duration> execTimes : others) {
for (Map.Entry<? extends ModuleElement, Duration> entry : execTimes.entrySet()) {
Duration ruleDuration = executionTimes.get(entry.getKey());
Duration entryDuration = entry.getValue();
executionTimes.put(
entry.getKey(),
ruleDuration != null ? ruleDuration.plus(entryDuration) : entryDuration
);
}
}
}
public Map<ModuleElement, Duration> getExecutionTimes() {
return executionTimes;
}
@Override
public boolean isTerminated() {
return false;
}
@Override
public void aboutToExecute(ModuleElement ast, IEolContext context) {
control(ast, context);
}
@Override
public void finishedExecuting(ModuleElement ast, Object result, IEolContext context) {
done(ast, context);
}
@Override
public void finishedExecutingWithException(ModuleElement ast, EolRuntimeException exception, IEolContext context) {
done(ast, context);
}
}