You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by rm...@apache.org on 2013/10/23 15:12:34 UTC

svn commit: r1535018 - in /incubator/sirona/trunk: aop/src/main/java/org/apache/sirona/aop/ aop/src/test/java/org/apache/sirona/aop/ aspectj/src/main/java/org/apache/sirona/aspectj/ cdi/src/main/java/org/apache/sirona/cdi/ core/src/main/java/org/apache...

Author: rmannibucau
Date: Wed Oct 23 13:12:33 2013
New Revision: 1535018

URL: http://svn.apache.org/r1535018
Log:
making AbstractPerformanceInterceptor configurable to skip too small invocations

Added:
    incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/DynamicInterceptionTest.java
Modified:
    incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/AbstractPerformanceInterceptor.java
    incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/MonitoringProxyFactory.java
    incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/MonitoringProxyFactoryTest.java
    incubator/sirona/trunk/aspectj/src/main/java/org/apache/sirona/aspectj/CommonsMonitoringAspect.java
    incubator/sirona/trunk/cdi/src/main/java/org/apache/sirona/cdi/CommonsMonitoringInterceptor.java
    incubator/sirona/trunk/core/src/main/java/org/apache/sirona/Role.java
    incubator/sirona/trunk/core/src/main/java/org/apache/sirona/counters/Unit.java
    incubator/sirona/trunk/spring/src/main/java/org/apache/sirona/spring/AopaliancePerformanceInterceptor.java
    incubator/sirona/trunk/src/site/markdown/instrumentation.md

Modified: incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/AbstractPerformanceInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/AbstractPerformanceInterceptor.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/AbstractPerformanceInterceptor.java (original)
+++ incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/AbstractPerformanceInterceptor.java Wed Oct 23 13:12:33 2013
@@ -17,14 +17,22 @@
 
 package org.apache.sirona.aop;
 
+import org.apache.sirona.MonitoringException;
 import org.apache.sirona.Role;
+import org.apache.sirona.configuration.Configuration;
 import org.apache.sirona.counters.Counter;
 import org.apache.sirona.repositories.Repository;
 import org.apache.sirona.stopwatches.StopWatch;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
+import java.io.Serializable;
 import java.lang.reflect.Method;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * A method interceptor that compute method invocation performances.
@@ -34,7 +42,27 @@ import java.lang.reflect.Method;
  *
  * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
  */
