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

specialized-variants.mddocs/

0

# Specialized Histogram Variants

1

2

Memory-optimized histogram implementations designed for specific use cases and constraints. These variants trade off maximum count capacity or other features for reduced memory usage.

3

4

## IntCountsHistogram

5

6

HDR histogram using int arrays for count storage, providing lower memory usage with count limited to Integer.MAX_VALUE per bucket.

7

8

```java { .api }

9

public class IntCountsHistogram extends AbstractHistogram {

10

11

// Constructors

12

public IntCountsHistogram(int numberOfSignificantValueDigits);

13

public IntCountsHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

14

public IntCountsHistogram(long lowestDiscernibleValue,

15

long highestTrackableValue,

16

int numberOfSignificantValueDigits);

17

public IntCountsHistogram(AbstractHistogram source);

18

19

// Factory methods

20

static IntCountsHistogram decodeFromByteBuffer(ByteBuffer buffer,

21

long minBarForHighestTrackableValue);

22

static IntCountsHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

23

long minBarForHighestTrackableValue);

24

static IntCountsHistogram fromString(String base64CompressedHistogramString);

25

26

// Implementation methods

27

public IntCountsHistogram copy();

28

public IntCountsHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

29

}

30

```

31

32

### Usage Characteristics

33

34

**Memory Savings**: Approximately 50% memory usage compared to standard Histogram (int vs long arrays).

35

36

**Count Limitations**: Each bucket limited to 2,147,483,647 (Integer.MAX_VALUE) counts.

37

38

**Usage Examples:**

39

40

```java

41

// Create int counts histogram for moderate volume measurements

42

IntCountsHistogram histogram = new IntCountsHistogram(1_000_000, 3);

43

44

// Record values - same API as standard histogram

45

for (int i = 0; i < 1_000_000; i++) {

46

histogram.recordValue(ThreadLocalRandom.current().nextInt(1000));

47

}

48

49

// Analysis methods unchanged

50

double mean = histogram.getMean();

51

long p95 = histogram.getValueAtPercentile(95.0);

52

long totalCount = histogram.getTotalCount();

53

54

// Memory usage comparison

55

int intHistMemory = histogram.getEstimatedFootprintInBytes();

56

Histogram standardHist = new Histogram(1_000_000, 3);

57

int standardMemory = standardHist.getEstimatedFootprintInBytes();

58

59

System.out.printf("IntCountsHistogram: %d bytes%n", intHistMemory);

60

System.out.printf("Standard Histogram: %d bytes%n", standardMemory);

61

System.out.printf("Memory savings: %.1f%%%n",

62

100.0 * (standardMemory - intHistMemory) / standardMemory);

63

```

64

65

### When to Use IntCountsHistogram

66

67

**Good For:**

68

- Moderate to high volume measurements (< 2B samples per bucket)

69

- Memory-constrained environments

70

- Batch processing scenarios

71

- Latency measurements in typical applications

72

73

**Avoid When:**

74

- Extremely high-frequency measurements (risk of count overflow)

75

- Long-running cumulative histograms

76

- Situations where count precision is critical

77

78

## ShortCountsHistogram

79

80

HDR histogram using short arrays for count storage, providing minimal memory usage with count limited to Short.MAX_VALUE per bucket.

81

82

```java { .api }

83

public class ShortCountsHistogram extends AbstractHistogram {

84

85

// Constructors

86

public ShortCountsHistogram(int numberOfSignificantValueDigits);

87

public ShortCountsHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

88

public ShortCountsHistogram(long lowestDiscernibleValue,

89

long highestTrackableValue,

90

int numberOfSignificantValueDigits);

91

public ShortCountsHistogram(AbstractHistogram source);

92

93

// Factory methods

94

static ShortCountsHistogram decodeFromByteBuffer(ByteBuffer buffer,

95

long minBarForHighestTrackableValue);

96

static ShortCountsHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

97

long minBarForHighestTrackableValue);

98

static ShortCountsHistogram fromString(String base64CompressedHistogramString);

99

100

// Implementation methods

101

public ShortCountsHistogram copy();

102

public ShortCountsHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

103

}

104

```

105

106

### Usage Characteristics

107

108

**Memory Savings**: Approximately 75% memory usage reduction compared to standard Histogram.

109

110

**Count Limitations**: Each bucket limited to 32,767 (Short.MAX_VALUE) counts.

111

112

**Usage Examples:**

113

114

```java

115

// Create short counts histogram for low-volume or sampling scenarios

116

ShortCountsHistogram histogram = new ShortCountsHistogram(10_000, 2);

117

118

// Suitable for sampled data or low-frequency measurements

119

Random random = new Random();

120

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

121

if (random.nextDouble() < 0.1) { // 10% sampling rate

122

histogram.recordValue(random.nextInt(10000));

123

}

124

}

125

126

// Memory efficiency demonstration

127

int shortHistMemory = histogram.getEstimatedFootprintInBytes();

128

System.out.printf("ShortCountsHistogram memory: %d bytes%n", shortHistMemory);

129

130

// Same analysis capabilities

131

histogram.outputPercentileDistribution(System.out, 1.0);

132

```

