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 fc3fb7e068
commit 577931e8bc
4 changed files with 86 additions and 18 deletions

View File

@ -21,6 +21,7 @@ import io.netty.buffer.PoolArena.SizeClass;
import io.netty.util.Recycler;
import io.netty.util.Recycler.Handle;
import io.netty.util.ThreadDeathWatcher;
import io.netty.util.internal.MathUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -356,25 +357,11 @@ final class PoolThreadCache {
private int allocations;
MemoryRegionCache(int size, SizeClass sizeClass) {
this.size = powerOfTwo(size);
this.size = MathUtil.findNextPositivePowerOfTwo(size);
queue = PlatformDependent.newFixedMpscQueue(this.size);
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.
*/

View File

@ -16,6 +16,7 @@
package io.netty.util;
import io.netty.util.internal.MathUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
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.
@ -148,6 +150,7 @@ public final class ResourceLeakDetector<T> {
private final String resourceType;
private final int samplingInterval;
private final int mask;
private final long maxActive;
private long active;
private final AtomicBoolean loggedTooManyActive = new AtomicBoolean();
@ -178,7 +181,10 @@ public final class ResourceLeakDetector<T> {
}
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;
head.next = tail;
@ -198,7 +204,7 @@ public final class ResourceLeakDetector<T> {
}
if (level.ordinal() < Level.PARANOID.ordinal()) {
if (leakCheckCnt ++ % samplingInterval == 0) {
if ((leakCheckCnt ++ & mask) == 0) {
reportLeak(level);
return new DefaultResourceLeak(obj);
} else {

View File

@ -0,0 +1,39 @@
/*
* 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.util.internal;
/**
* Math utility methods.
*/
public final class MathUtil {
private MathUtil() {
}
/**
* 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.
*
* 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
* @return The next power of 2 or the value itself if it is a power of 2
*/
public static int findNextPositivePowerOfTwo(final int value) {
assert value > Integer.MIN_VALUE && value < 0x40000000;
return 1 << (32 - Integer.numberOfLeadingZeros(value - 1));
}
}

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