Chronicle Core
This library wraps up low level access to
- Off Heap Memory Access
- JVM Access Methods
- OS Calls
- Resource Reference Counting
- Object Pools
- Class Local Caching
- Maths Functions for casting types, rounding double, faster hashing.
- Serializable Lambdas
- Histogram A high performance wide range histogram.
- JLBH Java Latency Benchmarking Harness.
Off Heap Memory Access
This allows you to access native memory using primitives and some thread safe operations.
Memory memory = OS.memory();
long address = memory.allocate(1024);
try {
memory.writeInt(address, 1);
assert memory.readInt(address) == 1;
final boolean swapped = memory.compareAndSwapInt(address, 1, 2);
assert swapped;
assert memory.readInt(address) == 2;
} finally {
memory.freeMemory(address, 1024);
}
JVM Access Methods
Check the JVM is running in debug mode
if (Jvm.isDebug()) {
// running in debug.
Rethrow a checked exception as an unchecked one.
try {
// IO operation
} catch (IOException ioe) {
throw Jvm.rethrow(ioe);
}
Get a Field for a Class by name
Field theUnsafe = Jvm.getField(Unsafe.class, "theUnsafe");
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
OS Calls
Access to system calls
int processId = OS.getProcessId();
int maxProcessId = OS.getMaxProcessId();
int pageSize = OS.getPageSize();
boolean isWindows = OS.isWindows();
boolean is64bit = OS.is64Bit();
String hostname = OS.getHostName();
String username = OS.getUserName();
String targetDir = OS.getTarget(); // where is the target directory during builds.
Memory mapped files
FileChannel fc = new RandomAccessFile(fileName, "rw").getChannel();
// map in 64 KiB
long address = OS.map(fc, MapMode.READ_WRITE, 0, 64 << 10);
// use address
OS.memory().writeLong(1024L, 0x1234567890ABCDEFL);
// unmap memory region
OS.unmap(address, 64 << 10);
Resource Reference Counting
Use reference counting to deterministically release resources.
MappedFile mf = MappedFile.mappedFile(tmp, chunkSize, 0);
MappedBytesStore bs = mf.acquireByteStore(chunkSize + (1 << 10));
assertEquals(2, mf.refCount());
assertEquals(3, bs.refCount());
assertEquals("refCount: 2, 0, 3", mf.referenceCounts());
mf.close();
assertEquals(2, bs.refCount());
assertEquals("refCount: 1, 0, 2", mf.referenceCounts());
bs2.release();
assertEquals(1, mf.refCount());
assertEquals(1, bs.refCount());
bs.release();
assertEquals(0, bs.refCount());
assertEquals(0, mf.refCount());
assertEquals("refCount: 0, 0, 0", mf.referenceCounts());
Object Pools
There is String and Enum object pools to turn a CharSequence into a String.
Bytes b = Bytes.from("Hello World");
b.readSkip(6);
StringInterner si = new StringInterner(128);
String s = si.intern(b);
String s2 = si.intern(b);
assertEquals("World", s);
assertSame(s, s2);
Class Local Caching
Add caching of a data structure for each class using a lambda
public static final ClassLocal<EnumInterner> ENUM_INTERNER =
ClassLocal.withInitial(c -> new EnumInterner<>(c));
E enumValue = ENUM_INTERNER.get(enumClass).intern(stringBuilder);
Maths Functions
Maths functions to support rounds
double a = 0.1;
double b = 0.3;
double c= Maths.round2(b - a); // 0.2 rounded to 2 decimal places
Checking type conversions
int i = Maths.toInt32(longValue);
Serializable Lambdas
There is a number of FunctionalInterfaces you can utilise as method arguments. This allows implicitly making a lambda Serializable.
// in KeyedVisitable
default <R> R applyToKey(K key, @NotNull SerializableFunction<E, R> function) {
// in code
String fullename = map.applyToKey("u:123223", u -> u.getFullName());
Histogram
A high dynamic range histogram with tunable accuracy.
Histogram h = new Histogram(32, 4);
long start = instance.ticks(), prev = start;
for (int i = 0; i <= 1000_000_000; i++) {
long now = instance.ticks();
long time = now - prev;
h.sample(time);
prev = now;
}
System.out.println(h.toLongMicrosFormat(instance::toMicros));
JLBH
Java Latency Benchmark Harness is a tool that allows you to benchmark your code running in context, rather than in a microbenchmark. An excellent introduction can be found in this series of articles.
Since those articles were written the main change has been to allow JLBH to be installed to an event loop, rather than it running in its own thread. To do this, use the JLBH.eventLoopHandler method rather than JLBH.start.