133

134

### When to Use ShortCountsHistogram

135

136

**Good For:**

137

- Sampled measurements

138

- Proof-of-concept or testing scenarios

139

- Embedded systems with severe memory constraints

140

- Short-duration measurements

141

- Template or placeholder histograms

142

143

**Avoid When:**

144

- Production high-frequency recording

145

- Long-running cumulative measurements

146

- Applications where count accuracy is important

147

148

## PackedHistogram

149

150

Memory-optimized histogram using packed array representation, ideal for sparse value distributions with significant memory savings.

151

152

```java { .api }

153

public class PackedHistogram extends AbstractHistogram {

154

155

// Constructors

156

public PackedHistogram(int numberOfSignificantValueDigits);

157

public PackedHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

158

public PackedHistogram(long lowestDiscernibleValue,

159

long highestTrackableValue,

160

int numberOfSignificantValueDigits);

161

public PackedHistogram(AbstractHistogram source);

162

163

// Factory methods

164

static PackedHistogram decodeFromByteBuffer(ByteBuffer buffer,

165

long minBarForHighestTrackableValue);

166

static PackedHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

167

long minBarForHighestTrackableValue);

168

static PackedHistogram fromString(String base64CompressedHistogramString);

169

170

// Implementation methods

171

public PackedHistogram copy();

172

public PackedHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

173

}

174

```

175

176

### Packed Array Technology

177

178

PackedHistogram uses dynamic packed arrays that:

179

- Store only non-zero counts

180

- Compress data based on actual usage patterns

181

- Expand dynamically as needed

182

- Provide excellent memory efficiency for sparse data

183

184

### Usage Examples

185

186

```java

187

// Create packed histogram - excellent for sparse distributions

188

PackedHistogram histogram = new PackedHistogram(3);

189

190

// Record sparse data (many values have zero counts)

191

Random random = new Random();

192

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

193

// Sparse distribution - most values between 1000-2000, few outliers

194

if (random.nextDouble() < 0.95) {

195

histogram.recordValue(1000 + random.nextInt(1000)); // Dense region

196

} else {

197

histogram.recordValue(random.nextInt(1000000)); // Sparse outliers

198

}

199

}

200

201

// Memory efficiency shines with sparse data

202

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

203

histogram.getEstimatedFootprintInBytes());

204

205

// Compare with standard histogram for same data

206

Histogram standard = new Histogram(histogram);

207

System.out.printf("Standard histogram memory: %d bytes%n",

208

standard.getEstimatedFootprintInBytes());

209

210

// Full functionality preserved

211

double mean = histogram.getMean();

212

long p50 = histogram.getValueAtPercentile(50.0);

213

long p99 = histogram.getValueAtPercentile(99.0);

214

```

215

216

### Performance Characteristics

217

218

**Memory**: Excellent for sparse distributions, may use more memory for dense distributions.

219

220

**Performance**: Slight CPU overhead due to packing/unpacking operations.

221

222

**Auto-resize**: Supports auto-resizing with efficient memory management.

223

224

### When to Use PackedHistogram

225

226

**Ideal For:**

227

- Sparse value distributions

228

- Wide value ranges with clustered data

229

- Network latency measurements (many low values, few high outliers)

230

- Response time measurements with occasional timeouts

231

- Memory-constrained applications with sparse data

232

233

**Consider Alternatives For:**

234

- Uniformly distributed data

235

- CPU-critical recording paths

236

- Dense value distributions

237

238

## PackedConcurrentHistogram

239

240

Thread-safe version of PackedHistogram combining packed array memory efficiency with concurrent recording support.

241

242

```java { .api }

243

public class PackedConcurrentHistogram extends ConcurrentHistogram {

244

245

// Constructors

246

public PackedConcurrentHistogram(int numberOfSignificantValueDigits);

247

public PackedConcurrentHistogram(long highestTrackableValue, int numberOfSignificantValueDigits);

248

public PackedConcurrentHistogram(long lowestDiscernibleValue,

249

long highestTrackableValue,

250

int numberOfSignificantValueDigits);

251

public PackedConcurrentHistogram(AbstractHistogram source);

252

253

// Factory methods

254

static PackedConcurrentHistogram decodeFromByteBuffer(ByteBuffer buffer,

255

long minBarForHighestTrackableValue);

256

static PackedConcurrentHistogram decodeFromCompressedByteBuffer(ByteBuffer buffer,

257

long minBarForHighestTrackableValue);

258

259

// Implementation methods

260

public PackedConcurrentHistogram copy();

261

public PackedConcurrentHistogram copyCorrectedForCoordinatedOmission(long expectedInterval);

262

}

263

```

264

265

### Usage Examples

266

267

