2015-06-09 16 views
12

Ho scritto un timer che misurerà le prestazioni di un particolare codice in qualsiasi applicazione multithread. Nel timer sottostante, popolerà anche la mappa con quante chiamate hanno richiesto x millisecondi. Userò questa mappa come parte della mia istogramma per fare ulteriori analisi, come la percentuale di chiamate ha preso questa molto millisecondi ed eccCalcolo della media e percentili da una mappa dell'istogramma?

public static class StopWatch { 

    public static ConcurrentHashMap<Long, Long> histogram = new ConcurrentHashMap<Long, Long>(); 

    /** 
    * Creates an instance of the timer and starts it running. 
    */ 
    public static StopWatch getInstance() { 
     return new StopWatch(); 
    } 

    private long m_end = -1; 
    private long m_interval = -1; 
    private final long m_start; 

    private StopWatch() { 
     m_start = m_interval = currentTime(); 
    } 

    /** 
    * Returns in milliseconds the amount of time that has elapsed since the timer was created. If the 
    * <code>stop</code> method has been invoked, then this returns instead the elapsed time between the creation of 
    * the timer and the moment when <code>stop</code> was invoked. 
    * 
    * @return duration it took 
    */ 
    public long getDuration() { 
     long result = 0; 

     final long startTime = m_start; 
     final long endTime = isStopWatchRunning() ? currentTime() : m_end; 

     result = convertNanoToMilliseconds(endTime - startTime); 

     boolean done = false; 
     while (!done) { 
      Long oldValue = histogram.putIfAbsent(result, 1L); 
      if (oldValue != null) { 
       done = histogram.replace(result, oldValue, oldValue + 1); 
      } else { 
       done = true; 
      } 
     } 

     return result; 
    } 

    /** 
    * Returns in milliseconds the amount of time that has elapsed since the last invocation of this same method. If 
    * this method has not previously been invoked, then it is the amount of time that has elapsed since the timer 
    * was created. <strong>Note</strong> that once the <code>stop</code> method has been invoked this will just 
    * return zero. 
    * 
    * @return interval period 
    */ 
    public long getInterval() { 
     long result = 0; 

     final long startTime = m_interval; 
     final long endTime; 

     if (isStopWatchRunning()) { 
      endTime = m_interval = currentTime(); 
     } else { 
      endTime = m_end; 
     } 

     result = convertNanoToMilliseconds(endTime - startTime); 

     return result; 
    } 

    /** 
    * Stops the timer from advancing. This has an impact on the values returned by both the 
    * <code>getDuration</code> and the <code>getInterval</code> methods. 
    */ 
    public void stop() { 
     if (isStopWatchRunning()) { 
      m_end = currentTime(); 
     } 
    } 

    /** 
    * What is the current time in nanoseconds? 
    * 
    * @return returns back the current time in nanoseconds 
    */ 
    private long currentTime() { 
     return System.nanoTime(); 
    } 

    /** 
    * This is used to check whether the timer is alive or not 
    * 
    * @return checks whether the timer is running or not 
    */ 
    private boolean isStopWatchRunning() { 
     return (m_end <= 0); 
    } 

    /** 
    * This is used to convert NanoSeconds to Milliseconds 
    * 
    * @param nanoseconds 
    * @return milliseconds value of nanoseconds 
    */ 
    private long convertNanoToMilliseconds(final long nanoseconds) { 
     return nanoseconds/1000000L; 
    } 
} 

Ad esempio, questo è il modo in cui userò la mia suddetta classe di timer per misurare le prestazioni di un particolare codice nella mia applicazione multithreading:

StopWatch timer = StopWatch.getInstance(); 
//... some code here to measure 
timer.getDuration(); 

Ora la mia domanda è - Qual è il modo migliore per calcolare la media, mediana, 95 ° e 99 ° percentile della richiesta da mia mappa istogramma? Voglio dire, voglio aggiungere determinati metodi solo nella mia classe StopWatch, che farà tutti i calcoli come trovare la media, la mediana, il 95 ° e il 99 ° percentile.

