Use bitwise operation when sampling for resource leak detection.
Motivation: Modulo operations are slow, we can use bitwise operation to detect if resource leak detection must be done while sampling. Modifications: - Ensure the interval is a power of two - Use bitwise operation for sampling - Add benchmark. Result: Faster sampling.
This commit is contained in:
parent
ed98cd8200
commit
a47685b243
@ -21,6 +21,7 @@ import io.netty.buffer.PoolArena.SizeClass;
|
|||||||
import io.netty.util.Recycler;
|
import io.netty.util.Recycler;
|
||||||
import io.netty.util.Recycler.Handle;
|
import io.netty.util.Recycler.Handle;
|
||||||
import io.netty.util.ThreadDeathWatcher;
|
import io.netty.util.ThreadDeathWatcher;
|
||||||
|
import io.netty.util.internal.MathUtil;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
@ -356,25 +357,11 @@ final class PoolThreadCache {
|
|||||||
private int allocations;
|
private int allocations;
|
||||||
|
|
||||||
MemoryRegionCache(int size, SizeClass sizeClass) {
|
MemoryRegionCache(int size, SizeClass sizeClass) {
|
||||||
this.size = powerOfTwo(size);
|
this.size = MathUtil.findNextPositivePowerOfTwo(size);
|
||||||
queue = PlatformDependent.newFixedMpscQueue(this.size);
|
queue = PlatformDependent.newFixedMpscQueue(this.size);
|
||||||
this.sizeClass = sizeClass;
|
this.sizeClass = sizeClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int powerOfTwo(int res) {
|
|
||||||
if (res <= 2) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
res--;
|
|
||||||
res |= res >> 1;
|
|
||||||
res |= res >> 2;
|
|
||||||
res |= res >> 4;
|
|
||||||
res |= res >> 8;
|
|
||||||
res |= res >> 16;
|
|
||||||
res++;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init the {@link PooledByteBuf} using the provided chunk and handle with the capacity restrictions.
|
* Init the {@link PooledByteBuf} using the provided chunk and handle with the capacity restrictions.
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package io.netty.util;
|
package io.netty.util;
|
||||||
|
|
||||||
|
import io.netty.util.internal.MathUtil;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
@ -105,7 +106,8 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int DEFAULT_SAMPLING_INTERVAL = 113;
|
// Should be power of two.
|
||||||
|
private static final int DEFAULT_SAMPLING_INTERVAL = 128;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #setLevel(Level)} instead.
|
* @deprecated Use {@link #setLevel(Level)} instead.
|
||||||
@ -148,6 +150,7 @@ public final class ResourceLeakDetector<T> {
|
|||||||
|
|
||||||
private final String resourceType;
|
private final String resourceType;
|
||||||
private final int samplingInterval;
|
private final int samplingInterval;
|
||||||
|
private final int mask;
|
||||||
private final long maxActive;
|
private final long maxActive;
|
||||||
private long active;
|
private long active;
|
||||||
private final AtomicBoolean loggedTooManyActive = new AtomicBoolean();
|
private final AtomicBoolean loggedTooManyActive = new AtomicBoolean();
|
||||||
@ -178,7 +181,10 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.resourceType = resourceType;
|
this.resourceType = resourceType;
|
||||||
this.samplingInterval = samplingInterval;
|
this.samplingInterval = MathUtil.findNextPositivePowerOfTwo(samplingInterval);
|
||||||
|
// samplingInterval is a power of two so we calculate a mask that we can use to
|
||||||
|
// check if we need to do any leak detection or not.
|
||||||
|
mask = this.samplingInterval - 1;
|
||||||
this.maxActive = maxActive;
|
this.maxActive = maxActive;
|
||||||
|
|
||||||
head.next = tail;
|
head.next = tail;
|
||||||
@ -198,7 +204,7 @@ public final class ResourceLeakDetector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (level.ordinal() < Level.PARANOID.ordinal()) {
|
if (level.ordinal() < Level.PARANOID.ordinal()) {
|
||||||
if (leakCheckCnt ++ % samplingInterval == 0) {
|
if ((leakCheckCnt ++ & mask) == 0) {
|
||||||
reportLeak(level);
|
reportLeak(level);
|
||||||
return new DefaultResourceLeak(obj);
|
return new DefaultResourceLeak(obj);
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,8 +26,8 @@ public final class MathUtil {
|
|||||||
* Fast method of finding the next power of 2 greater than or equal to the supplied value.
|
* Fast method of finding the next power of 2 greater than or equal to the supplied value.
|
||||||
*
|
*
|
||||||
* If the value is {@code <= 0} then 1 will be returned.
|
* If the value is {@code <= 0} then 1 will be returned.
|
||||||
|
* This method is not suitable for {@link Integer#MIN_VALUE} or numbers greater than 2^30.
|
||||||
*
|
*
|
||||||
* This method is not suitable for {@link Integer#MIN_VALUE} or numbers greater than 2^30.*
|
|
||||||
* @param value from which to search for next power of 2
|
* @param value from which to search for next power of 2
|
||||||
* @return The next power of 2 or the value itself if it is a power of 2
|
* @return The next power of 2 or the value itself if it is a power of 2
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.microbench.util;
|
||||||
|
|
||||||
|
import io.netty.util.ResourceLeakDetector;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
public class ResourceLeakDetectorBenchmark extends AbstractMicrobenchmark {
|
||||||
|
|
||||||
|
private static final Object DUMMY = new Object();
|
||||||
|
private ResourceLeakDetector<Object> detector;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() {
|
||||||
|
detector = new ResourceLeakDetector<Object>(getClass(), 128, Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object open() {
|
||||||
|
return detector.open(DUMMY);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user