CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-hdrhistogram--hdr-histogram

High Dynamic Range (HDR) Histogram for recording and analyzing value distributions with configurable precision across wide dynamic ranges.

Pending
Overview
Eval results
Files

iterators.mddocs/

Iterator Patterns and Data Analysis

Comprehensive iteration capabilities for detailed exploration and analysis of histogram data. HdrHistogram provides multiple iterator types for different analysis patterns, from percentile exploration to linear bucket analysis.

AbstractHistogramIterator

Base class for all histogram iterators providing common iteration functionality.

public abstract class AbstractHistogramIterator implements Iterator<HistogramIterationValue> {
    
    // Iterator interface
    boolean hasNext();
    HistogramIterationValue next();
    void remove();  // Unsupported operation
    
    // Reset and reuse
    void reset();
    void reset(AbstractHistogram histogram);
    
    // Current state access
    long getValueIteratedTo();
    long getValueIteratedFrom();
    long getCountAtValueIteratedTo();
    long getCountAddedInThisIterationStep();
    long getTotalCountToThisValue();
    long getTotalValueToThisValue();
    double getPercentileIteratedTo();
    double getPercentileLevelIteratedTo();
}

PercentileIterator

Iterates through histogram values according to percentile levels with exponentially decreasing resolution, focusing detail on higher percentiles.

public class PercentileIterator extends AbstractHistogramIterator {
    
    // Constructor
    public PercentileIterator(AbstractHistogram histogram, int percentileTicksPerHalfDistance);
    
    // Reset for reuse
    void reset(int percentileTicksPerHalfDistance);
    void reset(AbstractHistogram histogram, int percentileTicksPerHalfDistance);
}

Usage Examples

// Create percentile iterator with 5 ticks per half distance
// This provides more detail at higher percentiles
PercentileIterator iterator = new PercentileIterator(histogram, 5);

System.out.println("Percentile Distribution:");
System.out.println("Value(μs) | Percentile | Count | TotalCount");
System.out.println("----------|------------|-------|------------");

while (iterator.hasNext()) {
    HistogramIterationValue iterationValue = iterator.next();
    
    System.out.printf("%8d | %9.4f%% | %5d | %10d%n",
        iterationValue.getValueIteratedTo(),
        iterationValue.getPercentileIteratedTo(),
        iterationValue.getCountAddedInThisIterationStep(),
        iterationValue.getTotalCountToThisValue());
}

Percentile Resolution Control

The percentileTicksPerHalfDistance parameter controls resolution:

// Low resolution - fewer data points, faster iteration
PercentileIterator coarse = new PercentileIterator(histogram, 1);

// Medium resolution - good balance  
PercentileIterator balanced = new PercentileIterator(histogram, 5);

// High resolution - more data points, detailed analysis
PercentileIterator detailed = new PercentileIterator(histogram, 10);

// Compare percentile coverage
System.out.println("Percentile Resolution Comparison:");
analyzePercentileResolution("Coarse (1)", coarse);
analyzePercentileResolution("Balanced (5)", balanced); 
analyzePercentileResolution("Detailed (10)", detailed);

SLA Analysis with Percentiles

public void analyzeSLACompliance(AbstractHistogram histogram, long slaThreshold) {
    PercentileIterator iterator = new PercentileIterator(histogram, 5);
    
    System.out.printf("SLA Analysis (threshold: %d μs):%n", slaThreshold);
    
    while (iterator.hasNext()) {
        HistogramIterationValue value = iterator.next();
        long latency = value.getValueIteratedTo();
        double percentile = value.getPercentileIteratedTo();
        
        // Highlight key percentiles and SLA violations
        if (percentile >= 50.0) {  // Focus on P50 and above
            String status = latency <= slaThreshold ? "✓" : "✗ VIOLATION";
            System.out.printf("P%.1f: %d μs %s%n", percentile, latency, status);
        }
        
        // Stop at 99.99th percentile for most analyses
        if (percentile >= 99.99) break;
    }
}

LinearIterator

Iterates through histogram values using linear steps of equal size, ideal for uniform bucket analysis.

public class LinearIterator extends AbstractHistogramIterator {
    
