From 777bcddba40b9fa0c1d06e182675dd099597388e Mon Sep 17 00:00:00 2001 From: leventov Date: Tue, 28 Oct 2014 02:11:11 +0300 Subject: [PATCH] Refactored L1 cache associativity contention break in VanillaChronicleMap --- .../chronicle/map/VanillaChronicleMap.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index abae5bd93..834b94e3f 100644 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -42,6 +42,8 @@ import java.nio.channels.FileChannel; import java.util.*; import java.util.concurrent.TimeUnit; +import static java.lang.Long.numberOfTrailingZeros; +import static java.lang.Math.max; import static java.lang.Thread.currentThread; @@ -269,23 +271,19 @@ class VanillaChronicleMap, + sizeOfEntriesInSegment(); if ((ss & 63L) != 0) throw new AssertionError(); + return breakL1CacheAssociativityContention(ss); + } - // Say, there is 32 KB L1 cache with 2(4, 8) way set associativity, 64-byte lines. - // It means there are 32 * 1024 / 64 / 2(4, 8) = 256(128, 64) sets, - // i. e. each way (bank) contains 256(128, 64) lines. (L2 and L3 caches has more sets.) - // If segment size in lines multiplied by 2^n is divisible by set size, - // every 2^n-th segment header fall into the same set. - // To break this up we make segment size odd in lines, in this case only each - // 256(128, 64)-th segment header fall into the same set. - - // If there are 64 sets in L1, it should be 8- or much less likely 4-way, and segments - // collision by pairs is not so terrible. - - // if the size is a multiple of 4096 or slightly more. Make sure it is at least 64 more than a multiple. - if ((ss & 4093) < 64) - ss = (ss & ~63) + 64; - - return ss; + private long breakL1CacheAssociativityContention(long segmentSize) { + // Conventional alignment to break is 4096 (given Intel's 32KB 8-way L1 cache), + // for any case break 2 times smaller alignment + int alignmentToBreak = 2048; + int eachNthSegmentFallIntoTheSameSet = + max(1, alignmentToBreak >> numberOfTrailingZeros(segmentSize)); + if (eachNthSegmentFallIntoTheSameSet < actualSegments) { + segmentSize |= 64L; // make segment size "odd" (in cache lines) + } + return segmentSize; } int multiMapsPerSegment() { @@ -625,7 +623,7 @@ class VanillaChronicleMap, */ long getSize() { // any negative value is in error state. - return Math.max(0L, this.bytes.readVolatileLong(SIZE_OFFSET)); + return max(0L, this.bytes.readVolatileLong(SIZE_OFFSET)); }