1 /*
   2  * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
   3  * 
   4  * This file is part of the Lock Contention Tracing Subsystem for the HotSpot
   5  * Virtual Machine, which is developed at Christian Doppler Laboratory on
   6  * Monitoring and Evolution of Very-Large-Scale Software Systems. Please
   7  * contact us at <http://mevss.jku.at/> if you need additional information
   8  * or have any questions.
   9  *
  10  * This code is free software; you can redistribute it and/or modify it
  11  * under the terms of the GNU General Public License version 2 only, as
  12  * published by the Free Software Foundation.
  13  *
  14  * This code is distributed in the hope that it will be useful, but WITHOUT
  15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17  * version 2 for more details (a copy is included in the LICENSE file that
  18  * accompanied this code).
  19  *
  20  * You should have received a copy of the GNU General Public License version
  21  * 2 along with this work. If not, see <http://www.gnu.org/licenses/>.
  22  *
  23  */ 
  24 package sun.evtracing.processing.statistics.aggregator;
  25 
  26 import java.util.ArrayList;
  27 import java.util.Comparator;
  28 import java.util.HashMap;
  29 import java.util.Iterator;
  30 import java.util.Map;
  31 import java.util.Map.Entry;
  32 
  33 import sun.evtracing.processing.statistics.metadata.Contention;
  34 
  35 public abstract class ComplexAggregator<I, O> extends Aggregator {
  36         protected Map<I, Aggregator> children = new HashMap<>();
  37 
  38         ComplexAggregator(AggregatorFactory<? extends ComplexAggregator<I, O>> factory) {
  39                 super(factory);
  40         }
  41 
  42         ComplexAggregator(ComplexAggregator<I, O> x, ComplexAggregator<I, O> y) {
  43                 super(x, y);
  44 
  45                 children.putAll(x.children);
  46                 for (Entry<I, Aggregator> e : y.children.entrySet()) {
  47                         children.merge(e.getKey(), e.getValue(), (u, v) -> {
  48                                 u.merge();
  49                                 v.merge();
  50                                 return u.factory().mergeChecked(u, v);
  51                         });
  52                 }
  53         }
  54 
  55         @Override
  56         public abstract Map<O, Aggregator> children();
  57 
  58         Aggregator createChild() {
  59                 return factory().nextFactory().create();
  60         }
  61 
  62         void submitToChildren(I key, Contention c) {
  63                 Aggregator child = children.computeIfAbsent(key, x -> createChild());
  64                 child.submit(c);
  65         }
  66 
  67         @Override
  68         public void merge() {
  69                 filterDuration();
  70                 for (Aggregator child : children.values()) {
  71                         child.merge();
  72                 }
  73         }
  74         
  75         private void filterDuration() {
  76                 AggregationConfiguration config = factory().configuration();
  77                 if (config.isAbsoluteDurationFilterEnabled() || config.isRelativeDurationFilterEnabled()) {
  78                         long threshold;
  79                         if (config.isAbsoluteDurationFilterEnabled() && config.isRelativeDurationFilterEnabled()) {
  80                                 threshold = Math.max((long) (statistic().getSum() * config.relativeDurationFilterThreshold()), config.absoluteDurationFilterThreshold());
  81                         } else if (config.isAbsoluteDurationFilterEnabled()) {
  82                                 threshold = config.absoluteDurationFilterThreshold();
  83                         } else {
  84                                 threshold = (long) (statistic().getSum() * config.relativeDurationFilterThreshold());
  85                         }
  86 
  87                         Map<I, Aggregator> affected = new HashMap<>();
  88                         Iterator<Entry<I, Aggregator>> it = children.entrySet().iterator();
  89                         while (it.hasNext()) {
  90                                 Map.Entry<I, Aggregator> entry = it.next();
  91                                 if (entry.getValue().statistic().getSum() < threshold) {
  92                                         affected.put(entry.getKey(), entry.getValue());
  93                                         it.remove();
  94                                 }
  95                         }
  96 
  97                         if (affected.size() > 1) {
  98                                 Aggregator merged = affected.values().stream().reduce((x, y) -> x.factory().mergeChecked(x, y)).get();
  99                                 children.put(createDurationFilteredChild(), merged);
 100                         } else {
 101                                 // don't filter if only one child would be affected
 102                                 children.putAll(affected);
 103                         }
 104                 }
 105         }
 106         
 107         protected abstract I createDurationFilteredChild();
 108 
 109         void mergeChildren(Comparator<? super I> cmp) {
 110                 ArrayList<I> sorted = new ArrayList<>(children.keySet());
 111                 sorted.sort(cmp);
 112 
 113                 Map<I, Aggregator> merged = new HashMap<>();
 114                 I current = null;
 115                 Aggregator currentChild = null;
 116                 for (I next : sorted) {
 117                         Aggregator nextChild = children.get(next);
 118                         if (current != null) {
 119                                 if (cmp.compare(current, next) == 0) {
 120                                         currentChild = currentChild.factory().mergeChecked(currentChild, nextChild);
 121                                 } else {
 122                                         merged.put(current, currentChild);
 123                                         current = next;
 124                                         currentChild = nextChild;
 125                                 }
 126                         } else {
 127                                 current = next;
 128                                 currentChild = nextChild;
 129                         }
 130                 }
 131                 if (current != null) {
 132                         merged.put(current, currentChild);
 133                 }
 134                 children = merged;
 135                 filterDuration();
 136                 for (Aggregator child : children.values()) {
 137                         child.merge();
 138                 }
 139         }
 140 }