org.nuiton.jaxx.compiler.JAXXProfile Maven / Gradle / Ivy
The newest version!
/*
* #%L
* JAXX :: Compiler
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.jaxx.compiler;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import org.nuiton.jaxx.compiler.tasks.CompileFirstPassTask;
import org.nuiton.jaxx.compiler.tasks.CompileSecondPassTask;
import org.nuiton.jaxx.compiler.tasks.FinalizeTask;
import org.nuiton.jaxx.compiler.tasks.GenerateTask;
import org.nuiton.jaxx.compiler.tasks.StyleSheetTask;
import io.ultreia.java4all.lang.Strings;
/**
* Pour profiler les temps d'execution pendant une compilation.
*
* @author Tony Chemit - [email protected]
* @since 1.3
*/
public class JAXXProfile {
void clear() {
entries.clear();
compilers.clear();
}
protected class CompilerEntry {
final JAXXCompiler compiler;
final SortedMap times;
public CompilerEntry(JAXXCompiler compiler) {
this.compiler = compiler;
times = new TreeMap<>();
}
}
public static class ProfileResult {
final long min;
final long max;
long average;
long total;
final Map delta;
final List times;
ProfileResult(Map delta) {
this.delta = delta;
times = new ArrayList<>(delta.values());
Collections.sort(times);
min = times.get(0);
max = times.get(times.size() - 1);
total = 0;
average = 0;
for (Long t : times) {
total += t;
}
average = total / times.size();
}
public long getTime(JAXXCompiler compiler) {
for (Entry entry : delta.entrySet()) {
if (entry.getKey().equals(compiler)) {
return entry.getValue();
}
}
throw new IllegalArgumentException("could not find time for compiler " + compiler);
}
public void clear() {
times.clear();
delta.clear();
}
public JAXXCompiler getCompiler(Long l) {
for (Entry entry : delta.entrySet()) {
if (entry.getValue().equals(l)) {
return entry.getKey();
}
}
throw new IllegalArgumentException("could not find compiler for time " + l);
}
}
final SortedMap entries;
final List compilers;
public JAXXProfile() {
compilers = new ArrayList<>();
entries = new TreeMap<>();
}
public void addTime(JAXXCompiler compiler, String key) {
CompilerEntry e = getEntry(compiler);
e.times.put(key, System.nanoTime());
}
public Map getDelta(String keyOne, String keyTwo) {
Map result = new HashMap<>();
for (Map.Entry e : entries.entrySet()) {
JAXXCompiler c = getCompiler(e.getKey());
CompilerEntry entry = e.getValue();
Long t0 = entry.times.get(keyOne);
Long t1 = entry.times.get(keyTwo);
if (t0 == null) {
throw new NullPointerException(
"could not find time for " + keyOne +
" on compiler " + c.getOutputClassName());
}
if (t1 == null) {
throw new NullPointerException(
"could not find time for " + keyTwo +
" on compiler " + c.getOutputClassName());
}
long delta = t1 - t0;
result.put(c, delta);
}
return result;
}
public ProfileResult newProfileResult(String name) {
ProfileResult result;
Map delta =
getDelta(name + "_start", name + "_end");
result = new ProfileResult(delta);
return result;
}
public ProfileResult newProfileResult(ProfileResult... toCumul) {
ProfileResult result;
Map delta = new HashMap<>();
for (JAXXCompiler c : compilers) {
long total = 0;
for (ProfileResult cumul : toCumul) {
long time = cumul.getTime(c);
total += time;
}
delta.put(c, total);
}
result = new ProfileResult(delta);
return result;
}
public StringBuilder computeProfileReport() {
StringBuilder buffer = new StringBuilder();
if (compilers.isEmpty()) {
return buffer.append("no jaxx file treated, no profile report");
}
// compute max size of the fqn of a compiled file
int maxLength = 0;
for (JAXXCompiler compiler : compilers) {
int l = compiler.getOutputClassName().length();
if (l > maxLength) {
maxLength = l;
}
}
ProfileResult cfp = newProfileResult(CompileFirstPassTask.TASK_NAME);
ProfileResult csp = newProfileResult(CompileSecondPassTask.TASK_NAME);
ProfileResult ssp = newProfileResult(StyleSheetTask.TASK_NAME);
ProfileResult fp = newProfileResult(FinalizeTask.TASK_NAME);
ProfileResult gp = newProfileResult(GenerateTask.TASK_NAME);
ProfileResult total = newProfileResult(cfp, csp, ssp, fp, gp);
String reportPattern = "\n|%1$-" + maxLength +
"s|%2$15s|%3$15s|%4$15s|%5$15s|%6$15s|%7$15s|";
char[] tmpC = new char[maxLength];
Arrays.fill(tmpC, '-');
String line = String.format(reportPattern,
new String(tmpC),
"---------------",
"---------------",
"---------------",
"---------------",
"---------------",
"---------------");
buffer.append(line);
buffer.append(String.format(reportPattern,
"(files / stats) \\ passes",
"compile round 1",
"compile round 2",
"stylesheet",
"finalize",
"generation",
"all passes")
);
buffer.append(line);
// affiche les temps de tous les fichiers en temp total croissant
for (Long l : total.times) {
JAXXCompiler c = total.getCompiler(l);
printReportLine(buffer,
reportPattern,
c.getOutputClassName(),
cfp.getTime(c),
csp.getTime(c),
ssp.getTime(c),
fp.getTime(c),
gp.getTime(c),
total.getTime(c)
);
}
buffer.append(line);
if (compilers.size() > 1) {
printReportLine(buffer,
reportPattern,
"total (" + compilers.size() + " files)",
cfp.total,
csp.total,
ssp.total,
fp.total,
gp.total,
total.total
);
buffer.append(line);
printReportLine2(buffer,
reportPattern,
"min",
cfp.min,
csp.min,
ssp.min,
fp.min,
gp.min,
total.min
);
printReportLine2(buffer,
reportPattern,
"max",
cfp.max,
csp.max,
ssp.max,
fp.max,
gp.max,
total.max
);
printReportLine(buffer,
reportPattern,
"average",
cfp.average,
csp.average,
ssp.average,
fp.average,
gp.average,
total.average
);
buffer.append(line);
}
cfp.clear();
csp.clear();
ssp.clear();
gp.clear();
total.clear();
return buffer;
}
public static final String TIME_PATTERN = "%1$9s - %2$2d%%";
protected void printReportLine(StringBuilder buffer,
String reportPattern,
String label,
long firstPassCounter,
long secondPassCounter,
long cssCounter,
long finalizeCounter,
long generatorCounter,
long totalCounter) {
float percentCFP = (float) firstPassCounter / totalCounter * 100;
float percentCSP = (float) secondPassCounter / totalCounter * 100;
float percentCSSP = (float) cssCounter / totalCounter * 100;
float percentFP = (float) finalizeCounter / totalCounter * 100;
float percentGP = (float) generatorCounter / totalCounter * 100;
String strCFP = String.format(TIME_PATTERN,
Strings.convertTime(firstPassCounter),
(int) percentCFP
);
String strCSP = String.format(TIME_PATTERN,
Strings.convertTime(secondPassCounter),
(int) percentCSP
);
String strCSSP = String.format(TIME_PATTERN,
Strings.convertTime(cssCounter),
(int) percentCSSP
);
String strFP = String.format(TIME_PATTERN,
Strings.convertTime(finalizeCounter),
(int) percentFP
);
String strGP = String.format(TIME_PATTERN,
Strings.convertTime(generatorCounter),
(int) percentGP
);
buffer.append(String.format(reportPattern,
label,
strCFP,
strCSP,
strCSSP,
strFP,
strGP,
Strings.convertTime(totalCounter))
);
}
protected void printReportLine2(StringBuilder buffer,
String reportPattern,
String label,
long firstPassCounter,
long secondPassCounter,
long cssCounter,
long finalizeCounter,
long generatorCounter,
long totalCounter) {
buffer.append(String.format(reportPattern,
label,
Strings.convertTime(firstPassCounter),
Strings.convertTime(secondPassCounter),
Strings.convertTime(cssCounter),
Strings.convertTime(finalizeCounter),
Strings.convertTime(generatorCounter),
Strings.convertTime(totalCounter))
);
}
protected CompilerEntry getEntry(JAXXCompiler compiler) {
int key = compiler.getOutputClassName().hashCode();
CompilerEntry result = entries.get(key);
if (result == null) {
result = new CompilerEntry(compiler);
entries.put(key, result);
compilers.add(compiler);
}
return result;
}
protected JAXXCompiler getCompiler(int hasCode) {
for (JAXXCompiler c : compilers) {
if (hasCode == c.getOutputClassName().hashCode()) {
return c;
}
}
return null;
}
}