    // Constructor  
    public LinearIterator(AbstractHistogram histogram, long valueUnitsPerBucket);
    
    // Reset for reuse
    void reset(long valueUnitsPerBucket);
    void reset(AbstractHistogram histogram, long valueUnitsPerBucket);
}

Usage Examples

// Create linear iterator with 1000μs (1ms) buckets
LinearIterator iterator = new LinearIterator(histogram, 1000);

System.out.println("Linear Distribution (1ms buckets):");
System.out.println("Range(ms) | Count | Density");
System.out.println("----------|-------|--------");

while (iterator.hasNext()) {
    HistogramIterationValue iterationValue = iterator.next();
    
    if (iterationValue.getCountAddedInThisIterationStep() > 0) {
        long fromValue = iterationValue.getValueIteratedFrom();
        long toValue = iterationValue.getValueIteratedTo();
        long count = iterationValue.getCountAddedInThisIterationStep();
        
        System.out.printf("%3d - %3d | %5d | %s%n",
            fromValue / 1000, toValue / 1000, count,
            "*".repeat((int)(count / 100)));  // Simple ASCII histogram
    }
}

Bucket-Based Analysis

public void analyzeDistributionBuckets(AbstractHistogram histogram, long bucketSize) {
    LinearIterator iterator = new LinearIterator(histogram, bucketSize);
    
    List<BucketInfo> buckets = new ArrayList<>();
    
    while (iterator.hasNext()) {
        HistogramIterationValue value = iterator.next();
        
        if (value.getCountAddedInThisIterationStep() > 0) {
            buckets.add(new BucketInfo(
                value.getValueIteratedFrom(),
                value.getValueIteratedTo(),
                value.getCountAddedInThisIterationStep()
            ));
        }
    }
    
    // Find peak bucket
    BucketInfo peakBucket = buckets.stream()
        .max(Comparator.comparing(b -> b.count))
        .orElse(null);
        
    if (peakBucket != null) {
        System.out.printf("Peak distribution: %d-%d range with %d samples%n",
            peakBucket.fromValue, peakBucket.toValue, peakBucket.count);
    }
    
    // Analyze distribution spread
    long totalRange = histogram.getMaxValue() - histogram.getMinNonZeroValue();
    long activeRanges = buckets.size();
    
    System.out.printf("Distribution spread: %d active ranges out of %d total range%n",
        activeRanges, totalRange / bucketSize);
}

LogarithmicIterator

Iterates through histogram values at logarithmically increasing levels, providing higher resolution at lower values.

public class LogarithmicIterator extends AbstractHistogramIterator {
    
    // Constructor
    public LogarithmicIterator(AbstractHistogram histogram, 
                              long valueUnitsInFirstBucket, 
                              double logBase);
    
    // Reset for reuse
    void reset(long valueUnitsInFirstBucket, double logBase);
    void reset(AbstractHistogram histogram, long valueUnitsInFirstBucket, double logBase);
}

Usage Examples

// Create logarithmic iterator: first bucket = 10μs, base = 2.0  
LogarithmicIterator iterator = new LogarithmicIterator(histogram, 10, 2.0);

System.out.println("Logarithmic Distribution:");
System.out.println("Bucket Range | Count | Cumulative%");
System.out.println("-------------|-------|------------");

long totalCount = histogram.getTotalCount();

while (iterator.hasNext()) {
    HistogramIterationValue iterationValue = iterator.next();
    
    if (iterationValue.getCountAddedInThisIterationStep() > 0) {
        long fromValue = iterationValue.getValueIteratedFrom();
        long toValue = iterationValue.getValueIteratedTo();
        long count = iterationValue.getCountAddedInThisIterationStep();
        double cumulative = 100.0 * iterationValue.getTotalCountToThisValue() / totalCount;
        
        System.out.printf("%5d - %5d | %5d | %9.2f%%n",
            fromValue, toValue, count, cumulative);
    }
}

Logarithmic Base Analysis

Different logarithmic bases provide different resolution patterns:

