package er.profiling; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; public class PFStatsNode { private long _id; private PFStatsNode _parent; private String _name; private String _type; private long _startTime; private long _endTime; private List<PFStatsNode> _children; private Object _target; private Object _context; private Map<String, Long> _counters; private List<String> _errors; public PFStatsNode(String name, String type, Object target, Object context) { _name = name; _type = type; _target = target; _context = context; _id = PFProfiler.nextStatsID(); } public void clearErrors() { _errors = null; if (_children != null) { for (PFStatsNode child : _children) { child.clearErrors(); } } } public void addError(String error) { if (_errors == null) { _errors = new LinkedList<>(); } _errors.add(error); } public boolean hasErrors() { return _errors != null && _errors.size() > 0; } public List<String> errors() { return _errors; } public String type() { return _type; } public PFStatsNode parentStats() { return _parent; } public long id() { return _id; } public String name() { return _name; } public Object target() { return _target; } public Object context() { return _context; } public int depth() { return _parent == null ? 0 : (_parent.depth() + 1); } public PFStatsNode rootStats() { return _parent == null ? this : _parent.rootStats(); } public boolean isLeaf() { return _children == null || _children.size() == 0; } public boolean isRoot() { return rootStats() == this; } public void start() { _startTime = System.nanoTime(); // for (int i = depth(); i > 0; i --) { // System.out.print(" "); // } // System.out.println(_name + ":start"); } public void end() { _endTime = System.nanoTime(); if (_parent != null) { _parent.end(); } // for (int i = depth(); i > 0; i --) { // System.out.print(" "); // } // System.out.println(_name + ":done (" + duration() + "ms)"); } public long overhead() { long overhead = duration(); if (_children != null) { long childrenDuration = 0; for (PFStatsNode child : _children) { childrenDuration += child.duration(); } overhead -= childrenDuration; } return overhead; } public long duration() { return _endTime - _startTime; } public double durationMillis() { return duration() / 1000000.0; } public long durationOf(String name, boolean recursiveSum) { long duration = 0; if (name.equals(_name)) { duration += duration(); } if (_children != null && (recursiveSum || duration == 0)) { for (PFStatsNode child : _children) { duration += child.durationOf(name, recursiveSum); } } return duration; } public double durationOfMillis(String name, boolean recursiveSum) { return durationOf(name, recursiveSum) / 1000000.0; } public int countOf(String name, boolean recursiveCount) { int count = 0; if (name.equals(_name)) { count++; } if (_children != null && (recursiveCount || count == 0)) { for (PFStatsNode child : _children) { count += child.countOf(name, recursiveCount); } } return count; } public DurationCount countBetweenDurations(long minNanos, long maxNanos) { DurationCount durationCount = new DurationCount(); countBetweenDurations(minNanos, maxNanos, durationCount); return durationCount; } protected void countBetweenDurations(long minNanos, long maxNanos, DurationCount durationCount) { long duration = overhead(); if (duration >= minNanos && duration < maxNanos) { durationCount.count++; durationCount.duration += duration; } if (_children != null) { for (PFStatsNode child : _children) { child.countBetweenDurations(minNanos, maxNanos, durationCount); } } } public List<PFStatsNode> children() { return _children; } public PFStatsNode push(String name, String type, Object target, Object context) { if (_children == null) { _children = new LinkedList<>(); } PFStatsNode stats = new PFStatsNode(name, type, target, context); stats._parent = this; _children.add(stats); PFProfiler.setCurrentStats(stats); stats.start(); return stats; } public void pop() { end(); if (_parent != null) { PFProfiler.setCurrentStats(_parent); } } public double percentage() { return (double) duration() / (double) rootStats().duration(); } public boolean isAtLeastPercentage(double minimumPercentage) { return minimumPercentage == 0.0 || (percentage() >= minimumPercentage); } public boolean isImportant() { return children() == null || parentStats() == null || (!isAtLeastPercentage(parentStats().percentage() * 0.9)); } public String cssID() { return "wo_p_" + id(); } public void incrementCounter(String counterName) { synchronized (this) { if (_counters == null) { _counters = new TreeMap<>(); } Long counter = _counters.get(counterName); if (counter == null) { _counters.put(counterName, Long.valueOf(1)); } else { _counters.put(counterName, Long.valueOf(counter.longValue() + 1)); } } } public Map<String, Long> counters() { return _counters; } public static class DurationCount { long duration; int count; public long nanos() { return duration; } public int count() { return count; } public double millis() { return (double) duration / 1000000.0f; } } }