btw. @glv,
I enhanced your measure example a bit, even if there are already many out of the box, but as a kind of a show-case and just for the fun doing…
Cheers
— mnse
//-------------------------------------------------------------------------------------------------
// Main sketch
//-------------------------------------------------------------------------------------------------
PerformanceMeasure perf;
void setup() {
size(700, 150);
perf= new PerformanceMeasure();
textAlign(LEFT, CENTER);
textSize(24);
}
void draw() {
background(0);
fill(255, 128, 0);
// Old-School variant
// int which = floor(random(5));
// perf.start("Test"+which);
// delay(floor(random(1000)));
// perf.stop("Test"+which);
// More modern way
perf.measure(String.format("Task%s",floor(random(5))), () -> {
delay(floor(random(1000)));
});
text(perf.consoleAndGetLongestRunner(), 20, height/2);
if (millis() > 60000) {
perf.show();
exit();
}
}
//-------------------------------------------------------------------------------------------------
// PerformanceMeasure stuff
//-------------------------------------------------------------------------------------------------
import java.util.Map;
import java.util.HashMap;
import java.util.AbstractMap;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@FunctionalInterface
interface Task {
void execute();
}
class PerformanceMeasureEntry {
public String name;
public int amountCalls;
public int initialStart;
public int currentStart;
public int lastDuration;
public int overallDuration;
public boolean isActive;
public PerformanceMeasureEntry(String label) {
name=label;
amountCalls=0;
initialStart=-1;
}
public void start() {
amountCalls++;
isActive=true;
int now = millis();
if (initialStart < 0)
initialStart = now;
currentStart=now;
}
public void stop() {
int now = millis();
lastDuration = now - currentStart;
overallDuration = now - initialStart;
isActive=false;
}
@Override
public String toString() {
return String.format("name=%s => calls=[%d,%s], last=[%s], overall=[%s]", name, amountCalls, (isActive==true?"active":"inactice"), formatDuration(lastDuration), formatDuration(overallDuration));
}
public String formatDuration(int ms) {
Duration duration = Duration.of(ms, ChronoUnit.MILLIS);
return Stream.of(
new AbstractMap.SimpleEntry<>("d", duration.toDaysPart()),
new AbstractMap.SimpleEntry<>("h", duration.toHoursPart()),
new AbstractMap.SimpleEntry<>("m", duration.toMinutesPart()),
new AbstractMap.SimpleEntry<>("s", duration.toSecondsPart()),
new AbstractMap.SimpleEntry<>("ms", duration.toMillisPart())
).filter(entry -> entry.getValue().intValue() != 0)
.map(entry -> entry.getValue() + entry.getKey())
.collect(Collectors.joining(" "));
}
}
class PerformanceMeasure {
private Map<String, PerformanceMeasureEntry> measuremap;
public PerformanceMeasure() {
measuremap = new HashMap<>();
}
public void start(String label) {
measuremap.computeIfAbsent(label, a -> {
return new PerformanceMeasureEntry(a);
}).start();
}
public void stop(String label) {
measuremap.values().stream().filter(a -> a.name.equals(label)).forEachOrdered(a -> a.stop());
}
public void measure(String label, Task task) {
start(label);
task.execute();
stop(label);
}
public String consoleAndGetLongestRunner() {
return measuremap.values().stream().sorted((a, b) -> {
return Integer.compare(b.overallDuration, a.overallDuration);
}
).peek(a -> {
println(String.format("[processes=%d] %s", measuremap.size(), a));
}).map(Object::toString).findFirst().orElse("");
}
void show() {
println("--- Ranking ---");
measuremap.values().stream().sorted((a, b) -> {
return Integer.compare(a.overallDuration, b.overallDuration);
}).forEach(PApplet::println);
}
}
Currently writes to stdout, but could easily changed to use a file (short dump)…
[processes=1] name=Task2 => calls=[1,inactice], last=[543ms], overall=[543ms]
[processes=1] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=2] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=3] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=3] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=4] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=5] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=5] name=Task2 => calls=[2,inactice], last=[731ms], overall=[1s 288ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
[processes=5] name=Task3 => calls=[3,inactice], last=[979ms], overall=[5s 489ms]
[processes=5] name=Task3 => calls=[3,inactice], last=[979ms], overall=[5s 489ms]
[processes=5] name=Task0 => calls=[6,inactice], last=[741ms], overall=[5s 903ms]
[processes=5] name=Task3 => calls=[4,inactice], last=[157ms], overall=[6s 946ms]
[processes=5] name=Task3 => calls=[5,inactice], last=[346ms], overall=[7s 293ms]
[processes=5] name=Task1 => calls=[3,inactice], last=[613ms], overall=[8s 271ms]
[processes=5] name=Task1 => calls=[3,inactice], last=[613ms], overall=[8s 271ms]
--- Ranking ---
name=Task2 => calls=[3,inactice], last=[556ms], overall=[4s 258ms]
name=Task0 => calls=[6,inactice], last=[741ms], overall=[5s 903ms]
name=Task4 => calls=[4,inactice], last=[414ms], overall=[7s 273ms]
name=Task3 => calls=[5,inactice], last=[346ms], overall=[7s 293ms]
name=Task1 => calls=[3,inactice], last=[613ms], overall=[8s 271ms]