public void compareLogarithmicBases(AbstractHistogram histogram) {
    double[] bases = {1.5, 2.0, 3.0, 10.0};
    
    for (double base : bases) {
        LogarithmicIterator iterator = new LogarithmicIterator(histogram, 1, base);
        
        int bucketCount = 0;
        while (iterator.hasNext()) {
            HistogramIterationValue value = iterator.next();
            if (value.getCountAddedInThisIterationStep() > 0) {
                bucketCount++;
            }
        }
        
        System.out.printf("Base %.1f: %d active buckets%n", base, bucketCount);
    }
}

RecordedValuesIterator

Iterates through all recorded histogram values using finest granularity steps, including only non-zero counts.

public class RecordedValuesIterator extends AbstractHistogramIterator {
    
    // Constructor
    public RecordedValuesIterator(AbstractHistogram histogram);
    
    // Reset for reuse
    void reset();
    void reset(AbstractHistogram histogram);
}

Usage Examples

// Iterate through all recorded values
RecordedValuesIterator iterator = new RecordedValuesIterator(histogram);

System.out.println("All Recorded Values:");
System.out.println("Value | Count | Cumulative Count | Percentile");
System.out.println("------|-------|------------------|------------");

while (iterator.hasNext()) {
    HistogramIterationValue iterationValue = iterator.next();
    
    long value = iterationValue.getValueIteratedTo();
    long count = iterationValue.getCountAtValueIteratedTo();
    long totalCount = iterationValue.getTotalCountToThisValue();
    double percentile = iterationValue.getPercentileIteratedTo();
    
    System.out.printf("%5d | %5d | %14d | %9.4f%%%n",
        value, count, totalCount, percentile);
        
    // Limit output for large histograms
    if (totalCount > histogram.getTotalCount() * 0.999) {
        System.out.println("... (showing first 99.9% of data)");
        break;
    }
}

Exact Value Analysis

public void findExactValues(AbstractHistogram histogram, long... searchValues) {
    RecordedValuesIterator iterator = new RecordedValuesIterator(histogram);
    Set<Long> searchSet = Arrays.stream(searchValues).boxed().collect(Collectors.toSet());
    
    System.out.println("Exact Value Search:");
    
    while (iterator.hasNext() && !searchSet.isEmpty()) {
        HistogramIterationValue value = iterator.next();
        long currentValue = value.getValueIteratedTo();
        
        if (searchSet.contains(currentValue)) {
            System.out.printf("Value %d: count=%d, percentile=%.4f%%%n",
                currentValue,
                value.getCountAtValueIteratedTo(), 
                value.getPercentileIteratedTo());
            searchSet.remove(currentValue);
        }
    }
    
    // Report missing values
    if (!searchSet.isEmpty()) {
        System.out.println("Values not found: " + searchSet);
    }
}

AllValuesIterator

Iterates through all possible histogram values using finest granularity, including zero counts.

public class AllValuesIterator extends AbstractHistogramIterator {
    
    // Constructor
    public AllValuesIterator(AbstractHistogram histogram);
    
    // Reset for reuse  
    void reset();
    void reset(AbstractHistogram histogram);
}

Usage Examples

// Analyze value coverage and gaps
AllValuesIterator iterator = new AllValuesIterator(histogram);

long consecutiveZeros = 0;
long maxGap = 0;
long gapStart = 0;

while (iterator.hasNext()) {
    HistogramIterationValue iterationValue = iterator.next();
    long value = iterationValue.getValueIteratedTo();
    long count = iterationValue.getCountAtValueIteratedTo();
    
    if (count == 0) {
        if (consecutiveZeros == 0) {
            gapStart = value;
        }
        consecutiveZeros++;
    } else {
        if (consecutiveZeros > maxGap) {
            maxGap = consecutiveZeros;
            System.out.printf("Largest gap: %d values (%d - %d)%n", 
                maxGap, gapStart, gapStart + maxGap - 1);
        }
        consecutiveZeros = 0;
    }
}

HistogramIterationValue

Container class for histogram iteration results with comprehensive value information.

public class HistogramIterationValue {
    
    // Value information
    long getValueIteratedTo();
    long getValueIteratedFrom();
    
    // Count information
    long getCountAtValueIteratedTo();
    long getCountAddedInThisIterationStep();
    long getTotalCountToThisValue();
    long getTotalValueToThisValue();
    
    // Percentile information
    double getPercentile();
    double getPercentileLevelIteratedTo();
    
    // Utility methods
    String toString();
}

Comprehensive Value Analysis

public void analyzeIterationValue(HistogramIterationValue value) {
    System.out.printf("Iteration Value Analysis:%n");
    System.out.printf("  Current value: %d%n", value.getValueIteratedTo());
    System.out.printf("  Value range: %d - %d%n", 
        value.getValueIteratedFrom(), value.getValueIteratedTo());
    System.out.printf("  Count at value: %d%n", value.getCountAtValueIteratedTo());
    System.out.printf("  Count in step: %d%n", value.getCountAddedInThisIterationStep());
    System.out.printf("  Cumulative count: %d%n", value.getTotalCountToThisValue());
    System.out.printf("  Cumulative value: %d%n", value.getTotalValueToThisValue());
    System.out.printf("  Percentile level: %.4f%%%n", value.getPercentileLevelIteratedTo());
}

Double Histogram Iterators

HdrHistogram provides corresponding iterator types for DoubleHistogram values.

DoublePercentileIterator

public class DoublePercentileIterator implements Iterator<DoubleHistogramIterationValue> {
    
    public DoublePercentileIterator(DoubleHistogram histogram, int percentileTicksPerHalfDistance);
    
    boolean hasNext();
    DoubleHistogramIterationValue next();
    void reset(int percentileTicksPerHalfDistance);
}

DoubleLinearIterator

public class DoubleLinearIterator implements Iterator<DoubleHistogramIterationValue> {
    
    public DoubleLinearIterator(DoubleHistogram histogram, double valueUnitsPerBucket);
    
    boolean hasNext();
    DoubleHistogramIterationValue next();
    void reset(double valueUnitsPerBucket);
}

Usage Examples for Double Iterators

// Analyze double histogram with percentile iterator
DoubleHistogram responseTimeHist = getResponseTimeHistogram();
DoublePercentileIterator iterator = new DoublePercentileIterator(responseTimeHist, 5);

System.out.println("Response Time Percentile Analysis:");
while (iterator.hasNext()) {
    DoubleHistogramIterationValue value = iterator.next();
    
    double responseTime = value.getValueIteratedTo();
    double percentile = value.getPercentileLevelIteratedTo();
    
    if (percentile >= 50.0) {  // Focus on P50+
        System.out.printf("P%.1f: %.3f seconds%n", percentile, responseTime);
    }
}

DoubleHistogramIterationValue

public class DoubleHistogramIterationValue {
    
    double getValueIteratedTo();
    double getValueIteratedFrom();
    long getCountAtValueIteratedTo();
    long getCountAddedInThisIterationStep();
    long getTotalCountToThisValue();
    double getPercentileLevelIteratedTo();
}

Advanced Iterator Patterns

Multi-Iterator Comparison

public void compareIteratorTypes(AbstractHistogram histogram) {
    // Setup different iterator types
    PercentileIterator percentile = new PercentileIterator(histogram, 5);
    LinearIterator linear = new LinearIterator(histogram, 1000);
    LogarithmicIterator logarithmic = new LogarithmicIterator(histogram, 100, 2.0);
    
    System.out.println("Iterator Type Comparison:");
    
    // Count steps for each iterator type
    int percentileSteps = countSteps(percentile);
    int linearSteps = countSteps(linear);
    int logSteps = countSteps(logarithmic);
    
    System.out.printf("Percentile iterator: %d steps%n", percentileSteps);
    System.out.printf("Linear iterator: %d steps%n", linearSteps);
    System.out.printf("Logarithmic iterator: %d steps%n", logSteps);
}

private int countSteps(Iterator<HistogramIterationValue> iterator) {
    int steps = 0;
    while (iterator.hasNext()) {
        iterator.next();
        steps++;
    }
    return steps;
}

Custom Analysis Functions

public class HistogramAnalyzer {
    
    public void findOutliers(AbstractHistogram histogram, double outlierThreshold) {
        PercentileIterator iterator = new PercentileIterator(histogram, 10);
        
        System.out.printf("Outlier Analysis (threshold: %.1f%%):%n", outlierThreshold);
        
        while (iterator.hasNext()) {
            HistogramIterationValue value = iterator.next();
            double percentile = value.getPercentileIteratedTo();
            
            if (percentile >= outlierThreshold) {
                long latency = value.getValueIteratedTo();
                long count = value.getCountAddedInThisIterationStep();
                
                System.out.printf("P%.4f: %d μs (%d samples)%n", 
                    percentile, latency, count);
            }
        }
    }
    
    public void analyzeDistributionShape(AbstractHistogram histogram) {
        LinearIterator iterator = new LinearIterator(histogram, 500);  // 500μs buckets
        
        List<Long> bucketCounts = new ArrayList<>();
        
        while (iterator.hasNext()) {
            HistogramIterationValue value = iterator.next();
            bucketCounts.add(value.getCountAddedInThisIterationStep());
        }
        
        // Calculate distribution metrics
        long maxBucket = Collections.max(bucketCounts);
        double mean = bucketCounts.stream().mapToLong(Long::longValue).average().orElse(0);
        
        System.out.printf("Distribution shape analysis:%n");
        System.out.printf("  Buckets: %d%n", bucketCounts.size());
        System.out.printf("  Peak bucket count: %d%n", maxBucket);
        System.out.printf("  Mean bucket count: %.1f%n", mean);
        System.out.printf("  Peak-to-mean ratio: %.2f%n", maxBucket / mean);
    }
}

Iterator Performance Optimization

public class OptimizedIteratorUsage {
    
    // Reuse iterators to minimize object creation
    private final PercentileIterator percentileIter;
    private final LinearIterator linearIter;
    
    public OptimizedIteratorUsage(AbstractHistogram templateHistogram) {
        this.percentileIter = new PercentileIterator(templateHistogram, 5);
        this.linearIter = new LinearIterator(templateHistogram, 1000);
    }
    
    public void analyzeManyHistograms(List<AbstractHistogram> histograms) {
        for (AbstractHistogram histogram : histograms) {
            // Reset and reuse existing iterators
            percentileIter.reset(histogram, 5);
            linearIter.reset(histogram, 1000);
            
            analyzeWithPercentiles(percentileIter);
            analyzeWithLinearBuckets(linearIter);
        }
    }
    
    private void analyzeWithPercentiles(PercentileIterator iterator) {
        // Analysis implementation using reused iterator
        while (iterator.hasNext()) {
            HistogramIterationValue value = iterator.next();
            // Process value...
        }
    }
    
    private void analyzeWithLinearBuckets(LinearIterator iterator) {
        // Analysis implementation using reused iterator  
        while (iterator.hasNext()) {
            HistogramIterationValue value = iterator.next();
            // Process value...
        }
    }
}

Choosing the Right Iterator

Iterator Selection Guide

Analysis NeedRecommended IteratorConfiguration
SLA compliancePercentileIteratorpercentileTicksPerHalfDistance = 5-10
Distribution shapeLinearIteratorvalueUnitsPerBucket = expected_range/100
Scale analysisLogarithmicIteratorlogBase = 2.0 or 10.0
Exact value lookupRecordedValuesIteratorN/A
Gap analysisAllValuesIteratorN/A (use sparingly)
Response time analysisDoublePercentileIteratorFor double histograms

Performance Characteristics

Iterator TypePerformanceMemoryUse Case
PercentileIteratorFastLowHigh-level percentile analysis
LinearIteratorFastLowUniform bucket analysis
LogarithmicIteratorFastLowScale-aware analysis
RecordedValuesIteratorMediumLowDetailed value exploration
AllValuesIteratorSlowMediumComplete coverage analysis

Memory and Performance Tips

  • Reuse iterators when analyzing multiple histograms
  • Choose appropriate granularity to balance detail vs. performance
  • Limit iteration scope for large histograms (break early when possible)
  • Use percentile iterators for most analysis scenarios
  • Avoid AllValuesIterator for large value ranges unless necessary

Install with Tessl CLI

npx tessl i tessl/maven-org-hdrhistogram--hdr-histogram

docs

concurrent-histograms.md

core-operations.md

double-histograms.md

index.md

iterators.md

recorders.md

serialization.md

specialized-variants.md

utilities.md

tile.json