E quindi posso ottenere direttamente utilizzando l'istanza StopWatch.

La mia mappa istogramma sarà simile a questa:

chiave - significa numero di millisecondi

valore - significa numero di chiamate che hanno avuto che molto millisecondi.

+1

Scegli questa ---> http://math.stackexchange.com/questions/879052/how-to-find-mean-and-median-from-histogram –

+0

Hai provato a codice qualcosa? – assylias

+1

Stai cercando una libreria che ti aiuti con gli algoritmi statistici? Qualcosa come le statistiche di [Apache Commons Math] (http://commons.apache.org/proper/commons-math/userguide/stat.html)? – cheffe

risposta

3

La media è semplice da implementare. La mediana è il 50 ° percentile, quindi è sufficiente un singolo metodo percentile che funzioni e creare un metodo di utilità per la mediana. Esistono several variations of Percentile calculation, ma questo dovrebbe generare gli stessi risultati della funzione PERCENTILE.INC di Microsoft Excel.

import java.util.Map; 
import java.util.SortedSet; 
import java.util.concurrent.ConcurrentSkipListSet; 

public class HistogramStatistics 
{ 
    public static Double average(final Map<Long, Long> histogram) 
    { 
     return HistogramStatistics.mean(histogram); 
    } 

    public static Double mean(final Map<Long, Long> histogram) 
    { 
     double sum = 0L; 

     for (Long value : histogram.keySet()) 
     { 
      sum += (value * histogram.get(value)); 
     } 

     return sum/(double) HistogramStatistics.count(histogram); 
    } 

    public static Double median(final Map<Long, Long> histogram) 
    { 
     return HistogramStatistics.percentile(histogram, 0.50d); 
    } 

    public static Double percentile(final Map<Long, Long> histogram, final double percent) 
    { 
     if ((percent < 0d) || (percent > 1d)) 
     { 
      throw new IllegalArgumentException("Percentile must be between 0.00 and 1.00."); 
     } 

     if ((histogram == null) || histogram.isEmpty()) 
     { 
      return null; 
     } 

     double n = (percent * (HistogramStatistics.count(histogram).doubleValue() - 1d)) + 1d; 
     double d = n - Math.floor(n); 
     SortedSet<Long> bins = new ConcurrentSkipListSet<Long>(histogram.keySet()); 
     long observationsBelowBinInclusive = 0L; 
     Long lowBin = bins.first(); 

     Double valuePercentile = null; 

     for (Long highBin : bins) 
     { 
      observationsBelowBinInclusive += histogram.get(highBin); 

      if (n <= observationsBelowBinInclusive) 
      { 
       if ((d == 0f) || (histogram.get(highBin) > 1L)) 
       { 
        lowBin = highBin; 
       } 

       valuePercentile = lowBin.doubleValue() + ((highBin - lowBin) * d); 

       break; 
      } 

      lowBin = highBin; 
     } 

     return valuePercentile; 
    } 

    public static Long count(final Map<Long, Long> histogram) 
    { 
     long observations = 0L; 

     for (Long value : histogram.keySet()) 
     { 
      observations += histogram.get(value); 
     } 

     return observations; 
    } 
} 
1

Dare un istogramma (Lista Frequency) come la seguente

Value | Frequency 
------+---------- 
    1 | 5 
    2 | 3 
    3 | 1 
    4 | 7 
    5 | 2 
    .. 

Dove ogni Value è verificato Frequency volte nel data-set.

public static double getMean (ConcurrentHashMap<Long,Long> histogram) 
{ 
    double mean = 0; 
    double a = 0; 
    double b = 0; 

    TreeSet<Long> values = histogram.keySet(); 

    for (Long value : values) 
    { 
     // a = a + (value x frequency) 
     a = a + (value * histogram.get(value)); 

     // b = b + frequency 
     b = b + histogram.get(value); 
    } 

    // mean = SUM(value x frequency)/SUM(frequency) 
    mean = (a/b); 

    return mean; 
} 
+0

Questo risponde solo (nemmeno) alla metà della domanda, che era circa la media * e percentili *. – AndreKR