public String toECharts()

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();
    }