```java

268

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

269

PackedConcurrentHistogram histogram = new PackedConcurrentHistogram(3);

270

271

// Multiple threads recording sparse latency data

272

ExecutorService executor = Executors.newFixedThreadPool(8);

273

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

274

executor.submit(() -> {

275

Random random = new Random();

276

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

277

// Simulate network latency: mostly 1-10ms, occasional spikes

278

long latency = random.nextDouble() < 0.9

279

? 1000 + random.nextInt(9000) // Normal: 1-10ms

280

: 50000 + random.nextInt(950000); // Spikes: 50-1000ms

281

282

histogram.recordValue(latency); // Thread-safe, wait-free

283

}

284

});

285

}

286

287

// Coordinated reading (same as ConcurrentHistogram)

288

WriterReaderPhaser phaser = histogram.getWriterReaderPhaser();

289

phaser.readerLock();

290

try {

291

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

292

histogram.getEstimatedFootprintInBytes());

293

histogram.outputPercentileDistribution(System.out, 0.001); // Scale to ms

294

} finally {

295

phaser.readerUnlock();

296

}

297

298

executor.shutdown();

299

```

300

301

## Memory Usage Comparison

302

303

Here's a practical comparison of memory usage across variants:

304

305

```java

306

// Test configuration: 1M max value, 3 significant digits

307

int maxValue = 1_000_000;

308

int precision = 3;

309

310

// Create different histogram types

311

Histogram standard = new Histogram(maxValue, precision);

312

IntCountsHistogram intCounts = new IntCountsHistogram(maxValue, precision);

313

ShortCountsHistogram shortCounts = new ShortCountsHistogram(maxValue, precision);

314

PackedHistogram packed = new PackedHistogram(maxValue, precision);

315

316

// Record same sparse data pattern

317

Random random = new Random(12345); // Fixed seed for reproducible results

318

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

319

long value = random.nextDouble() < 0.8

320

? random.nextInt(1000) // 80% in range 0-1000

321

: random.nextInt(maxValue); // 20% spread across full range

322

323

standard.recordValue(value);

324

intCounts.recordValue(value);

325

shortCounts.recordValue(value);

326

packed.recordValue(value);

327

}

328

329

// Compare memory footprints

330

System.out.printf("Standard Histogram: %6d bytes%n",

331

standard.getEstimatedFootprintInBytes());

332

System.out.printf("IntCountsHistogram: %6d bytes (%.1f%% of standard)%n",

333

intCounts.getEstimatedFootprintInBytes(),

334

100.0 * intCounts.getEstimatedFootprintInBytes() / standard.getEstimatedFootprintInBytes());

335

System.out.printf("ShortCountsHistogram: %6d bytes (%.1f%% of standard)%n",

336

shortCounts.getEstimatedFootprintInBytes(),

337

100.0 * shortCounts.getEstimatedFootprintInBytes() / standard.getEstimatedFootprintInBytes());

338

System.out.printf("PackedHistogram: %6d bytes (%.1f%% of standard)%n",

339

packed.getEstimatedFootprintInBytes(),

340

100.0 * packed.getEstimatedFootprintInBytes() / standard.getEstimatedFootprintInBytes());

341

```

342

343

## Choosing the Right Specialized Variant

344

345

### Decision Matrix

346

347

| Use Case | Recommended Variant | Reason |

348

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

349

| Memory-constrained, moderate volume | IntCountsHistogram | 50% memory savings, reasonable count limits |

350

| Sampling/testing scenarios | ShortCountsHistogram | Maximum memory savings |

351

| Sparse distributions | PackedHistogram | Adaptive memory based on actual data |

352

| Concurrent sparse data | PackedConcurrentHistogram | Thread safety + memory efficiency |

353

| Dense uniform distributions | Standard Histogram | No packing overhead |

354

355

### Migration Considerations

356

357

All specialized variants maintain API compatibility:

358

359

```java

360

// Easy migration between variants

361

AbstractHistogram source = getExistingHistogram();

362

363

// Convert to memory-optimized variant

364

PackedHistogram optimized = new PackedHistogram(source);

365

366

// Or create concurrent version

367

PackedConcurrentHistogram concurrent = new PackedConcurrentHistogram(source);

368

369

// API remains identical

370

optimized.recordValue(1234);

371

long p99 = optimized.getValueAtPercentile(99.0);

372

```

373

374

### Performance Impact

375

376

**Recording Performance**:

377

- IntCountsHistogram: ~5-10% slower than standard (int vs long operations)

378

- ShortCountsHistogram: ~10-15% slower (type conversion overhead)

379

- PackedHistogram: ~20-30% slower (packing operations)

380

- PackedConcurrentHistogram: ~25-35% slower (packing + concurrency)

381

382

**Query Performance**:

383

- IntCountsHistogram: Equivalent to standard

384

- ShortCountsHistogram: Equivalent to standard

385

- PackedHistogram: ~10-20% slower (unpacking overhead)

386

- PackedConcurrentHistogram: Same as PackedHistogram for queries

387

388

**Memory vs Performance Trade-off**:

389

Choose based on whether memory savings outweigh performance costs in your specific use case.