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:
Norman Maurer 2015-10-28 11:46:28 +01:00
parent ed98cd8200
commit a47685b243
4 changed files with 48 additions and 19 deletions

View File

@ -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.
*/ */

View File

@ -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 {

View File

@ -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
*/ */

View File

@ -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);
}
}