All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy