or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

concurrent-histograms.mdcore-operations.mddouble-histograms.mdindex.mditerators.mdrecorders.mdserialization.mdspecialized-variants.mdutilities.md

double-histograms.mddocs/

0

# Double Value Histograms

1

2

Histogram implementations for recording and analyzing double (floating-point) values with configurable precision and dynamic range. These histograms provide the same statistical analysis capabilities as integer histograms but for continuous-valued data.

3

4

## DoubleHistogram

5

6

Core implementation for recording double values with HDR precision.

7

8

```java { .api }

9

public class DoubleHistogram extends EncodableHistogram

10

implements DoubleValueRecorder, Serializable {

11

12

// Constructors

13

public DoubleHistogram(int numberOfSignificantValueDigits);

14

public DoubleHistogram(long highestToLowestValueRatio, int numberOfSignificantValueDigits);

15

public DoubleHistogram(int numberOfSignificantValueDigits,

16

Class<? extends AbstractHistogram> internalCountsHistogramClass);

17

18

// Factory methods

19

static DoubleHistogram decodeFromByteBuffer(ByteBuffer buffer,

20

long minBarForHighestToLowestValueRatio);

21

static DoubleHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

22

long minBarForHighestToLowestValueRatio);

23

static DoubleHistogram fromString(String base64CompressedHistogramString);

24

25

// Implementation methods

26

public DoubleHistogram copy();

27

public DoubleHistogram copyCorrectedForCoordinatedOmission(double expectedInterval);

28

}

29

```

30

31

### Recording Double Values

32

33

```java { .api }

34

// Core recording methods

35

void recordValue(double value);

36

void recordValueWithCount(double value, long count);

37

void recordValueWithExpectedInterval(double value, double expectedInterval);

38

void reset();

39

```

40

41

**Usage Examples:**

42

43

```java

44

// Create double histogram with auto-resizing

45

DoubleHistogram histogram = new DoubleHistogram(3);

46

47

// Record floating-point measurements

48

histogram.recordValue(1.234); // Response time in seconds

49

histogram.recordValue(0.987); // Another measurement

50

histogram.recordValue(2.345); // Higher latency

51

52

// Record multiple occurrences

53

histogram.recordValueWithCount(1.5, 10); // Value 1.5 occurred 10 times

54

55

// Coordinated omission correction for timing measurements

56

double expectedInterval = 0.1; // Expected 100ms intervals

57

double actualMeasurement = 1.5; // But measured 1.5 seconds (pause occurred)

58

histogram.recordValueWithExpectedInterval(actualMeasurement, expectedInterval);

59

```

60

61

### Statistical Analysis

62

63

```java { .api }

64

// Count and statistics

65

long getTotalCount();

66

double getMaxValue();

67

double getMinValue();

68

double getMinNonZeroValue();

69

double getMean();

70

double getStdDeviation();

71

72

// Percentile queries

73

double getValueAtPercentile(double percentile);

74

double getPercentileAtOrBelowValue(double value);

75

76

// Value-specific queries

77

long getCountAtValue(double value);

78

long getCountBetweenValues(double lowValue, double highValue);

79

```

80

81

**Usage Examples:**

82

83

```java

84

// Analyze response time distribution

85

long totalRequests = histogram.getTotalCount();

86

double avgResponseTime = histogram.getMean();

87

double maxResponseTime = histogram.getMaxValue();

88

89

// Key percentiles for SLA monitoring

90

double p50 = histogram.getValueAtPercentile(50.0); // Median response time

91

double p95 = histogram.getValueAtPercentile(95.0); // 95th percentile

92

double p99 = histogram.getValueAtPercentile(99.0); // 99th percentile

93

double p999 = histogram.getValueAtPercentile(99.9); // 99.9th percentile

94

95

System.out.printf("Response Time Analysis:%n");

96

System.out.printf(" Requests: %d%n", totalRequests);

97

System.out.printf(" Average: %.3f sec%n", avgResponseTime);

98

System.out.printf(" P50: %.3f sec%n", p50);

99

System.out.printf(" P95: %.3f sec%n", p95);

100

System.out.printf(" P99: %.3f sec%n", p99);

101

System.out.printf(" P999: %.3f sec%n", p999);

102

103

// SLA analysis - what percentage meets 2-second target?

104

double percentileAt2Sec = histogram.getPercentileAtOrBelowValue(2.0);

105

System.out.printf("%.2f%% of requests complete within 2 seconds%n", percentileAt2Sec);

106

```

107

108

### Value Equivalence Analysis

109

110

```java { .api }

111

// Value equivalence methods

112

double sizeOfEquivalentValueRange(double value);

113

double lowestEquivalentValue(double value);

114

double highestEquivalentValue(double value);

115

double medianEquivalentValue(double value);

116

double nextNonEquivalentValue(double value);

117

boolean valuesAreEquivalent(double value1, double value2);

118

```

119

120

**Usage Examples:**

121

122

```java

123

// Understand histogram precision for double values

124

double value = 1.234;

125

double rangeSize = histogram.sizeOfEquivalentValueRange(value);

126

double lowest = histogram.lowestEquivalentValue(value);

127

double highest = histogram.highestEquivalentValue(value);

128

double median = histogram.medianEquivalentValue(value);

129

130

System.out.printf("Value %.6f represents range [%.6f, %.6f]%n", value, lowest, highest);

131

System.out.printf("Range size: %.6f%n", rangeSize);

132

System.out.printf("Median equivalent: %.6f%n", median);

133

134

// Check if two values would be considered equivalent

135

double val1 = 1.2345;

136

double val2 = 1.2346;

137

if (histogram.valuesAreEquivalent(val1, val2)) {

138

System.out.println("Values are equivalent within histogram precision");

139

}

140

141

// Iterate through distinct values efficiently

142

double currentValue = histogram.getMinNonZeroValue();

143

while (currentValue <= histogram.getMaxValue()) {

144

long count = histogram.getCountAtValue(currentValue);

145

if (count > 0) {

146

System.out.printf("Value: %.6f, Count: %d%n", currentValue, count);

147

}

148

currentValue = histogram.nextNonEquivalentValue(currentValue);

149

}

150

```

151

152

### Configuration and Auto-Resize

153

154

```java { .api }

155

// Configuration

156

void setAutoResize(boolean autoResize);

157

boolean isAutoResize();

158

long getHighestToLowestValueRatio();

159

int getNumberOfSignificantValueDigits();

160

161

// Timestamp and metadata

162

long getStartTimeStamp();

163

void setStartTimeStamp(long timestamp);

164

long getEndTimeStamp();

165

void setEndTimeStamp(long timestamp);

166

String getTag();

167

void setTag(String tag);

168

```

169

170

**Usage Examples:**

171

172

```java

173

// Create histogram with specific dynamic range

174

long dynamicRange = 1000000; // 1M:1 ratio (6 orders of magnitude)

175

DoubleHistogram histogram = new DoubleHistogram(dynamicRange, 3);

176

177

// Enable auto-resize for unknown ranges

178

histogram.setAutoResize(true);

179

180

// Tag histogram for identification

181

histogram.setTag("api-response-times");

182

histogram.setStartTimeStamp(System.currentTimeMillis());

183

184

// Record measurements

185

recordApiResponseTimes(histogram);

186

187

histogram.setEndTimeStamp(System.currentTimeMillis());

188

System.out.printf("Measurement period: %s%n", histogram.getTag());

189

```

190

191

### Constructor Variations

192

193

```java

194

// Auto-resizing histogram (recommended for most use cases)

195

DoubleHistogram autoResize = new DoubleHistogram(3);

196

197

// Fixed dynamic range (1M:1 ratio)

198

DoubleHistogram fixedRange = new DoubleHistogram(1_000_000, 3);

199

200

// Custom internal histogram implementation

201

DoubleHistogram withIntCounts = new DoubleHistogram(3, IntCountsHistogram.class);

202

DoubleHistogram withPackedStorage = new DoubleHistogram(3, PackedHistogram.class);

203

```

204

205

## ConcurrentDoubleHistogram

206

207

Thread-safe version of DoubleHistogram supporting concurrent recording operations.

208

209

```java { .api }

210

public class ConcurrentDoubleHistogram extends DoubleHistogram {

211

212

// Constructors

213

public ConcurrentDoubleHistogram(int numberOfSignificantValueDigits);

214

public ConcurrentDoubleHistogram(long highestToLowestValueRatio, int numberOfSignificantValueDigits);

215

public ConcurrentDoubleHistogram(int numberOfSignificantValueDigits,

216

Class<? extends AbstractHistogram> internalCountsHistogramClass);

217

218

// Implementation methods

219

public ConcurrentDoubleHistogram copy();

220

public ConcurrentDoubleHistogram copyCorrectedForCoordinatedOmission(double expectedInterval);

221

}

222

```

223

224

### Thread Safety Characteristics

225

226

**Wait-Free Operations:**

227

- `recordValue()` - Concurrent recording without contention

228

- `recordValueWithCount()` - Concurrent recording with counts

229

- `recordValueWithExpectedInterval()` - Concurrent coordinated omission correction

230

- Auto-resizing operations

231

232

**Requires External Synchronization:**

233

- Statistical queries and analysis

234

- Iterator operations

235

- Histogram manipulation operations

236

237

### Usage Examples

238

239

```java

240

// Create concurrent double histogram for multi-threaded recording

241

ConcurrentDoubleHistogram histogram = new ConcurrentDoubleHistogram(3);

242

243

// Multiple threads recording response times concurrently

244

ExecutorService requestProcessors = Executors.newFixedThreadPool(10);

245

246

for (int i = 0; i < 10; i++) {

247

requestProcessors.submit(() -> {

248

Random random = new Random();

249

for (int j = 0; j < 10000; j++) {

250

// Simulate processing and record response time

251

double startTime = System.nanoTime() / 1e9;

252

simulateApiCall(); // Your API processing

253

double endTime = System.nanoTime() / 1e9;

254

255

// Thread-safe recording (no synchronization needed)

256

histogram.recordValue(endTime - startTime);

257

}

258

});

259

}

260

261

// Separate monitoring thread

262

ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();

263

monitor.scheduleAtFixedRate(() -> {

264

// Synchronized reading for consistent snapshot

265

synchronized (histogram) {

266

double p95 = histogram.getValueAtPercentile(95.0);

267

double p99 = histogram.getValueAtPercentile(99.0);

268

System.out.printf("Current P95: %.3fs, P99: %.3fs%n", p95, p99);

269

}

270

}, 0, 10, TimeUnit.SECONDS);

271

272

requestProcessors.shutdown();

273

monitor.shutdown();

274

```

275

276

### Writer-Reader Coordination

277

278

For more sophisticated coordination without blocking:

279

280

```java

281

ConcurrentDoubleHistogram histogram = new ConcurrentDoubleHistogram(3);

282

WriterReaderPhaser phaser = histogram.getWriterReaderPhaser();

283

284

// Recording threads (multiple)

285

Runnable recorder = () -> {

286

Random random = new Random();

287

for (int i = 0; i < 100000; i++) {

288

double measurement = random.nextGaussian() * 0.1 + 0.5; // ~500ms ± 100ms

289

histogram.recordValue(measurement);

290

}

291

};

292

293

// Analysis thread (single)

294

Runnable analyzer = () -> {

295

phaser.readerLock();

296

try {

297

// Safe to iterate and analyze

298

System.out.printf("Total count: %d%n", histogram.getTotalCount());

299

histogram.outputPercentileDistribution(System.out, 1.0);

300

} finally {

301

phaser.readerUnlock();

302

}

303

};

304

305

// Start concurrent operations

306

new Thread(recorder).start();

307

new Thread(recorder).start();

308

new Thread(analyzer).start();

309

```

310

311

## SynchronizedDoubleHistogram

312

313

Fully thread-safe double histogram with synchronized access for all operations.

314

315

```java { .api }

316

public class SynchronizedDoubleHistogram extends DoubleHistogram {

317

318

// Constructors

319

public SynchronizedDoubleHistogram(int numberOfSignificantValueDigits);

320

public SynchronizedDoubleHistogram(long highestToLowestValueRatio, int numberOfSignificantValueDigits);

321

public SynchronizedDoubleHistogram(int numberOfSignificantValueDigits,

322

Class<? extends AbstractHistogram> internalCountsHistogramClass);

323

324

// Implementation methods

325

public SynchronizedDoubleHistogram copy();

326

public SynchronizedDoubleHistogram copyCorrectedForCoordinatedOmission(double expectedInterval);

327

}

328

```

329

330

### Usage Examples

331

332

```java

333

// Fully synchronized double histogram

334

SynchronizedDoubleHistogram histogram = new SynchronizedDoubleHistogram(3);

335

336

// All operations are thread-safe but may block

337

Runnable measurements = () -> {

338

Random random = new Random();

339

for (int i = 0; i < 50000; i++) {

340

double value = Math.abs(random.nextGaussian()) * 2.0; // Positive values 0-6 range

341

histogram.recordValue(value); // Thread-safe, may block

342

}

343

};

344

345

Runnable monitoring = () -> {

346

while (true) {

347

// No synchronization needed - all operations are atomic

348

long count = histogram.getTotalCount();

349

double mean = histogram.getMean();

350

double p95 = histogram.getValueAtPercentile(95.0);

351

352

System.out.printf("Count: %d, Mean: %.3f, P95: %.3f%n", count, mean, p95);

353

354

try { Thread.sleep(2000); } catch (InterruptedException e) { break; }

355

}

356

};

357

358

// Start concurrent operations

359

new Thread(measurements).start();

360

new Thread(measurements).start();

361

new Thread(monitoring).start();

362

```

363

364

## DoubleValueRecorder Interface

365

366

Core interface for double value recording functionality.

367

368

```java { .api }

369

public interface DoubleValueRecorder {

370

void recordValue(double value);

371

void recordValueWithCount(double value, long count);

372

void recordValueWithExpectedInterval(double value, double expectedInterval);

373

void reset();

374

}

375

```

376

377

## Double Histogram Iteration

378

379

DoubleHistogram provides specialized iterators for double values:

380

381

```java { .api }

382

// Double-specific iterators

383

DoublePercentileIterator percentileIterator(int percentileTicksPerHalfDistance);

384

DoubleLinearIterator linearIterator(double valueUnitsPerBucket);

385

DoubleLogarithmicIterator logarithmicIterator(double valueUnitsInFirstBucket, double logBase);

386

DoubleRecordedValuesIterator recordedValuesIterator();

387

DoubleAllValuesIterator allValuesIterator();

388

```

389

390

**Usage Examples:**

391

392

```java

393

// Iterate through percentiles

394

DoublePercentileIterator percentileIter = histogram.percentileIterator(5);

395

while (percentileIter.hasNext()) {

396

DoubleHistogramIterationValue value = percentileIter.next();

397

System.out.printf("Percentile %.2f: %.6f (count: %d)%n",

398

value.getPercentileLevelIteratedTo(),

399

value.getValueIteratedTo(),

400

value.getCountAtValueIteratedTo());

401

}

402

403

// Linear iteration through value ranges

404

DoubleLinearIterator linearIter = histogram.linearIterator(0.1); // 100ms buckets

405

while (linearIter.hasNext()) {

406

DoubleHistogramIterationValue value = linearIter.next();

407

if (value.getCountAtValueIteratedTo() > 0) {

408

System.out.printf("Range %.3f-%.3f: %d samples%n",

409

value.getValueIteratedFrom(),

410

value.getValueIteratedTo(),

411

value.getTotalCountToThisValue());

412

}

413

}

414

```

415

416

## Practical Use Cases

417

418

### Web Application Response Times

419

420

```java

421

// Track API endpoint response times

422

ConcurrentDoubleHistogram apiResponseTimes = new ConcurrentDoubleHistogram(3);

423

apiResponseTimes.setTag("api-latency");

424

425

// In your request handler

426

@GetMapping("/api/data")

427

public ResponseEntity<Data> getData() {

428

double startTime = System.nanoTime() / 1e9;

429

430

try {

431

Data result = dataService.getData();

432

return ResponseEntity.ok(result);

433

} finally {

434

double endTime = System.nanoTime() / 1e9;

435

apiResponseTimes.recordValue(endTime - startTime);

436

}

437

}

438

439

// Periodic reporting

440

@Scheduled(fixedRate = 60000) // Every minute

441

public void reportMetrics() {

442

synchronized (apiResponseTimes) {

443

double p95 = apiResponseTimes.getValueAtPercentile(95.0);

444

double p99 = apiResponseTimes.getValueAtPercentile(99.0);

445

446

if (p95 > 2.0) { // Alert if P95 > 2 seconds

447

alertingService.alert("API P95 latency high: " + p95 + "s");

448

}

449

450

metricsService.record("api.p95", p95);

451

metricsService.record("api.p99", p99);

452

}

453

}

454

```

455

456

### Financial Transaction Processing

457

458

```java

459

// Track transaction processing times with high precision

460

DoubleHistogram transactionTimes = new DoubleHistogram(4); // High precision

461

transactionTimes.setTag("transaction-processing");

462

463

// Record transaction with coordinated omission correction

464

public void processTransaction(Transaction tx) {

465

double expectedProcessingTime = 0.050; // Expected 50ms processing

466

double startTime = System.nanoTime() / 1e9;

467

468

try {

469

// Process transaction

470

processTransactionInternal(tx);

471

} finally {

472

double endTime = System.nanoTime() / 1e9;

473

double actualTime = endTime - startTime;

474

475

// Account for coordinated omission (system pauses, GC, etc.)

476

transactionTimes.recordValueWithExpectedInterval(actualTime, expectedProcessingTime);

477

}

478

}

479

480

// Compliance reporting

481

public ComplianceReport generateComplianceReport() {

482

return ComplianceReport.builder()

483

.totalTransactions(transactionTimes.getTotalCount())

484

.averageProcessingTime(transactionTimes.getMean())

485

.p95ProcessingTime(transactionTimes.getValueAtPercentile(95.0))

486

.p99ProcessingTime(transactionTimes.getValueAtPercentile(99.0))

487

.maxProcessingTime(transactionTimes.getMaxValue())

488

.complianceThresholdMet(transactionTimes.getValueAtPercentile(99.0) < 0.100) // < 100ms P99

489

.build();

490

}

491

```

492

493

## Performance Considerations

494

495

### Memory Usage

496

DoubleHistogram internally uses an integer histogram scaled to the appropriate range:

497

- Memory usage similar to equivalent integer histogram

498

- Dynamic range affects memory requirements

499

- Consider using packed variants for sparse double distributions

500

501

### Precision and Range

502

The `numberOfSignificantValueDigits` parameter affects both precision and memory:

503

- **2 digits**: ~10% precision, low memory

504

- **3 digits**: ~1% precision, moderate memory (recommended)

505

- **4 digits**: ~0.1% precision, higher memory

506

- **5 digits**: ~0.01% precision, high memory

507

508

### Double Value Scaling

509

Double values are internally scaled to integers:

510

- Very small values (< 1e-12) may lose precision

511

- Very large values (> 1e12) may lose precision

512

- Choose appropriate dynamic range for your data

513

514

## PackedDoubleHistogram

515

516

Memory-optimized version of DoubleHistogram using packed array representation for sparse double value distributions.

517

518

```java { .api }

519

public class PackedDoubleHistogram extends DoubleHistogram {

520

521

// Constructors

522

public PackedDoubleHistogram(int numberOfSignificantValueDigits);

523

public PackedDoubleHistogram(long highestToLowestValueRatio, int numberOfSignificantValueDigits);

524

public PackedDoubleHistogram(DoubleHistogram source);

525

526

// Factory methods

527

static PackedDoubleHistogram decodeFromByteBuffer(ByteBuffer buffer,

528

long minBarForHighestToLowestValueRatio);

529

static PackedDoubleHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

530

long minBarForHighestToLowestValueRatio);

531

}

532

```

533

534

### Usage Examples

535

536

```java

537

// Create packed double histogram for sparse distributions

538

PackedDoubleHistogram histogram = new PackedDoubleHistogram(3);

539

540

// Record sparse response time data (most values 0.1-1.0s, few outliers)

541

Random random = new Random();

542

for (int i = 0; i < 100000; i++) {

543

if (random.nextDouble() < 0.9) {

544

// 90% of values in normal range

545

histogram.recordValue(0.1 + random.nextDouble() * 0.9);

546

} else {

547

// 10% outliers

548

histogram.recordValue(5.0 + random.nextDouble() * 95.0);

549

}

550

}

551

552

// Packed storage provides memory efficiency for sparse distributions

553

System.out.printf("Memory usage: %d bytes%n", histogram.getEstimatedFootprintInBytes());

554

```

555

556

## PackedConcurrentDoubleHistogram

557

558

Thread-safe packed double histogram combining memory efficiency with concurrent recording support.

559

560

```java { .api }

561

public class PackedConcurrentDoubleHistogram extends ConcurrentDoubleHistogram {

562

563

// Constructors

564

public PackedConcurrentDoubleHistogram(int numberOfSignificantValueDigits);

565

public PackedConcurrentDoubleHistogram(long highestToLowestValueRatio, int numberOfSignificantValueDigits);

566

public PackedConcurrentDoubleHistogram(DoubleHistogram source);

567

568

// Factory methods

569

static PackedConcurrentDoubleHistogram decodeFromByteBuffer(ByteBuffer buffer,

570

long minBarForHighestToLowestValueRatio);

571

static PackedConcurrentDoubleHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

572

long minBarForHighestToLowestValueRatio);

573

574

// Implementation methods

575

public PackedConcurrentDoubleHistogram copy();

576

public PackedConcurrentDoubleHistogram copyCorrectedForCoordinatedOmission(double expectedInterval);

577

}

578

```

579

580

### Usage Examples

581

582

```java

583

// Thread-safe packed double histogram for concurrent sparse recording

584

PackedConcurrentDoubleHistogram histogram = new PackedConcurrentDoubleHistogram(3);

585

586

// Multiple threads recording sparse latency measurements

587

ExecutorService executor = Executors.newFixedThreadPool(8);

588

589

for (int t = 0; t < 8; t++) {

590

executor.submit(() -> {

591

Random random = new Random();

592

for (int i = 0; i < 50000; i++) {

593

// Simulate API latency: mostly fast, occasional slow responses

594

double latency = random.nextDouble() < 0.95

595

? 0.001 + random.nextDouble() * 0.099 // 95% fast: 1-100ms

596

: 1.0 + random.nextDouble() * 9.0; // 5% slow: 1-10s

597

598

histogram.recordValue(latency); // Thread-safe recording

599

}

600

});

601

}

602

603

// Coordinated analysis

604

WriterReaderPhaser phaser = histogram.getWriterReaderPhaser();

605

phaser.readerLock();

606

try {

607

System.out.printf("Packed memory usage: %d bytes%n",

608

histogram.getEstimatedFootprintInBytes());

609

610

double p95 = histogram.getValueAtPercentile(95.0);

611

double p99 = histogram.getValueAtPercentile(99.0);

612

613

System.out.printf("P95: %.3fs, P99: %.3fs%n", p95, p99);

614

} finally {

615

phaser.readerUnlock();

616

}

617

618

executor.shutdown();

619

```

620

621

## Thread Safety Summary

622

623

| Histogram Type | Recording Thread Safety | Query Thread Safety | Auto-Resize Support |

624

|---------------|------------------------|-------------------|-------------------|

625

| DoubleHistogram | No | No | Yes |

626

| ConcurrentDoubleHistogram | Yes (wait-free) | External sync needed | Yes |

627

| SynchronizedDoubleHistogram | Yes (synchronized) | Yes (synchronized) | Yes |

628

| PackedDoubleHistogram | No | No | Yes |

629

| PackedConcurrentDoubleHistogram | Yes (wait-free) | External sync needed | Yes |