# Mechanical Sympathy

Hardware and software working together in harmony

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Simple Binary Encoding

DevFeed: [Simple Binary Encoding](<https://devfeed.tech/articles/simple-binary-encoding-13635.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2014/05/simple-binary-encoding.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2014-05-05T19:01:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Finance](<https://devfeed.tech/topics/finance.md>), [Low Latency](<https://devfeed.tech/topics/low-latency.md>), [data](<https://devfeed.tech/topics/data.md>), [Parsing](<https://devfeed.tech/topics/parsing.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Java](<https://devfeed.tech/topics/java.md>), [.NET](<https://devfeed.tech/topics/net.md>)

Tags: [big-data](<https://devfeed.tech/tags/big-data.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [decoding](<https://devfeed.tech/tags/decoding.md>), [encoding](<https://devfeed.tech/tags/encoding.md>), [finance](<https://devfeed.tech/tags/finance.md>), [financial](<https://devfeed.tech/tags/financial.md>), [java](<https://devfeed.tech/tags/java.md>), [json](<https://devfeed.tech/tags/json.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [net](<https://devfeed.tech/tags/net.md>), [parsing](<https://devfeed.tech/tags/parsing.md>), [performance](<https://devfeed.tech/tags/performance.md>), [time](<https://devfeed.tech/tags/time.md>), [xml](<https://devfeed.tech/tags/xml.md>)

### AI overview

The article introduces FIX Simple Binary Encoding (SBE), a binary message codec designed to improve encoding and decoding efficiency for low-latency trading, especially market data. It describes reference implementations in Java, C++, and .NET and outlines design constraints such as placing variable-length fields at the end of messages.

### Source excerpt

Financial systems communicate by sending and receiving vast numbers of messages in many different formats. When people use terms like "vast" I normally think, "really..how many?" So lets quantify "vast" for the finance industry. Market data feeds from financial exchanges typically can be emitting tens or hundreds of thousands of message per second, and aggregate feeds like OPRA can peak at over 10 million messages per second with volumes growing year-on-year. This presentation gives a good overview. In this crazy world we still see significant use of ASCII encoded presentations, such as FIX tag value, and some more slightly sane binary encoded presentations like FAST. Some markets even commit the sin of sending out market data as XML! Well I cannot complain too much as they have at times provided me a good income writing ultra fast XML parsers. Last year the CME, who are a member the FIX community, commissioned Todd Montgomery, of 29West LBM fame, and myself to build the reference implementation of the new FIX Simple Binary Encoding (SBE) standard. SBE is a codec aimed at addressing the efficiency issues in low-latency trading, with a specific focus on market data. The CME, working within the FIX community, have done a great job of coming up with an encoding presentation that can be so efficient. Maybe a suitable atonement for the sins of past FIX tag value implementations. Todd and I worked on the Java and C++ implementation, and later we were helped on the .Net side by the amazing Olivier Deheurles at Adaptive. Working on a cool technical problem with such a team is a dream job. SBE Overview SBE is an OSI layer 6 presentation for encoding/decoding messages in binary format to support low-latency applications. Of the many applications I profile with performance issues, message encoding/decoding is often the most significant cost. I've seen many applications that spend significantly more CPU time parsing and transforming XML and JSON than executing business logic. S

## Lock-Based vs Lock-Free Concurrent Algorithms

DevFeed: [Lock-Based vs Lock-Free Concurrent Algorithms](<https://devfeed.tech/articles/lock-based-vs-lock-free-concurrent-algorithms-13634.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2013/08/lock-based-vs-lock-free-concurrent.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2013-08-26T10:48:00Z

Content type: opinion

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Java](<https://devfeed.tech/topics/java.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [algorithms](<https://devfeed.tech/tags/algorithms.md>), [atomic](<https://devfeed.tech/tags/atomic.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [java](<https://devfeed.tech/tags/java.md>), [jdk](<https://devfeed.tech/tags/jdk.md>), [lock-free](<https://devfeed.tech/tags/lock-free.md>), [locks](<https://devfeed.tech/tags/locks.md>), [performance](<https://devfeed.tech/tags/performance.md>), [review](<https://devfeed.tech/tags/review.md>), [test](<https://devfeed.tech/tags/test.md>)

### AI overview

This article reviews Java lock implementations, focusing on StampedLock and its optimistic-read design for systems with concurrent readers accessing shared state. It compares lock-based and lock-free approaches using a garbage-free spaceship-position API and a test harness across different threading and contention scenarios. The author argues that lock-free algorithms can often be a better solution for multiple-reader cases, while noting that results may vary across CPUs and operating systems.

### Source excerpt

Last week I attended a review session of the new JSR166 StampedLock run by Heinz Kabutz at the excellent JCrete unconference. StampedLock is an attempt to address the contention issues that arise in a system when multiple readers concurrently access shared state. StampedLock is designed to perform better than ReentrantReadWriteLock by taking an optimistic read approach. While attending the session a couple of things occurred to me. Firstly, I thought it was about time I reviewed the current status of Java lock implementations. Secondly, that although StampedLock looks like a good addition to the JDK, it seems to miss the fact that lock-free algorithms are often a better solution to the multiple reader case. Test Case To compare implementations I needed an API test case that would not favour a particular approach. For example, the API should be garbage free and allow the methods to be atomic. A simple test case is to design a spaceship that can be moved around a 2-dimensional space with the coordinates of its position available to be read atomically. At least 2 fields need to be read, or written, per transaction to make the concurrency interesting. /** * Interface to a concurrent representation of a ship that can move around * a 2 dimensional space with updates and reads performed concurrently. */ public interface Spaceship { /** * Read the position of the spaceship into the array of coordinates provided. * * @param coordinates into which the x and y coordinates should be read. * @return the number of attempts made to read the current state. */ int readPosition(final int[] coordinates); /** * Move the position of the spaceship by a delta to the x and y coordinates. * * @param xDelta delta by which the spaceship should be moved in the x-axis. * @param yDelta delta by which the spaceship should be moved in the y-axis. * @return the number of attempts made to write the new coordinates. */ int move(final int xDelta, final int yDelta); } The above API would be cleaner by

## Java Garbage Collection Distilled

DevFeed: [Java Garbage Collection Distilled](<https://devfeed.tech/articles/java-garbage-collection-distilled-13633.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2013/07/java-garbage-collection-distilled.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2013-07-16T19:45:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [openjdk](<https://devfeed.tech/topics/openjdk.md>), [Algorithms, Complexity](<https://devfeed.tech/topics/algorithms-complexity.md>), [systems](<https://devfeed.tech/topics/systems.md>)

Tags: [algorithms](<https://devfeed.tech/tags/algorithms.md>), [garbage-collection](<https://devfeed.tech/tags/garbage-collection.md>), [guide](<https://devfeed.tech/tags/guide.md>), [hotspot](<https://devfeed.tech/tags/hotspot.md>), [java](<https://devfeed.tech/tags/java.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [latency](<https://devfeed.tech/tags/latency.md>), [memory](<https://devfeed.tech/tags/memory.md>), [openjdk](<https://devfeed.tech/tags/openjdk.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

A guide to the tradeoffs involved in choosing and tuning Java garbage-collection algorithms for different workloads. It focuses on Oracle HotSpot and OpenJDK collectors and considers throughput, latency, and memory goals.

### Source excerpt

Serial, Parallel, Concurrent, CMS, G1, Young Gen, New Gen, Old Gen, Perm Gen, Eden, Tenured, Survivor Spaces, Safepoints, and the hundreds of JVM startup flags. Does this all baffle you when trying to tune the garbage collector while trying to get the required throughput and latency from your Java application? If it does then do not worry, you are not alone. Documentation describing garbage collection feels like man pages for an aircraft. Every knob and dial is detailed and explained but nowhere can you find a guide on how to fly. This article will attempt to explain the tradeoffs when choosing and tuning garbage collection algorithms for a particular workload. The focus will be on Oracle Hotspot JVM and OpenJDK collectors as those are the ones in most common usage. Towards the end other commercial JVMs will be discussed to illustrate alternatives. The Tradeoffs Wise folk keep telling us, "You do not get something for nothing". When we get something we usually have to give up something in return. When it comes to garbage collection we play with 3 major variables that set targets for the collectors: Throughput: The amount of work done by an application as a ratio of time spent in GC. Target throughput with -XX:GCTimeRatio=99 ; 99 is the default equating to 1% GC time. Latency: The time taken by systems in responding to events which is impacted by pauses introduced by garbage collection. Target latency for GC pauses with -XX:MaxGCPauseMillis=<n>. Memory: The amount of memory our systems use to store state, which is often copied and moved around when being managed. The set of active objects retained by the application at any point in time is known as the Live Set. Maximum heap size -Xmx<n> is a tuning parameter for setting the heap size available to an application. Note: Often Hotspot cannot achieve these targets and will silently continue without warning, having missed its target by a great margin. Latency is a distribution across events. It may be acceptable to have

## Printing Generated Assembly Code From The Hotspot JIT Compiler

DevFeed: [Printing Generated Assembly Code From The Hotspot JIT Compiler](<https://devfeed.tech/articles/printing-generated-assembly-code-from-the-hotspot-jit-compiler-13632.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2013/06/printing-generated-assembly-code-from.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2013-06-27T19:24:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [JIT](<https://devfeed.tech/topics/jit.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>)

Tags: [asm](<https://devfeed.tech/tags/asm.md>), [assembly](<https://devfeed.tech/tags/assembly.md>), [command-line](<https://devfeed.tech/tags/command-line.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [debugging](<https://devfeed.tech/tags/debugging.md>), [hotspot](<https://devfeed.tech/tags/hotspot.md>), [java](<https://devfeed.tech/tags/java.md>), [jit](<https://devfeed.tech/tags/jit.md>), [latency](<https://devfeed.tech/tags/latency.md>), [linux](<https://devfeed.tech/tags/linux.md>)

### AI overview

A tutorial on installing the Hotspot Disassembler Plugin and using Java command-line options to print generated assembly code for a targeted method. It uses a concurrent two-thread latency test involving volatile fields and explains how to inspect JIT-generated output.

### Source excerpt

Sometimes when profiling a Java application it is necessary to understand the assembly code generated by the Hotspot JIT compiler. This can be useful in determining what optimisation decisions have been made and how our code changes can affect the generated assembly code. It is also useful at times knowing what instructions are emitted when debugging a concurrent algorithm to ensure visibility rules have been applied as expected. I have found quite a few bugs in various JVMs this way. This blog illustrates how to install a Disassembler Plugin and provides command line options for targeting a particular method. Installation Previously it was necessary to obtain a debug build for printing the assembly code generated by the Hotspot JIT for the Oracle/SUN JVM. Since Java 7, it has been possible to print the generated assembly code if a Disassembler Plugin is installed in a standard Oracle Hotspot JVM. To install the plugin for 64-bit Linux follow the steps below: Download the appropriate binary, or build from source, from https://kenai.com/projects/base-hsdis/downloads On Linux rename linux-hsdis-amd64.so to libhsdis-amd64.so Copy the shared library to $JAVA_HOME/jre/lib/amd64/server You now have the plugin installed! Test Program To test the plugin we need some code that is both interesting to a programmer and executes sufficiently hot to be optimised by the JIT. Some details of when the JIT will optimise can be found here. The code below can be used to measure the average latency between two threads by reading and writing volatile fields. These volatile fields are interesting because they require associated hardware fences to honour the Java Memory Model. import static java.lang.System.out; public class InterThreadLatency { private static final int REPETITIONS = 100 * 1000 * 1000; private static volatile int ping = -1; private static volatile int pong = -1; public static void main(final String[] args) throws Exception { for (int i = 0; i < 5; i++) { final long duratio

## CPU Cache Flushing Fallacy

DevFeed: [CPU Cache Flushing Fallacy](<https://devfeed.tech/articles/cpu-cache-flushing-fallacy-13631.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2013/02/cpu-cache-flushing-fallacy.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2013-02-14T12:22:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Cache](<https://devfeed.tech/topics/cache.md>), [cpu](<https://devfeed.tech/topics/cpu.md>), [x86](<https://devfeed.tech/topics/x86.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [systems](<https://devfeed.tech/topics/systems.md>), [intel](<https://devfeed.tech/topics/intel.md>)

Tags: [cache-coherence](<https://devfeed.tech/tags/cache-coherence.md>), [core](<https://devfeed.tech/tags/core.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [cpu-cache](<https://devfeed.tech/tags/cpu-cache.md>), [intel](<https://devfeed.tech/tags/intel.md>), [ipc](<https://devfeed.tech/tags/ipc.md>), [latency](<https://devfeed.tech/tags/latency.md>), [memory-heirarchy](<https://devfeed.tech/tags/memory-heirarchy.md>), [performance](<https://devfeed.tech/tags/performance.md>), [systems](<https://devfeed.tech/tags/systems.md>), [x86](<https://devfeed.tech/tags/x86.md>)

### AI overview

The article explains why describing CPU-cache behavior as a cache "flush" can be misleading. It discusses cache hierarchies, interactions between caches and execution cores, memory latency, cache misses, and cache coherence, using Intel x86 server CPUs as a concrete example.

### Source excerpt

Even from highly experienced technologists I often hear talk about how certain operations cause a CPU cache to "flush". This seems to be illustrating a very common fallacy about how CPU caches work, and how the cache sub-system interacts with the execution cores. In this article I will attempt to explain the function CPU caches fulfil, and how the cores, which execute our programs of instructions, interact with them. For a concrete example I will dive into one of the latest Intel x86 server CPUs. Other CPUs use similar techniques to achieve the same ends. Most modern systems that execute our programs are shared-memory multi-processor systems in design. A shared-memory system has a single memory resource that is accessed by 2 or more independent CPU cores. Latency to main memory is highly variable from 10s to 100s of nanoseconds. Within 100ns it is possible for a 3.0GHz CPU to process up to 1200 instructions. Each Sandy Bridge core is capable of retiring up to 4 instructions-per-cycle (IPC) in parallel. CPUs employ cache sub-systems to hide this latency and allow them to exercise their huge capacity to process instructions. Some of these caches are small, very fast, and local to each core; others are slower, larger, and shared across cores. Together with registers and main-memory, these caches make up our non-persistent memory hierarchy. Next time you are developing an important algorithm, try pondering that a cache-miss is a lost opportunity to have executed ~500 CPU instructions! This is for a single-socket system, on a multi-socket system you can effectively double the lost opportunity as memory requests cross socket interconnects. Memory Hierarchy Figure 1. For the circa 2012 Sandy Bridge E class servers our memory hierarchy can be decomposed as follows: Registers: Within each core are separate register files containing 160 entries for integers and 144 floating point numbers. These registers are accessible within a single cycle and constitute the fastest memory a

## Further Adventures With CAS Instructions And Micro Benchmarking

DevFeed: [Further Adventures With CAS Instructions And Micro Benchmarking](<https://devfeed.tech/articles/further-adventures-with-cas-instructions-and-micro-benchmarking-13630.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2013/01/further-adventures-with-cas.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2013-01-25T17:59:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [benchmarking](<https://devfeed.tech/topics/benchmarking.md>), [Hardware](<https://devfeed.tech/topics/hardware.md>), [intel](<https://devfeed.tech/topics/intel.md>), [x86](<https://devfeed.tech/topics/x86.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Java](<https://devfeed.tech/topics/java.md>)

Tags: [assembly](<https://devfeed.tech/tags/assembly.md>), [benchmarking](<https://devfeed.tech/tags/benchmarking.md>), [cas](<https://devfeed.tech/tags/cas.md>), [hardware](<https://devfeed.tech/tags/hardware.md>), [intel](<https://devfeed.tech/tags/intel.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [performance](<https://devfeed.tech/tags/performance.md>), [techniques](<https://devfeed.tech/tags/techniques.md>), [x86](<https://devfeed.tech/tags/x86.md>)

### AI overview

This article revisits apparent CAS and LOCK instruction performance differences between Intel Sandy Bridge and Nehalem processors. It explains that the original microbenchmark partly measured fairness rather than throughput and examines alternative atomic-increment testing using lock xadd.

### Source excerpt

In a previous article I reported what appeared to be a performance issue with CAS/LOCK instructions on the Sandy Bridge microarchitecture compared to the previous Nehalem microarchitecture. Since then I've worked with the good people of Intel to understand what was going on and I'm now pleased to be able to shine some light on the previous results. I observed a small drop in throughput with the uncontended single-thread case, and an order-of-magnitude decrease in throughput once multiple threads contend when performing updates. This testing spawned out of observations testing Java Queue implementations and the Disruptor for the multi-producer case. I was initially puzzled by these findings because almost every other performance test I applied to Sandy Bridge indicated a major step forward for this microarchitecture. After digging deeper into this issue it has come to light that my tests have once again fallen fowl of the difficulties in micro-benchmarking. My test is not a good means of testing throughput and it is actually testing fairness in a roundabout manner. Let's revisit the code and work through what is going on. Test Code #include <time.h> #include <pthread.h> #include <stdlib.h> #include <iostream> typedef unsigned long long uint64; const uint64 COUNT = 500 * 1000 * 1000; volatile uint64 counter = 0; void* run_add(void* numThreads) { register uint64 value = (COUNT / *((int*)numThreads)) + 1; while (--value != 0) { __sync_add_and_fetch(&counter, 1); } } void* run_xadd(void*) { register uint64 value = counter; while (value < COUNT) { value = __sync_add_and_fetch(&counter, 1); } } void* run_cas(void*) { register uint64 value = 0; while (value < COUNT) { do { value = counter; } while (!__sync_bool_compare_and_swap(&counter, value, value + 1)); } } void* run_cas2(void*) { register uint64 value = 0; register uint64 next = 0; while (value < COUNT) { value = counter; do { next = value + 1; value = __sync_val_compare_and_swap(&counter, value, next); } while (value

## Mechanical Sympathy Discussion Group

DevFeed: [Mechanical Sympathy Discussion Group](<https://devfeed.tech/articles/mechanical-sympathy-discussion-group-13629.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/12/mechanical-sympathy-discussion-group.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-12-19T20:24:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Hardware](<https://devfeed.tech/topics/hardware.md>), [Software](<https://devfeed.tech/topics/software.md>), [coding](<https://devfeed.tech/topics/coding.md>)

Tags: [hardware](<https://devfeed.tech/tags/hardware.md>), [mechanical-sympathy](<https://devfeed.tech/tags/mechanical-sympathy.md>), [performance](<https://devfeed.tech/tags/performance.md>), [software](<https://devfeed.tech/tags/software.md>), [writing](<https://devfeed.tech/tags/writing.md>)

### AI overview

The author announces the launch of a discussion group about mechanical sympathy, focused on writing software that works in harmony with underlying hardware for better performance.

### Source excerpt

Lately a number of people have suggested I start a discussion group on the subject of mechanical sympathy, so I've taken the plunge and done it! The group can be a place to discuss topics related to writing software which works in harmony with the underlying hardware to gain great performance. https://groups.google.com/forum/?fromgroups#!forum/mechanical-sympathy

## Compact Off-Heap Structures/Tuples In Java

DevFeed: [Compact Off-Heap Structures/Tuples In Java](<https://devfeed.tech/articles/compact-off-heap-structures-tuples-in-java-13628.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/10/compact-off-heap-structurestuples-in.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-10-17T12:36:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [big-data](<https://devfeed.tech/topics/big-data.md>), [data](<https://devfeed.tech/topics/data.md>)

Tags: [arrays](<https://devfeed.tech/tags/arrays.md>), [big-data](<https://devfeed.tech/tags/big-data.md>), [code](<https://devfeed.tech/tags/code.md>), [garbage-collection](<https://devfeed.tech/tags/garbage-collection.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [memory-management](<https://devfeed.tech/tags/memory-management.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article explains how to simulate arrays of structures in Java using off-heap memory. It compares direct ByteBuffer with Unsafe, describing trade-offs involving memory layout, size limits, bounds checking, and performance, especially for large data sets and extreme-performance applications.

### Source excerpt

In my last post I detailed the implications of the access patterns your code takes to main memory. Since then I've had a lot of questions about what can be done in Java to enable more predictable memory layout. There are patterns that can be applied using array backed structures which I will discuss in another post. This post will explore how to simulate a feature sorely missing in Java - arrays of structures similar to what C has to offer. Structures are very useful, both on the stack and the heap. To my knowledge it is not possible to simulate this feature on the Java stack. Not being able to do this on the stack is such as shame because it greatly limits the performance of some parallel algorithms, however that is a rant for another day. In Java, all user defined types have to exist on the heap. The Java heap is managed by the garbage collector in the general case, however there is more to the wider heap in a Java process. With the introduction of direct ByteBuffer, memory can be allocated which is not tracked by the garbage collector because it can be available to native code for tasks like avoiding the copying of data to and from the kernel for IO. So one method of managing structures is to fake them within a ByteBuffer as a reasonable approach. This can allow compact data representations, but has performance and size limitations. For example, it is not possible to have a ByteBuffer greater than 2GB, and all access is bounds checked which impacts performance. An alternative exists using Unsafe that is both faster and and not size constrained like ByteBuffer. The approach I'm about to detail is not traditional Java. If your problem space is dealing with big data, or extreme performance, then there are benefits to be had. If your data sets are small, and performance is not an issue, then run away now to avoid getting sucked into the dark arts of native memory management. The benefits of the approach I'm about to detail are: Significantly improved performance More

## Memory Access Patterns Are Important

DevFeed: [Memory Access Patterns Are Important](<https://devfeed.tech/articles/memory-access-patterns-are-important-13627.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/08/memory-access-patterns-are-important.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-08-05T20:12:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Cache](<https://devfeed.tech/topics/cache.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Hardware](<https://devfeed.tech/topics/hardware.md>), [cpu](<https://devfeed.tech/topics/cpu.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [big-data](<https://devfeed.tech/tags/big-data.md>), [cache](<https://devfeed.tech/tags/cache.md>), [code](<https://devfeed.tech/tags/code.md>), [hardware](<https://devfeed.tech/tags/hardware.md>), [latency](<https://devfeed.tech/tags/latency.md>), [memory](<https://devfeed.tech/tags/memory.md>), [performance](<https://devfeed.tech/tags/performance.md>), [processors](<https://devfeed.tech/tags/processors.md>)

### AI overview

This article explains how processor cache hierarchies and memory-access patterns affect performance. It describes temporal, spatial, and striding patterns, then compares linear and increasingly random heap walks across CPU architectures. The results indicate that caches can hide main-memory latency more effectively for predictable access patterns, while larger memory regions and random access expose latency.

### Source excerpt

In high-performance computing it is often said that the cost of a cache-miss is the largest performance penalty for an algorithm. For many years the increase in speed of our processors has greatly outstripped latency gains to main-memory. Bandwidth to main-memory has greatly increased via wider, and multi-channel, buses however the latency has not significantly reduced. To hide this latency our processors employ evermore complex cache sub-systems that have many layers. The 1994 paper "Hitting the memory wall: implications of the obvious" describes the problem and goes on to argue that caches do not ultimately help because of compulsory cache-misses. I aim to show that by using access patterns which display consideration for the cache hierarchy, this conclusion is not inevitable. Let's start putting the problem in context with some examples. Our hardware tries to hide the main-memory latency via a number of techniques. Basically three major bets are taken on memory access patterns: Temporal: Memory accessed recently will likely be required again soon. Spatial: Adjacent memory is likely to be required soon. Striding: Memory access is likely to follow a predictable pattern. To illustrate these three bets in action let's write some code and measure the results. Walk through memory in a linear fashion being completely predictable. Pseudo randomly walk round memory within a restricted area then move on. This restricted area is what is commonly known as an operating system page of memory. Pseudo randomly walk around a large area of the heap. Code The following code should be run with the -Xmx4g JVM option. public class TestMemoryAccessPatterns { private static final int LONG_SIZE = 8; private static final int PAGE_SIZE = 2 * 1024 * 1024; private static final int ONE_GIG = 1024 * 1024 * 1024; private static final long TWO_GIG = 2L * ONE_GIG; private static final int ARRAY_SIZE = (int)(TWO_GIG / LONG_SIZE); private static final int WORDS_PER_PAGE = PAGE_SIZE / LONG_SIZE; pri

## Native C/C++ Like Performance For Java Object Serialisation

DevFeed: [Native C/C++ Like Performance For Java Object Serialisation](<https://devfeed.tech/articles/native-c-c-like-performance-for-java-object-serialisation-13626.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/07/native-cc-like-performance-for-java.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-07-05T17:51:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [IO](<https://devfeed.tech/topics/io.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Processes](<https://devfeed.tech/topics/processes.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [distributed](<https://devfeed.tech/tags/distributed.md>), [io](<https://devfeed.tech/tags/io.md>), [java](<https://devfeed.tech/tags/java.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [native](<https://devfeed.tech/tags/native.md>), [nio](<https://devfeed.tech/tags/nio.md>), [object](<https://devfeed.tech/tags/object.md>), [performance](<https://devfeed.tech/tags/performance.md>), [processes](<https://devfeed.tech/tags/processes.md>), [serialization](<https://devfeed.tech/tags/serialization.md>), [systems](<https://devfeed.tech/tags/systems.md>)

### AI overview

This article compares Java Serialization, a ByteBuffer-based binary protocol, and Unsafe-based serialization for converting Java objects to byte streams. It reports that Unsafe can reduce serialization time for a small object from about 10,000 nanoseconds to less than 100 nanoseconds, while binary approaches use fewer bytes than Java Serialization in the example.

### Source excerpt

Do you ever wish you could turn a Java object into a stream of bytes as fast as it can be done in a native language like C++? If you use standard Java Serialization you could be disappointed with the performance. Java Serialization was designed for a very different purpose than serialising objects as quickly and compactly as possible. Why do we need fast and compact serialisation? Many of our systems are distributed and we need to communicate by passing state between processes efficiently. This state lives inside our objects. I've profiled many systems and often a large part of the cost is the serialisation of this state to-and-from byte buffers. I've seen a significant range of protocols and mechanisms used to achieve this. At one end of the spectrum are the easy to use but inefficient protocols likes Java Serialisation, XML and JSON. At the other end of this spectrum are the binary protocols that can be very fast and efficient but they require a deeper understanding and skill. In this article I will illustrate the performance gains that are possible when using simple binary protocols and introduce a little known technique available in Java to achieve similar performance to what is possible with native languages like C or C++. The three approaches to be compared are: Java Serialization: The standard method in Java of having an object implement Serializable. Binary via ByteBuffer: A simple protocol using the ByteBuffer API to write the fields of an object in binary format. This is our baseline for what is considered a good binary encoding approach. Binary via Unsafe: Introduction to Unsafe and its collection of methods that allow direct memory manipulation. Here I will show how to get similar performance to C/C++. The Code import sun.misc.Unsafe; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.nio.By

## Applying Back Pressure When Overloaded

DevFeed: [Applying Back Pressure When Overloaded](<https://devfeed.tech/articles/applying-back-pressure-when-overloaded-13625.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/05/apply-back-pressure-when-overloaded.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-05-19T21:17:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [systems](<https://devfeed.tech/topics/systems.md>), [Transactions](<https://devfeed.tech/topics/transactions.md>), [Latency](<https://devfeed.tech/topics/latency.md>)

Tags: [capacity](<https://devfeed.tech/tags/capacity.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [performance](<https://devfeed.tech/tags/performance.md>), [queuing](<https://devfeed.tech/tags/queuing.md>), [systems](<https://devfeed.tech/tags/systems.md>), [transactions](<https://devfeed.tech/tags/transactions.md>)

### AI overview

The article explains how systems under sustained load can use back pressure to maintain throughput and acceptable response times by rejecting requests beyond processing capacity. It warns that unbounded queues increase latency and can consume all available memory, causing system failure.

### Source excerpt

How should a system respond when under sustained load? Should it keep accepting requests until its response times follow the deadly hockey stick, followed by a crash? All too often this is what happens unless a system is designed to cope with the case of more requests arriving than it is capable of processing. If we are seeing a sustained arrival rate of requests, greater than our system is capable of processing, then something has to give. Having the entire system degrade is not the ideal service we want to give our customers. A better approach would be to process transactions at our systems maximum possible throughput rate, while maintaining a good response time, and rejecting requests above this arrival rate. Let's consider a small art gallery as an metaphor. In this gallery the typical viewer spends on average 20 minutes browsing, and the gallery can hold a maximum of 30 viewers. If more than 30 viewers occupy the gallery at the same time then customers become unhappy because they cannot have a clear view of the paintings. If this happens they are unlikely to purchase or return. To keep our viewers happy it is better to recommend that some viewers visit the café a few doors down and come back when the gallery is less busy. This way the viewers in the gallery get to see all the paintings without other viewers in the way, and in the meantime those we cannot accommodate enjoy a coffee. If we apply Little's Law we cannot have customers arriving at more than 90 per hour, otherwise the maximum capacity is exceeded. If between 9:00-10:00 they are arriving at 100 per hour, then I'm sure the café down the road will appreciate the extra 10 customers. Within our systems the available capacity is generally a function of the size of our thread pools and time to process individual transactions. These thread pools are usually fronted by queues to handle bursts of traffic above our maximum arrival rate. If the queues are unbounded, and we have a sustained arrival rate above the

## Invoke Interface Optimisations

DevFeed: [Invoke Interface Optimisations](<https://devfeed.tech/articles/invoke-interface-optimisations-13624.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/04/invoke-interface-optimisations.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-04-29T10:22:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [Code](<https://devfeed.tech/topics/code.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [inlining](<https://devfeed.tech/tags/inlining.md>), [intel](<https://devfeed.tech/tags/intel.md>), [java](<https://devfeed.tech/tags/java.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [kernel](<https://devfeed.tech/tags/kernel.md>), [linux](<https://devfeed.tech/tags/linux.md>), [optimisations](<https://devfeed.tech/tags/optimisations.md>), [performance](<https://devfeed.tech/tags/performance.md>), [processor](<https://devfeed.tech/tags/processor.md>)

### AI overview

This article explains how the HotSpot JVM dynamically inlines methods at runtime, including methods invoked through interfaces and overridden methods. It describes the relevant Java bytecode instructions and presents benchmark results from a Linux system using Oracle's Java 1.7.0_02 server JVM.

### Source excerpt

I'm often asked about the performance differences between Java, C, and C++, and which is better. As with most things in life there is no black and white answer. A lot is often discussed about how managed runtime based languages offer less performance than their statically compiled compatriots. There are however a few tricks available to managed runtimes that can provide optimisation opportunities not available to statically optimised languages. One such optimisation available to the runtime is to dynamically inline a method at the call site. Many would say inlining is *the* major optimisation of dynamic languages. This is an approach whereby the function/method call overhead can be avoided and further optimisations enabled. Inlining can easily be done at compile, or run, time for static or private methods of a class because they cannot be overridden. It can also be done by Hotspot at run time which is way more interesting. In bytecode the runtime will see invokestatic and invokespecial opcodes for static and private methods respectively. Methods that involve late binding, such as interface implementations and method overriding, appear as the invokeinterface and invokevirtual opcodes respectively. At compile time it is not possible to determine how many implementations there will be for an interface, or how many classes will override a base method. The compiler can have some awareness but just how do you deal with dynamically loaded classes via Class.forName("x").newInstance()? The Hotspot runtime is very smart. It can track all classes as they are loaded and apply appropriate optimisations to give the best possible performance for our code. One such approach is dynamic inlining at the call site which we will explore. Code public interface Operation { int map(int value); } public class IncOperation implements Operation { public int map(final int value) { return value + 1; } } public class DecOperation implements Operation { public int map(final int value) { return va

## Fun with my-Channels Nirvana and Azul Zing

DevFeed: [Fun with my-Channels Nirvana and Azul Zing](<https://devfeed.tech/articles/fun-with-my-channels-nirvana-and-azul-zing-13623.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2012/03/fun-with-my-channels-nirvana-and-azul.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2012-03-22T17:55:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Low Latency](<https://devfeed.tech/topics/low-latency.md>), [Messaging](<https://devfeed.tech/topics/messaging.md>), [Java](<https://devfeed.tech/topics/java.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [ipc](<https://devfeed.tech/tags/ipc.md>), [java](<https://devfeed.tech/tags/java.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [messaging](<https://devfeed.tech/tags/messaging.md>)

### AI overview

An engineering article examines my-Channels' low-latency messaging system under load. Profiling identified lock contention as the main limit on latency and throughput; replacing the standard Java executor with a lock-free executor produced tests showing about 10x better performance and enabled 16x more throughput.

### Source excerpt

Since leaving LMAX I have been neglecting my blog a bit. This is not because I have not been doing anything interesting. Quite the opposite really, things have been so busy the blog has taken a back seat. I've been consulting for a number of hedge funds and product companies, most of which are super secretive. One company I have been spending quite a bit of time with is my-Channels, a messaging provider. They are really cool and have given me their blessing to blog about some of the interesting things I've been working on for them. For context, my-Channels are a messaging provider that specialise in delivering data to every device known to man over dodgy networks such as the Internet or your corporate WAN. They can deliver live financial market data to your desktop, laptop at home, or your iPhone, at the fastest possible rates. Lately, they have made the strategic move to enter the low-latency messaging space for the enterprise, and as part of this they have enlisted my services. They want to go low-latency without giving up the rich functionality their product offers which is giving me some interesting challenges. Just how bad is the latency of such a product when new to the low-latency space? I did not have high expectations because to be fair this was never their goal. After some initial tests, I'm thinking these guys are not in bad shape. They beat the crap out of most JMS implementations and it is going to be fun pushing them to the serious end of the low-latency space. OK enough of the basic tests, now it is time to get serious. I worked with them to create appropriate load tests and get the profilers running. No big surprises here, when we piled on the pressure, lock-contention came out as the biggest culprit limiting both latency and throughput. As we go down the list, lots of other interesting things showed up but let's follow good discipline and start at the top of the list. Good discipline for "Theory of Constraints" states that you always work on the mos

## Java Sequential IO Performance

DevFeed: [Java Sequential IO Performance](<https://devfeed.tech/articles/java-sequential-io-performance-13622.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/12/java-sequential-io-performance.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-12-26T19:47:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [IO](<https://devfeed.tech/topics/io.md>), [Filesystems](<https://devfeed.tech/topics/filesystems.md>), [Cache](<https://devfeed.tech/topics/cache.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Logging](<https://devfeed.tech/topics/logging.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [data](<https://devfeed.tech/tags/data.md>), [database](<https://devfeed.tech/tags/database.md>), [files](<https://devfeed.tech/tags/files.md>), [io](<https://devfeed.tech/tags/io.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [nio](<https://devfeed.tech/tags/nio.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article examines the performance characteristics of Java mechanisms for sequentially writing to and reading from files. It focuses on pre-allocated files, explaining how contiguous blocks and filesystem metadata affect access, and describes tests using 400 MB and 8 GB files under different cache conditions.

### Source excerpt

Many applications record a series of events to file-based storage for later use. This can be anything from logging and auditing, through to keeping a transaction redo log in an event sourced design or its close relative CQRS. Java has a number of means by which a file can be sequentially written to, or read back again. This article explores some of these mechanisms to understand their performance characteristics. For the scope of this article I will be using pre-allocated files because I want to focus on performance. Constantly extending a file imposes a significant performance overhead and adds jitter to an application resulting in highly variable latency. "Why is a pre-allocated file better performance?", I hear you ask. Well, on disk a file is made up from a series of blocks/pages containing the data. Firstly, it is important that these blocks are contiguous to provide fast sequential access. Secondly, meta-data must be allocated to describe this file on disk and saved within the file-system. A typical large file will have a number of "indirect" blocks allocated to describe the chain of data-blocks containing the file contents that make up part of this meta-data. I'll leave it as an exercise for the reader, or maybe a later article, to explore the performance impact of not preallocating the data files. If you have used a database you may have noticed that it preallocates the files it will require. The Test I want to experiment with 2 file sizes. One that is sufficiently large to test sequential access, but can easily fit in the file-system cache, and another that is much larger so that the cache subsystem is forced to retire pages so that new ones can be loaded. For these two cases I'll use 400MB and 8GB respectively. I'll also loop over the files a number of times to show the pre and post warm-up characteristics. I'll test 4 means of writing and reading back files sequentially: RandomAccessFile using a vanilla byte[] of page size. Buffered FileInputStream and Fi

## Biased Locking, OSR, and Benchmarking Fun

DevFeed: [Biased Locking, OSR, and Benchmarking Fun](<https://devfeed.tech/articles/biased-locking-osr-and-benchmarking-fun-13619.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/11/biased-locking-osr-and-benchmarking-fun.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-11-22T16:36:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [benchmarking](<https://devfeed.tech/topics/benchmarking.md>), [Java](<https://devfeed.tech/topics/java.md>), [JIT](<https://devfeed.tech/topics/jit.md>)

Tags: [azul](<https://devfeed.tech/tags/azul.md>), [benchmarking](<https://devfeed.tech/tags/benchmarking.md>), [java](<https://devfeed.tech/tags/java.md>), [jit](<https://devfeed.tech/tags/jit.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [locking](<https://devfeed.tech/tags/locking.md>), [locks](<https://devfeed.tech/tags/locks.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [performance](<https://devfeed.tech/tags/performance.md>), [profiling](<https://devfeed.tech/tags/profiling.md>), [testing](<https://devfeed.tech/tags/testing.md>)

### AI overview

This article revisits an experiment on Java biased locking after accounting for JVM warm-up behavior. It explains On Stack Replacement and JIT compilation, and argues that several shorter warm-up runs can produce better-optimized code than one long warm-up when designing micro-benchmarks.

### Source excerpt

After my last post on Java Lock Implementations, I got a lot of good feedback about my results and micro-benchmark design approach. As a result I now understand JVM warmup, On Stack Replacement (OSR) and Biased Locking somewhat better than before. Special thanks to Dave Dice from Oracle, and Cliff Click & Gil Tene from Azul, for their very useful feedback. In the last post I concluded, based on my experiments, that biased locking was no longer necessary on modern CPUs. While this conclusion is understandable given the data gathered in the experiment, it was not valid because the experiment did not take account of some JVM warm up behaviour that I was unaware of. In this post I will re-run the experiment taking into account the feedback and present some new results. I shall also expand on the changes I've made to the test and why it is important to consider the JVM warm-up behaviour when writing micro-benchmarks, or even very lean Java applications with quick start up time. On Stack Replacement (OSR) Java virtual machines will compile code to achieve greater performance based on runtime profiling. Some VMs run an interpreter for the majority of code and replace hot areas with compiled code following the 80/20 rule. Other VMs compile all code simply at first then replace the simple code with more optimised code based on profiling. Oracle Hotspot and Azul are examples of the first type and Oracle JRockit is an example of the second. Oracle Hotspot will count invocations of a method return plus branch backs for loops in that method, and if this exceeds 10K in server mode the method will be compiled. The compiled code on normal JIT'ing can be used when the method is next called. However if a loop is still iterating it may make sense to replace the method before the loop completes, especially if it has many iterations to go. OSR is the means by which a method gets replaced with a compiled version part way through iterating a loop. I was under the impression that normal JI

## Java Lock Implementations

DevFeed: [Java Lock Implementations](<https://devfeed.tech/articles/java-lock-implementations-13620.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/11/java-lock-implementations.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-11-19T02:57:00Z

Content type: comparison

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [x86](<https://devfeed.tech/topics/x86.md>), [Linux](<https://devfeed.tech/topics/linux.md>)

Tags: [concurrent](<https://devfeed.tech/tags/concurrent.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [java](<https://devfeed.tech/tags/java.md>), [linux](<https://devfeed.tech/tags/linux.md>), [lock-free](<https://devfeed.tech/tags/lock-free.md>), [locking](<https://devfeed.tech/tags/locking.md>), [locks](<https://devfeed.tech/tags/locks.md>), [ordering](<https://devfeed.tech/tags/ordering.md>), [performance](<https://devfeed.tech/tags/performance.md>), [tests](<https://devfeed.tech/tags/tests.md>), [x86](<https://devfeed.tech/tags/x86.md>)

### AI overview

This article compares Java lock implementations, including atomic locking on language monitors, biased locking, and ReentrantLock. It describes a test measuring lock costs under increasing contention on Intel CPUs using Linux and Oracle JDK 1.6.0_29, and recommends measuring applications before choosing JVM lock settings.

### Source excerpt

We all use 3rd party libraries as a normal part of development. Generally, we have no control over their internals. The libraries provided with the JDK are a typical example. Many of these libraries employ locks to manage contention. JDK locks come with two implementations. One uses atomic CAS style instructions to manage the claim process. CAS instructions tend to be the most expensive type of CPU instructions and on x86 have memory ordering semantics. Often locks are un-contended which gives rise to a possible optimisation whereby a lock can be biased to the un-contended thread using techniques to avoid the use of atomic instructions. This biasing allows a lock in theory to be quickly reacquired by the same thread. If the lock turns out to be contended by multiple threads the algorithm with revert from being biased and fall back to the standard approach using atomic instructions. Biased locking became the default lock implementation with Java 6. When respecting the single writer principle, biased locking should be your friend. Lately, when using the sockets API, I decided to measure the lock costs and was surprised by the results. I found that my un-contended thread was incurring a bit more cost than I expected from the lock. I put together the following test to compare the cost of the current lock implementations available in Java 6. The Test For the test I shall increment a counter within a lock, and increase the number of contending threads on the lock. This test will be repeated for the 3 major lock implementations available to Java: Atomic locking on Java language monitors Biased locking on Java language monitors ReentrantLock introduced with the java.util.concurrent package in Java 5. I'll also run the tests on the 3 most recent generations of the Intel CPU. For each CPU I'll execute the tests up to the maximum number of concurrent threads the core count will support. The tests are carried out with 64-bit Linux (Fedora Core 15) and Oracle JDK 1.6.0_29. The C

## Locks & Condition Variables - Latency Impact

DevFeed: [Locks & Condition Variables - Latency Impact](<https://devfeed.tech/articles/locks-condition-variables-latency-impact-13621.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/11/locks-condition-variables-latency.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-11-05T13:52:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Latency](<https://devfeed.tech/topics/latency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Java](<https://devfeed.tech/topics/java.md>), [Low Latency](<https://devfeed.tech/topics/low-latency.md>), [Linux](<https://devfeed.tech/topics/linux.md>)

Tags: [infiniband](<https://devfeed.tech/tags/infiniband.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [linux](<https://devfeed.tech/tags/linux.md>), [locks](<https://devfeed.tech/tags/locks.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [performance](<https://devfeed.tech/tags/performance.md>), [thread](<https://devfeed.tech/tags/thread.md>), [threads](<https://devfeed.tech/tags/threads.md>), [windows](<https://devfeed.tech/tags/windows.md>)

### AI overview

This article measures the latency impact of using locks and condition variables to pass control between two Java threads. It reports that kernel arbitration and thread scheduling add substantially more latency than signaling with memory barriers, and that allowing the operating system to schedule threads across different cores can hurt low-latency performance through cache pollution.

### Source excerpt

In a previous article on Inter-Thread Latency I showed how it is possible to signal a state change between 2 threads with less than 50ns of latency. To many developers, writing concurrent code using locks is a scary experience. Writing concurrent code using lock-free algorithms, i.e. algorithms that rely on the use of memory barriers and an intimate understanding of the underlying memory models, can be totally terrifying. To me lock-free / non-blocking algorithms are like playing with explosives or corrosive chemicals, if you do not understand what you are doing, or show the ultimate respect, then very bad things can, and most likely will, happen! In this article, I'd like to illustrate the impact of using locks and the resulting latency they can impose on your designs. I want to use a very similar algorithm to that used in my previous inter-thread latency article to illustrate the ping-pong effect of handing control back and forth between 2 threads. In this case, rather than using a couple of volatile variables, I will employ a pair of condition variables to signal a state change so control can be passed back and forth. The Code import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static java.lang.System.out; public final class LockedSignallingLatency { private static final int ITERATIONS = 10 * 1000 * 1000; private static final Lock lock = new ReentrantLock(); private static final Condition sendCondition = lock.newCondition(); private static final Condition echoCondition = lock.newCondition(); private static long sendValue = -1L; private static long echoValue = -1L; public static void main(final String[] args) throws Exception { final Thread sendThread = new Thread(new SendRunner()); final Thread echoThread = new Thread(new EchoRunner()); final long start = System.nanoTime(); echoThread.start(); sendThread.start(); sendThread.join(); echoThread.join(); final long duration = Sys

## Smart Batching

DevFeed: [Smart Batching](<https://devfeed.tech/articles/smart-batching-13618.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/10/smart-batching.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-10-19T16:44:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Latency](<https://devfeed.tech/topics/latency.md>), [Low Latency](<https://devfeed.tech/topics/low-latency.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [Code](<https://devfeed.tech/topics/code.md>), [IO](<https://devfeed.tech/topics/io.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Network](<https://devfeed.tech/topics/network.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Filesystems](<https://devfeed.tech/topics/filesystems.md>), [Database](<https://devfeed.tech/topics/database.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [batching](<https://devfeed.tech/tags/batching.md>), [code](<https://devfeed.tech/tags/code.md>), [data](<https://devfeed.tech/tags/data.md>), [data-structures](<https://devfeed.tech/tags/data-structures.md>), [distributed](<https://devfeed.tech/tags/distributed.md>), [io](<https://devfeed.tech/tags/io.md>), [java](<https://devfeed.tech/tags/java.md>), [latency](<https://devfeed.tech/tags/latency.md>), [locks](<https://devfeed.tech/tags/locks.md>), [low-latency](<https://devfeed.tech/tags/low-latency.md>), [network](<https://devfeed.tech/tags/network.md>), [networking](<https://devfeed.tech/tags/networking.md>), [performance](<https://devfeed.tech/tags/performance.md>), [queue](<https://devfeed.tech/tags/queue.md>), [systems](<https://devfeed.tech/tags/systems.md>), [thread](<https://devfeed.tech/tags/thread.md>), [threads](<https://devfeed.tech/tags/threads.md>)

### AI overview

The article explains how correctly designed batching can improve throughput while reducing and stabilizing average latency. It discusses batching messages for network packets and storage writes, and presents a Java approach that sends immediately when data is available while grouping bursts up to a buffer limit. The approach can avoid lock contention, but an unbounded queue may require size tracking and back pressure.

### Source excerpt

How often have we all heard that "batching" will increase latency? As someone with a passion for low-latency systems this surprises me. In my experience when batching is done correctly, not only does it increase throughput, it can also reduce average latency and keep it consistent. Well then, how can batching magically reduce latency? It comes down to what algorithm and data structures are employed. In a distributed environment we are often having to batch up messages/events into network packets to achieve greater throughput. We also employ similar techniques in buffering writes to storage to reduce the number of IOPS. That storage could be a block device backed file-system or a relational database. Most IO devices can only handle a modest number of IO operations per second, so it is best to fill those operations efficiently. Many approaches to batching involve waiting for a timeout to occur and this will by its very nature increase latency. The batch can also get filled before the timeout occurs making the latency even more unpredictable. Figure 1. Figure 1. above depicts decoupling the access to an IO device, and therefore the contention for access to it, by introducing a queue like structure to stage the messages/events to be sent and a thread doing the batching for writing to the device. The Algorithm An approach to batching uses the following algorithm in Java pseudo code: public final class NetworkBatcher implements Runnable { private final NetworkFacade network; private final Queue<Message> queue; private final ByteBuffer buffer; public NetworkBatcher(final NetworkFacade network, final int maxPacketSize, final Queue<Message> queue) { this.network = network; buffer = ByteBuffer.allocate(maxPacketSize); this.queue = queue; } public void run() { while (!Thread.currentThread().isInterrupted()) { while (null == queue.peek()) { employWaitStrategy(); // block, spin, yield, etc. } Message msg; while (null != (msg = queue.poll())) { if (msg.size() > buffer.remaining()

## Single Writer Principle

DevFeed: [Single Writer Principle](<https://devfeed.tech/articles/single-writer-principle-13617.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/09/single-writer-principle.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-09-22T14:24:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Scalability](<https://devfeed.tech/topics/scalability.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Operating system](<https://devfeed.tech/topics/operating-system.md>), [Kernel](<https://devfeed.tech/topics/kernel.md>), [cpu](<https://devfeed.tech/topics/cpu.md>)

Tags: [concurrency](<https://devfeed.tech/tags/concurrency.md>), [concurrency-control](<https://devfeed.tech/tags/concurrency-control.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [cycles](<https://devfeed.tech/tags/cycles.md>), [intel](<https://devfeed.tech/tags/intel.md>), [kernel](<https://devfeed.tech/tags/kernel.md>), [latency](<https://devfeed.tech/tags/latency.md>), [performance](<https://devfeed.tech/tags/performance.md>), [processor-affinity](<https://devfeed.tech/tags/processor-affinity.md>), [scalability](<https://devfeed.tech/tags/scalability.md>)

### AI overview

The article explains that contention among multiple writers is a major scalability limitation. It compares mutual exclusion, typically implemented with locks, with optimistic concurrency control, describing how contention can increase queuing, latency, and reduce throughput.

### Source excerpt

When trying to build a highly scalable system the single biggest limitation on scalability is having multiple writers contend for any item of data or resource. Sure, algorithms can be bad, but let's assume they have a reasonable Big O notation so we'll focus on the scalability limitations of the systems design. I keep seeing people just accept having multiple writers as the norm. There is a lot of research in computer science for managing this contention that boils down to 2 basic approaches. One is to provide mutual exclusion to the contended resource while the mutation takes place; the other is to take an optimistic strategy and swap in the changes if the underlying resource has not changed while you created the new copy. Mutual Exclusion Mutual exclusion is the means by which only one writer can have access to a protected resource at a time, and is usually implemented with a locking strategy. Locking strategies require an arbitrator, usually the operating system kernel, to get involved when the contention occurs to decide who gains access and in what order. This can be a very expensive process often requiring many more CPU cycles than the actual transaction to be applied to the business logic would use. Those waiting to enter the critical section, in advance of performing the mutation must queue, and this queuing effect (Little's Law) causes latency to become unpredictable and ultimately restricts throughput. Optimistic Concurrency Control Optimistic strategies involve taking a copy of the data, modifying it, then copying back the changes if data has not mutated in the meantime. If a change has happened in the meantime you repeat the process until successful. This repeating of the process increases with contention and therefore causes a queuing effect just like with mutual exclusion. If you work with a source code control system, such as Subversion or CVS, then you are using this algorithm every day. Optimistic strategies can work with data but do not work so wel

## Adventures with AtomicLong

DevFeed: [Adventures with AtomicLong](<https://devfeed.tech/articles/adventures-with-atomiclong-13615.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/09/adventures-with-atomiclong.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-09-11T11:46:00Z

Content type: article

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Java](<https://devfeed.tech/topics/java.md>), [Benchmark](<https://devfeed.tech/topics/benchmark.md>), [intel](<https://devfeed.tech/topics/intel.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [atomic](<https://devfeed.tech/tags/atomic.md>), [benchmark](<https://devfeed.tech/tags/benchmark.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [cas](<https://devfeed.tech/tags/cas.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [disruptor](<https://devfeed.tech/tags/disruptor.md>), [intel](<https://devfeed.tech/tags/intel.md>), [java](<https://devfeed.tech/tags/java.md>), [performance](<https://devfeed.tech/tags/performance.md>)

### AI overview

This article examines AtomicLong-based event sequencing in Java's Disruptor and reports unexpectedly worse performance after removing megamorphic method calls. The investigation attributes the result to increased contention exposing a performance issue with atomic instructions on Intel Sandy Bridge processors, also observed in ArrayBlockingQueue.

### Source excerpt

Sequencing events between threads is a common operation for many multi-threaded algorithms. These sequences could be used for assigning identity to orders, trades, transactions, messages, events, etc. Within the Disruptor we use a monotonic sequence for all events which is implemented as AtomicLong incrementAndGet for the multi-threaded publishing scenario. While working on the latest version of the Disruptor I made some changes which I was convinced would improve performance, however the results surprised me. I had removed some potentially megamorphic method calls and the performance got worse rather than better. After a lot of investigation, I discovered that the megamorphic method calls were hiding a performance issue with the latest Intel Sandybridge processors. With the megamorphic calls out of the way, the contention on the atomic sequence generation increased exposing the issue. I've also observed this performance issue with other Java concurrent structures such as ArrayBlockingQueue. I've been running various benchmarks on Sandybridge and have so far been impressed with performance improvements over Nehalem, especially for memory intensive applications due to the changes in its front-end. However with this sequencing benchmark, I discovered that Sandybridge has taken a major step backward in performance with regard to atomic instructions. Atomic instructions enable read-modify-write actions to be combined into an atomic operation. A good example is incrementing a counter. To complete the increment operation a thread must read the current value, increment it, and then write back the results. In a multi-threaded environment these distinct operations could interleave with other threads doing the same with corrupt results as a consequence. The normal way to avoid this interleaving is to take out a lock for mutual exclusion while performing the steps. Locks are very expensive and often require kernel arbitration between threads. Modern CPUs provide a number of at

## Modelling Is Everything

DevFeed: [Modelling Is Everything](<https://devfeed.tech/articles/modelling-is-everything-13616.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/09/modelling-is-everything.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-09-02T18:23:00Z

Content type: opinion

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Domain-driven design (DDD)](<https://devfeed.tech/topics/domain-driven-design.md>), [systems](<https://devfeed.tech/topics/systems.md>), [Development](<https://devfeed.tech/topics/development.md>), [Code](<https://devfeed.tech/topics/code.md>), [Cache](<https://devfeed.tech/topics/cache.md>), [cpu](<https://devfeed.tech/topics/cpu.md>), [Network](<https://devfeed.tech/topics/network.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [ddd](<https://devfeed.tech/tags/ddd.md>), [design](<https://devfeed.tech/tags/design.md>), [development](<https://devfeed.tech/tags/development.md>), [domain-driven-design](<https://devfeed.tech/tags/domain-driven-design.md>), [modelling](<https://devfeed.tech/tags/modelling.md>), [performance](<https://devfeed.tech/tags/performance.md>), [systems](<https://devfeed.tech/tags/systems.md>)

### AI overview

The article argues that modelling what needs to be implemented is the most important step in software development, especially when building high-performance systems. It connects Domain-Driven Design with modelling the problem domain and explains that understanding CPU, memory, storage, cache, and network behavior can improve correctness and performance.

### Source excerpt

I'm often asked, "What is the best way to learn about building high-performance systems"? There are many perfectly valid answers to this question but there is one thing that stands out for me above everything else, and that is modelling. Modelling what you need to implement is the most important and effective step in the process. I'd go further and say this principle applies to any development and the rest is just typing :-) Domain Driven Design (DDD) advocates modelling the domain and expressing this model in code as fundamental to the successful delivery and ongoing maintenance of software. I wholeheartedly agree with this. How often do we see code that is an approximation of the problem domain? Code that exhibits behaviour which approximates to what is required via inappropriate abstractions and mappings which just about cope. Those mappings between what is in the code and the real domain are only contained in the developers' heads and this is just not good enough. When requiring high-performance, code for parts of the system often have to model what is happening with the CPU, memory, storage sub-systems, or network sub-systems. When we have imperfect abstractions on top of these domains, performance can be very adversely affected. The goal of my "Mechanical Sympathy" blog is to peek at what is under the hood so we can improve our abstractions. What is a Model? A model does not need to be the result of a 3-year exercise producing UML. It can be, and often is best as, people communicating via various means including speech, drawings, illustrations, metaphors, analogies, etc, to build a mental model for shared understanding. If an accurate and distilled understanding can be reached then this model can be turned into code with great results. Infrastructure Domain Models If developers writing a concurrent framework do not have a good model of how a typical cache sub-system works, i.e. it uses message passing to exchange cache lines, then the framework is unlikely to

## Disruptor 2.0 Released

DevFeed: [Disruptor 2.0 Released](<https://devfeed.tech/articles/disruptor-2-0-released-13612.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/08/disruptor-20-released.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-08-27T08:49:00Z

Content type: release

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Java](<https://devfeed.tech/topics/java.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [concurrent](<https://devfeed.tech/tags/concurrent.md>), [concurrent-programming](<https://devfeed.tech/tags/concurrent-programming.md>), [dependency](<https://devfeed.tech/tags/dependency.md>), [disruptor](<https://devfeed.tech/tags/disruptor.md>), [framework](<https://devfeed.tech/tags/framework.md>), [graph](<https://devfeed.tech/tags/graph.md>), [java](<https://devfeed.tech/tags/java.md>), [performance](<https://devfeed.tech/tags/performance.md>), [queue](<https://devfeed.tech/tags/queue.md>), [release](<https://devfeed.tech/tags/release.md>)

### AI overview

This release article announces Disruptor 2.0, highlighting a cleaner API, renamed event-processing concepts, a DSL for assembling EventProcessor dependency graphs, and substantial performance improvements over queue-based approaches.

### Source excerpt

Significantly improved performance and a cleaner API are the key takeaways for the Disruptor 2.0 concurrent programming framework for Java. This release is the result of all the great feedback we have received from the community. Feedback is very welcome and really improves the end product so please keep it coming. You can find the Disruptor project here, plus we have a wiki with links to detailed blogs describing how things work. Naming & API Over the lifetime of the Disruptor naming has been a challenge. The funny thing is that with the 2.0 release we have come almost full circle. Originally we considered the Disruptor as an event processing framework that often got used as a queue replacement. To make it understandable to queue users we adopted the nomenclature of producers and consumers. However the consumers are not true consumers. With this release the consensus is to return to the event processing roots and adopt the following naming changes. Producer -> Publisher Events are claimed in strict sequence and published to the RingBuffer. Entry -> Event Events represent the currency of data exchange through the dependency graph of EventProcessors. Consumer -> EventProcessor Events are processed by EventProcessors. The processing of an event can be read only, but can also involve mutations on which other EventProcessors depend. ConsumerBarrier -> DependencyBarrier Complex graphs of dependent EventProcessors can be constructed for the processing of an Event. The DependencyBarriers are assembled to represent the dependency graph. This topic is the real value of the Disruptor and often misunderstood. A fun example can be seen playing FizzBuzz in our performance tests. The ProducerBarrier was always a one-to-one relationship with the RingBuffer so for ease of use its behaviour has been merged into the RingBuffer. This allows direct publishing into the RingBuffer. DSL Wizard The most complex part of using the Disruptor is the setting up of the dependency graph of EventP

## Code Refurbishment

DevFeed: [Code Refurbishment](<https://devfeed.tech/articles/code-refurbishment-13611.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/08/code-refurbishment.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-08-20T16:02:00Z

Content type: opinion

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Refactoring](<https://devfeed.tech/topics/refactoring.md>), [Code](<https://devfeed.tech/topics/code.md>), [Code quality](<https://devfeed.tech/topics/code-quality.md>), [Test-driven development](<https://devfeed.tech/topics/tdd.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [code-quality](<https://devfeed.tech/tags/code-quality.md>), [ddd](<https://devfeed.tech/tags/ddd.md>), [refactoring](<https://devfeed.tech/tags/refactoring.md>), [refurbishment](<https://devfeed.tech/tags/refurbishment.md>), [tests](<https://devfeed.tech/tags/tests.md>), [unit-tests](<https://devfeed.tech/tags/unit-tests.md>)

### AI overview

The article distinguishes refactoring from broader structural redevelopment. It defines refactoring as behavior-preserving changes that improve code structure, quality, and maintainability, while noting that larger changes may reuse existing code without being a complete rewrite.

### Source excerpt

Within our industry we use a huge range of terminology. Unfortunately we don't all agree on what individual terms actually mean. I so often hear people misuse the term "Refactoring" which has come to make the business in many organisations recoil in fear. The reason for this fear I've observed is because of what people often mean when misusing this term. I feel we are holding back our industry by not being disciplined in our use of terminology. If one chemist said to another chemist "we are about to perform titration", both would have a good idea what is involved. I believe computing is still a very immature science. As our subject matures hopefully we will become more precise and disciplined in our use of terminology and thus make our communication more accurate and effective. Refactoring is a very useful technique for improving code quality and clarity. To be precise it is a behaviour preserving change that improves a code base for future maintenance and understanding. A good example would be extracting a method to remove code duplication and applying this method at every site of the duplication, thus removing the duplication. Refactoring was first discussed in the early 1990s and became mainstream after Martin Fowler's excellent "Refactoring" book in 1999. Refactoring involves making a number of small internal changes to the code structure. These changes will typically not have any external impact. Well written unit tests that just assert externally observable behaviour will not change when code is refactored. If the external behaviour of code is changing when the structure is being changed then this is not refactoring. Now, why do our business folk recoil in fear when this simple and useful technique of "refactoring" is mentioned? I believe this is because developers are actually talking about a much more extensive structural redevelopment technique that does not have a common term. These structural changes are often not a complete ground-up rewrite because much

## False Sharing && Java 7

DevFeed: [False Sharing && Java 7](<https://devfeed.tech/articles/false-sharing-java-7-13613.md>)

Original publisher: [Read original article](<https://mechanical-sympathy.blogspot.com/2011/08/false-sharing-java-7.html>)

Author: Martin Thompson (noreply@blogger.com)

Published: 2011-08-13T09:07:00Z

Content type: tutorial

Language: en

Sources: [Mechanical Sympathy](<https://devfeed.tech/sources/mechanical-sympathy.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Cache](<https://devfeed.tech/topics/cache.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [cache](<https://devfeed.tech/tags/cache.md>), [code](<https://devfeed.tech/tags/code.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [java](<https://devfeed.tech/tags/java.md>), [performance](<https://devfeed.tech/tags/performance.md>), [techniques](<https://devfeed.tech/tags/techniques.md>)

### AI overview

This article explains that Java 7 may eliminate or reorder unused padding fields intended to prevent false sharing. It presents a PaddedAtomicLong implementation using extra volatile long fields and reports performance similar to an earlier false-sharing test, while noting that removing the padding demonstrates the effect.

### Source excerpt

In my previous post on False Sharing I suggested it can be avoided by padding the cache line with unused long fields. It seems Java 7 got clever and eliminated or re-ordered the unused fields, thus re-introducing false sharing. I've experimented with a number of techniques on different platforms and found the following code to be the most reliable. import java.util.concurrent.atomic.AtomicLong; public final class FalseSharing implements Runnable { public final static int NUM_THREADS = 4; // change public final static long ITERATIONS = 500L * 1000L * 1000L; private final int arrayIndex; private static PaddedAtomicLong[] longs = new PaddedAtomicLong[NUM_THREADS]; static { for (int i = 0; i < longs.length; i++) { longs[i] = new PaddedAtomicLong(); } } public FalseSharing(final int arrayIndex) { this.arrayIndex = arrayIndex; } public static void main(final String[] args) throws Exception { final long start = System.nanoTime(); runTest(); System.out.println("duration = " + (System.nanoTime() - start)); } private static void runTest() throws InterruptedException { Thread[] threads = new Thread[NUM_THREADS]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new FalseSharing(i)); } for (Thread t : threads) { t.start(); } for (Thread t : threads) { t.join(); } } public void run() { long i = ITERATIONS + 1; while (0 != --i) { longs[arrayIndex].set(i); } } public static long sumPaddingToPreventOptimisation(final int index) { PaddedAtomicLong v = longs[index]; return v.p1 + v.p2 + v.p3 + v.p4 + v.p5 + v.p6; } public static class PaddedAtomicLong extends AtomicLong { public volatile long p1, p2, p3, p4, p5, p6 = 7L; } } With this code I get similar performance results to those stated in the previous False Sharing article. The padding in PaddedAtomicLong above can be commented out to see the false sharing effect. I think we should all lobby the powers that be inside Oracle to have intrinsics added to the language so we can have cache line aligned and padded atomi

[Next page](<https://devfeed.tech/sources/mechanical-sympathy.md?cursor=WyIyMDExLTA4LTEzVDA5OjA3OjAwKzAwOjAwIiwgImNkZjAyMTk5LTY2ODgtNDllNS05MDExLTM4MDdkY2M3ZTFhNSJd>)