-public abstract class AbstractPerformanceInterceptor<T> {
+public abstract class AbstractPerformanceInterceptor<T> implements Serializable {
+    // static for performances reasons, all these values are read through getXXX so it is overridable
+    private static final boolean ADAPTIVE = Configuration.is(Configuration.CONFIG_PROPERTY_PREFIX + "performance.adaptive", false);
+    private static final long FORCED_ITERATION = Configuration.getInteger(Configuration.CONFIG_PROPERTY_PREFIX + "performance.forced-iteration", 0);
+    private static final long THRESHOLD = duration(Configuration.getProperty(Configuration.CONFIG_PROPERTY_PREFIX + "performance.threshold", null));
+    private static final ActivationContext ALWAYS_ACTIVE_CONTEXT = new ActivationContext(true, 0, 0);
+
+    protected static final ConcurrentMap<Object, ActivationContext> CONTEXTS = new ConcurrentHashMap<Object, ActivationContext>();
+
+    private static long duration(final String duration) {
+        if (duration == null) {
+            return 0;
+        }
+        final String[] parts = duration.split(" ");
+        if (parts.length == 1) {
+            return Long.parseLong(duration.trim());
+        } else if (parts.length == 2) {
+            return TimeUnit.valueOf(parts[2].trim().toUpperCase(Locale.ENGLISH)).toNanos(Long.parseLong(parts[0].trim()));
+        }
+        return 0;
+    }
 
     protected MonitorNameExtractor monitorNameExtractor;
 
@@ -51,8 +79,16 @@ public abstract class AbstractPerformanc
             return proceed(invocation);
         }
 
-        final Counter monitor = Repository.INSTANCE.getCounter(new Counter.Key(getRole(), name));
-        final StopWatch stopwatch = Repository.INSTANCE.start(monitor);
+        final ActivationContext context = doFindContext(invocation);
+
+        final StopWatch stopwatch;
+        if (context.isActive() || context.isForcedIteration()) {
+            final Counter monitor = Repository.INSTANCE.getCounter(new Counter.Key(getRole(), name));
+            stopwatch = Repository.INSTANCE.start(monitor);
+        } else {
+            stopwatch = null;
+        }
+
         Throwable error = null;
         try {
             return proceed(invocation);
@@ -60,13 +96,65 @@ public abstract class AbstractPerformanc
             error = t;
             throw t;
         } finally {
-            stopwatch.stop();
-            if (error != null) {
-                final ByteArrayOutputStream writer = new ByteArrayOutputStream();
-                error.printStackTrace(new PrintStream(writer));
-                Repository.INSTANCE.getCounter(new Counter.Key(Role.FAILURES, writer.toString())).add(stopwatch.getElapsedTime());
+            if (stopwatch != null) {
+                stopwatch.stop();
+
+                final long elapsedTime = stopwatch.getElapsedTime();
+
+                if (error != null) {
+                    final ByteArrayOutputStream writer = new ByteArrayOutputStream();
+                    error.printStackTrace(new PrintStream(writer));
+                    Repository.INSTANCE.getCounter(new Counter.Key(Role.FAILURES, writer.toString())).add(elapsedTime);
+                }
+
+                if (context.isThresholdActive() && elapsedTime < context.getThreshold()) {
+                    context.reset();
+                }
+            }
+        }
+    }
+
+    protected boolean isAdaptive() {
+        return ADAPTIVE;
+    }
+
+    protected Object extractContextKey(final T invocation) {
+        return null;
+    }
+
+    protected ActivationContext getOrCreateContext(final Object m) {
+        final ActivationContext c = CONTEXTS.get(m);
+        if (c == null) {
+            final String counterName;
+            if (SerializableMethod.class.isInstance(m)) {
+                counterName = getCounterName(null, SerializableMethod.class.cast(m).method());
+            } else {
+                counterName = m.toString();
             }
+            return putAndGetActivationContext(m, new ActivationContext(true, counterName));
         }
+        return c;
+    }
+
+    protected ActivationContext putAndGetActivationContext(Object m, ActivationContext newCtx) {
+        final ActivationContext old = CONTEXTS.putIfAbsent(m, newCtx);
+        if (old != null) {
+            newCtx = old;
+        }
+        return newCtx;
+    }
+
+    protected ActivationContext doFindContext(final T invocation) {
+        if (!isAdaptive()) {
+            return ALWAYS_ACTIVE_CONTEXT;
+        }
+
+        final Object m = extractContextKey(invocation);
+        if (m != null) {
+            return getOrCreateContext(m);
+        }
+
+        return ALWAYS_ACTIVE_CONTEXT;
     }
 
     protected Role getRole() {
@@ -90,4 +178,94 @@ public abstract class AbstractPerformanc
     public void setMonitorNameExtractor(final MonitorNameExtractor monitorNameExtractor) {
         this.monitorNameExtractor = monitorNameExtractor;
     }
+
+    protected static class SerializableMethod implements Serializable {
+        protected final String clazz;
+        protected final String method;
+        protected Method realMethod;
+
+        public SerializableMethod(final String clazz, final String method, final Method reflectMethod) {
+            this.clazz = clazz;
+            this.method = method;
+            this.realMethod = reflectMethod;
+        }
+
+        public SerializableMethod(final Method m) {
+            this(m.getDeclaringClass().getName(), m.getName(), m);
+        }
+
+        public Method method() {
+            if (realMethod == null) { // try to find it
+                try {
+                    Class<?> declaring = Thread.currentThread().getContextClassLoader().loadClass(clazz);
+                    while (declaring != null) {
+                        for (final Method m : declaring.getDeclaredMethods()) {
+                            if (m.getName().equals(method)) {
+                                realMethod = m;
+                                return realMethod;
+                            }
+                        }
+                        declaring = declaring.getSuperclass();
+                    }
+                } catch (final ClassNotFoundException e) {
+                    throw new MonitoringException(e);
+                }
+            }
+            return realMethod;
+        }
+    }
+
+    protected static class ActivationContext implements Serializable {
+        protected final long forceIteration;
+        protected final long threshold;
+        protected final boolean thresholdActive;
+
+        protected volatile boolean active = true;
+        protected volatile AtomicInteger iteration = new AtomicInteger(0);
+
+        public ActivationContext(final boolean active, final long th, final long it) {
+            this.active = active;
+
+            if (it >= 0) {
+                forceIteration = it;
+            } else {
+                forceIteration = FORCED_ITERATION;
+            }
+
+            if (th >= 0) {
+                threshold = th;
+            } else {
+                threshold = THRESHOLD;
+            }
+
+            this.thresholdActive = this.threshold > 0;
+        }
+
+        public ActivationContext(final boolean active, final String name) {
+            this(active,
+                duration(Configuration.getProperty(Configuration.CONFIG_PROPERTY_PREFIX + "performance." + name + ".threshold", null)),
+                Configuration.getInteger(Configuration.CONFIG_PROPERTY_PREFIX + "performance." + name + ".forced-iteration", -1));
+        }
+
+        public boolean isForcedIteration() {
+            return iteration.incrementAndGet() > forceIteration;
+        }
+
+        protected long getThreshold() {
+            return threshold;
+        }
+
+        protected boolean isThresholdActive() {
+            return thresholdActive;
+        }
+
+        public boolean isActive() {
+            return active;
+        }
+
+        public void reset() {
+            active = false;
+            iteration.set(0);
+        }
+    }
 }
\ No newline at end of file

Modified: incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/MonitoringProxyFactory.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/MonitoringProxyFactory.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/MonitoringProxyFactory.java (original)
+++ incubator/sirona/trunk/aop/src/main/java/org/apache/sirona/aop/MonitoringProxyFactory.java Wed Oct 23 13:12:33 2013
@@ -60,6 +60,11 @@ public final class MonitoringProxyFactor
         protected String getCounterName(final Invocation invocation) {
             return getCounterName(invocation.target, invocation.method);
         }
+
+        @Override
+        protected Object extractContextKey(final Invocation invocation) {
+            return new SerializableMethod(invocation.method);
+        }
     }
 
     private static class Invocation {

Added: incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/DynamicInterceptionTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/DynamicInterceptionTest.java?rev=1535018&view=auto
==============================================================================
--- incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/DynamicInterceptionTest.java (added)
+++ incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/DynamicInterceptionTest.java Wed Oct 23 13:12:33 2013
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 org.apache.sirona.aop;
+
+import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class DynamicInterceptionTest {
+
+    public static final int MAX_IT = 5;
+    public static final int THRESHOLD = 100;
+    private Repository repository;
+
+    @Before
+    @After
+    public void reset() {
+        repository = Repository.INSTANCE;
+        repository.clear();
+    }
+
+    @Test
+    public void playWithInterceptor() throws Throwable {
+        final ConfigurablePerfInterceptor interceptor = new ConfigurablePerfInterceptor();
+        assertFalse(repository.iterator().hasNext());
+
+        interceptor.invoke(THRESHOLD * 5);
+        assertTrue(repository.iterator().hasNext());
+        assertEquals(1, repository.iterator().next().getHits());
+        assertEquals("dynamic", repository.iterator().next().getKey().getName());
+
+        interceptor.invoke(THRESHOLD / 20);
+        assertEquals(2, repository.iterator().next().getHits());
+
+        for (int i = 0; i < MAX_IT; i++) {
+            interceptor.invoke(THRESHOLD * 5);
+        }
+        assertEquals(2, repository.iterator().next().getHits());
+
+        interceptor.invoke(THRESHOLD / 5);
+        assertEquals(3, repository.iterator().next().getHits());
+
+        for (int i = 0; i < MAX_IT; i++) {
+            interceptor.invoke(THRESHOLD * 2);
+        }
+        assertEquals(3, repository.iterator().next().getHits());
+
+        interceptor.invoke(THRESHOLD * 5);
+        interceptor.invoke(THRESHOLD * 5);
+        assertEquals(5, repository.iterator().next().getHits());
+    }
+
+    public static class ConfigurablePerfInterceptor extends AbstractPerformanceInterceptor<Long> {
+        public void invoke(final long duration) throws Throwable {
+            doInvoke(duration);
+        }
+
+        @Override
+        protected Object proceed(final Long duration) throws Throwable {
+            Thread.sleep(duration);
+            return null;
+        }
+
+        @Override
+        protected String getCounterName(final Long invocation) {
+            return "dynamic";
+        }
+
+        @Override
+        protected Method extractContextKey(final Long invocation) {
+            try {
+                return getClass().getMethod("invoke", long.class);
+            } catch (final NoSuchMethodException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        @Override
+        protected boolean isAdaptive() {
+            return true;
+        }
+
+        @Override
+        protected ActivationContext doFindContext(final Long invocation) {
+            return putAndGetActivationContext(extractContextKey(null), new ActivationContext(true, TimeUnit.MILLISECONDS.toNanos(THRESHOLD), MAX_IT));
+        }
+    }
+}

Modified: incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/MonitoringProxyFactoryTest.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/MonitoringProxyFactoryTest.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/MonitoringProxyFactoryTest.java (original)
+++ incubator/sirona/trunk/aop/src/test/java/org/apache/sirona/aop/MonitoringProxyFactoryTest.java Wed Oct 23 13:12:33 2013
@@ -19,6 +19,8 @@ package org.apache.sirona.aop;
 import org.apache.sirona.Role;
 import org.apache.sirona.counters.Counter;
 import org.apache.sirona.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 import java.util.concurrent.TimeUnit;
@@ -28,6 +30,12 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.fail;
 
 public class MonitoringProxyFactoryTest {
+    @Before
+    @After
+    public void reset() {
+        Repository.INSTANCE.clear();
+    }
+
     @Test
     public void test() {
         final Foo foo = MonitoringProxyFactory.monitor(Foo.class, new FooImpl());

Modified: incubator/sirona/trunk/aspectj/src/main/java/org/apache/sirona/aspectj/CommonsMonitoringAspect.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/aspectj/src/main/java/org/apache/sirona/aspectj/CommonsMonitoringAspect.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/aspectj/src/main/java/org/apache/sirona/aspectj/CommonsMonitoringAspect.java (original)
+++ incubator/sirona/trunk/aspectj/src/main/java/org/apache/sirona/aspectj/CommonsMonitoringAspect.java Wed Oct 23 13:12:33 2013
@@ -49,6 +49,11 @@ public abstract class CommonsMonitoringA
         return invocation.getSignature().toLongString();
     }
 
+    @Override
+    protected Object extractContextKey(final ProceedingJoinPoint invocation) {
+        return new SerializableMethod(findMethod(invocation.getSignature()));
+    }
+
     private static Method findMethod(final Signature signature) {
         if ("org.aspectj.runtime.reflect.MethodSignatureImpl".equals(signature.getClass().getName())) {
             try {

Modified: incubator/sirona/trunk/cdi/src/main/java/org/apache/sirona/cdi/CommonsMonitoringInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/cdi/src/main/java/org/apache/sirona/cdi/CommonsMonitoringInterceptor.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/cdi/src/main/java/org/apache/sirona/cdi/CommonsMonitoringInterceptor.java (original)
+++ incubator/sirona/trunk/cdi/src/main/java/org/apache/sirona/cdi/CommonsMonitoringInterceptor.java Wed Oct 23 13:12:33 2013
@@ -22,6 +22,7 @@ import javax.interceptor.AroundInvoke;
 import javax.interceptor.AroundTimeout;
 import javax.interceptor.Interceptor;
 import javax.interceptor.InvocationContext;
+import java.lang.reflect.Method;
 
 @Interceptor
 @Monitored
@@ -41,4 +42,9 @@ public class CommonsMonitoringIntercepto
     protected String getCounterName(final InvocationContext invocation) {
         return getCounterName(invocation.getTarget(), invocation.getMethod());
     }
+
+    @Override
+    protected Object extractContextKey(final InvocationContext invocation) {
+        return new SerializableMethod(invocation.getMethod());
+    }
 }

Modified: incubator/sirona/trunk/core/src/main/java/org/apache/sirona/Role.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/main/java/org/apache/sirona/Role.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/core/src/main/java/org/apache/sirona/Role.java (original)
+++ incubator/sirona/trunk/core/src/main/java/org/apache/sirona/Role.java Wed Oct 23 13:12:33 2013
@@ -19,6 +19,8 @@ package org.apache.sirona;
 
 import org.apache.sirona.counters.Unit;
 
+import java.io.Serializable;
+
 import static org.apache.sirona.counters.Unit.Time.NANOSECOND;
 
 /**
@@ -27,7 +29,7 @@ import static org.apache.sirona.counters
  *
  * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
  */
-public class Role implements Comparable<Role> {
+public class Role implements Comparable<Role>, Serializable {
     public static final Role WEB = new Role("web", NANOSECOND);
     public static final Role JSP = new Role("jsp", NANOSECOND);
     public static final Role JDBC = new Role("jdbc", NANOSECOND);

Modified: incubator/sirona/trunk/core/src/main/java/org/apache/sirona/counters/Unit.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/core/src/main/java/org/apache/sirona/counters/Unit.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/core/src/main/java/org/apache/sirona/counters/Unit.java (original)
+++ incubator/sirona/trunk/core/src/main/java/org/apache/sirona/counters/Unit.java Wed Oct 23 13:12:33 2013
@@ -17,6 +17,7 @@
 
 package org.apache.sirona.counters;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -38,7 +39,7 @@ import java.util.concurrent.CopyOnWriteA
  *
  * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
  */
-public class Unit implements Comparable<Unit> {
+public class Unit implements Comparable<Unit>, Serializable {
     private static final Map<String, Unit> UNITS = new ConcurrentHashMap<String, Unit>();
 
     /**

Modified: incubator/sirona/trunk/spring/src/main/java/org/apache/sirona/spring/AopaliancePerformanceInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/spring/src/main/java/org/apache/sirona/spring/AopaliancePerformanceInterceptor.java?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/spring/src/main/java/org/apache/sirona/spring/AopaliancePerformanceInterceptor.java (original)
+++ incubator/sirona/trunk/spring/src/main/java/org/apache/sirona/spring/AopaliancePerformanceInterceptor.java Wed Oct 23 13:12:33 2013
@@ -21,6 +21,8 @@ import org.aopalliance.intercept.MethodI
 import org.aopalliance.intercept.MethodInvocation;
 import org.apache.sirona.aop.AbstractPerformanceInterceptor;
 
+import java.lang.reflect.Method;
+
 /**
  * Spring-aop implementation of PerformanceInterceptor.
  *
@@ -42,4 +44,8 @@ public class AopaliancePerformanceInterc
         return invocation.proceed();
     }
 
+    @Override
+    protected Object extractContextKey(final MethodInvocation invocation) {
+        return new SerializableMethod(invocation.getMethod());
+    }
 }
\ No newline at end of file

Modified: incubator/sirona/trunk/src/site/markdown/instrumentation.md
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/src/site/markdown/instrumentation.md?rev=1535018&r1=1535017&r2=1535018&view=diff
==============================================================================
--- incubator/sirona/trunk/src/site/markdown/instrumentation.md (original)
+++ incubator/sirona/trunk/src/site/markdown/instrumentation.md Wed Oct 23 13:12:33 2013
@@ -27,7 +27,9 @@ to use javassist you set it to `org.apac
 
 Then the API is quite simple:
 
-    final MyClient client = MonitoringProxyFactory.monitor(MyClient.class, getMyClientInstance());
+```java
+final MyClient client = MonitoringProxyFactory.monitor(MyClient.class, getMyClientInstance());
+```
 
 # CDI
 
@@ -91,3 +93,38 @@ concrete aspect defining the pointcut to
     </aspectj>
 
 See [AspectJ documentation](http://eclipse.org/aspectj/doc/next/progguide/language-joinPoints.html) for more information.
+
+# Note on interceptor configuration (experimental)
+
+Few global configuration (`sirona.properties`) is available for all interceptors:
+
+* `org.apache.sirona.performance.adaptive`: if this boolean is set to true the following parameter are taken into account
+* `org.apache.sirona.performance.threshold`: if > 0 it is the duration under which calls are skipped (no more monitored). Note: the format supports <duration> <TimeUnit name> too. For instance `100 MILLISECONDS` is valid.
+* `org.apache.sirona.performance.forced-iteration`: the number of iterations a deactivated interceptor (because of threshold rule) will wait before forcing a measure to see if the monitoring should be activated back.
+
+Note: `threshold` and `forced-iteration` parameters can be specialized appending to `org.apache.sirona.` the method qualified name.
+
+Here a sample of the behavior associated with these properties. Let say you configured `forced-iteration` to 5 and
+ `threshold` to 100 milliseconds. If `xxx ms` represent an invocation of xxx milliseconds and `*` represent a call
+ which was measured, here is an invocation sequence:
+
+ ```
+ 500 ms*
+ 5 ms*
+ 500 ms
+ 500 ms
+ 500 ms
+ 500 ms
+ 500 ms
+ 20 ms*
+ 200 ms
+ 200 ms
+ 200 ms
+ 200 ms
+ 200 ms
+ 500 ms*
+ 500 ms*
+ ```
+
+Note: the idea is to reduce the overhead of the interception. This is pretty efficient in general but particularly with AspectJ.
+Note 2: if your invocations are pretty unstable this is not really usable since since you'll not get a good threshold value.