in hugegraph-common/src/main/java/org/apache/hugegraph/perf/PerfUtil.java [323:494]
public String toECharts() {
TriFunction<Integer, Integer, List<Stopwatch>, String> formatLevel = (
totalDepth, depth, items) -> {
float factor = 100.0f / (totalDepth + 1);
float showFactor = 1 + (totalDepth - depth) / (float) depth;
float radiusFrom = depth * factor;
float radiusTo = depth * factor + factor;
if (depth == 1) {
radiusFrom = 0;
}
StringBuilder sb = new StringBuilder(8 + items.size() * 128);
sb.append('{');
sb.append("name: 'Total Cost',");
sb.append("type: 'pie',");
sb.append(String.format("radius: ['%s%%', '%s%%'],",
radiusFrom, radiusTo));
sb.append(String.format(
"label: {normal: {position: 'inner', formatter:" +
"function(params) {" +
" if (params.percent > %s) return params.data.name;" +
" else return '';" +
"}}},", showFactor));
sb.append("data: [");
items.sort((i, j) -> i.id().compareTo(j.id()));
for (Stopwatch w : items) {
sb.append('{');
sb.append("id:'");
sb.append(w.id());
sb.append("',");
sb.append("name:'");
sb.append(w.name());
sb.append("',");
sb.append("value:");
// w.totalCost() - w.totalWasted() ?
sb.append(w.totalCost());
sb.append(',');
sb.append("cost:");
sb.append(w.totalCost() / 1000000.0);
sb.append(',');
sb.append("minCost:");
sb.append(w.minCost());
sb.append(',');
sb.append("maxCost:");
sb.append(w.maxCost());
sb.append(',');
sb.append("wasted:");
sb.append(w.totalWasted() / 1000000.0);
sb.append(',');
sb.append("selfWasted:");
sb.append(w.totalSelfWasted() / 1000000.0);
sb.append(',');
sb.append("times:");
sb.append(w.times());
sb.append(',');
sb.append("totalTimes:");
sb.append(w.totalTimes());
sb.append('}');
sb.append(',');
}
if (!items.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("]}");
return sb.toString();
};
BiConsumer<List<Stopwatch>, List<Stopwatch>> fillChildrenTotal =
(itemsOfLn, itemsOfLnParent) -> {
for (Stopwatch parent : itemsOfLnParent) {
List<Stopwatch> children = itemsOfLn.stream().filter(c -> {
return c.parent().equals(parent.id());
}).collect(Collectors.toList());
parent.fillChildrenTotal(children);
}
};
BiConsumer<List<Stopwatch>, List<Stopwatch>> fillOther =
(itemsOfLn, itemsOfLnParent) -> {
for (Stopwatch parent : itemsOfLnParent) {
Stream<Stopwatch> children = itemsOfLn.stream().filter(c -> {
return c.parent().equals(parent.id());
});
// Fill other cost
long sumCost = children.mapToLong(Stopwatch::totalCost).sum();
long otherCost = parent.totalCost() - sumCost;
if (otherCost > 0L) {
Stopwatch other = newStopwatch("~", parent.id());
other.totalCost(otherCost);
itemsOfLn.add(other);
}
}
};
Map<Path, Stopwatch> items = this.stopwatches;
Map<Integer, List<Stopwatch>> levelItems = new HashMap<>();
int maxDepth = 0;
for (Map.Entry<Path, Stopwatch> e : items.entrySet()) {
int depth = e.getKey().toString().split("/").length;
List<Stopwatch> levelItem = levelItems.get(depth);
if (levelItem == null) {
levelItem = new LinkedList<>();
levelItems.putIfAbsent(depth, levelItem);
}
levelItem.add(e.getValue().copy());
if (depth > maxDepth) {
maxDepth = depth;
}
}
// Fill wasted cost from the outermost to innermost
for (int i = maxDepth; i > 0; i--) {
assert levelItems.containsKey(i) : i;
List<Stopwatch> itemsOfI = levelItems.get(i);
List<Stopwatch> itemsOfParent = levelItems.get(i - 1);
if (itemsOfParent != null) {
// Fill total value of children
fillChildrenTotal.accept(itemsOfI, itemsOfParent);
}
}
StringBuilder sb = new StringBuilder(8 + items.size() * 128);
// Output results header
sb.append("{");
sb.append("tooltip: {trigger: 'item', " +
"formatter: function(params) {" +
" return params.data.name + ' ' + params.percent + '% <br/>'" +
" + 'cost: ' + params.data.cost + ' (ms) <br/>'" +
" + 'min cost: ' + params.data.minCost + ' (ns) <br/>'" +
" + 'max cost: ' + params.data.maxCost + ' (ns) <br/>'" +
" + 'wasted: ' + params.data.wasted + ' (ms) <br/>'" +
" + 'self wasted: ' + params.data.selfWasted + ' (ms) <br/>'" +
" + 'times: ' + params.data.times + '<br/>'" +
" + 'total times: ' + params.data.totalTimes + '<br/>'" +
" + 'path: ' + params.data.id + '<br/>';" +
"}");
sb.append("},");
sb.append("series: [");
// Output results data
for (int i = 1; i <= maxDepth; i++) {
assert levelItems.containsKey(i) : i;
List<Stopwatch> itemsOfI = levelItems.get(i);
List<Stopwatch> itemsOfParent = levelItems.get(i - 1);
if (itemsOfParent != null) {
// Fill other cost for non-root level, ignore root level (i=1)
fillOther.accept(itemsOfI, itemsOfParent);
}
// Output items of level I
sb.append(formatLevel.apply(maxDepth, i, itemsOfI));
sb.append(',');
}
if (!items.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("]}");
return sb.toString();
}