diff --git a/remoting/src/main/java/hudson/remoting/Channel.java b/remoting/src/main/java/hudson/remoting/Channel.java index edb4aff7f3..6c0d9bbf2f 100644 --- a/remoting/src/main/java/hudson/remoting/Channel.java +++ b/remoting/src/main/java/hudson/remoting/Channel.java @@ -18,6 +18,8 @@ import java.util.Vector; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -113,6 +115,40 @@ public class Channel implements VirtualChannel { private final Vector listeners = new Vector(); private int gcCounter; + /** + * Total number of nanoseconds spent for remote class loading. + *

+ * Remote code execution often results in classloading activity + * (more precisely, when the remote peer requests some computation + * on this channel, this channel often has to load necessary + * classes from the remote peer.) + *

+ * This counter represents the total amount of time this channel + * had to spend loading classes from the remote peer. The time + * measurement doesn't include the time locally spent to actually + * define the class (as the local classloading would have incurred + * the same cost.) + */ + public final AtomicLong classLoadingTime = new AtomicLong(); + + /** + * Total counts of remote classloading activities. Used in a pair + * with {@link #classLoadingTime}. + */ + public final AtomicInteger classLoadingCount = new AtomicInteger(); + + /** + * Total number of nanoseconds spent for remote resource loading. + * @see #classLoadingTime + */ + public final AtomicLong resourceLoadingTime = new AtomicLong(); + + /** + * Total count of remote resource loading. + * @see #classLoadingCount + */ + public final AtomicInteger resourceLoadingCount = new AtomicInteger(); + /** * Communication mode. * @since 1.161 @@ -478,6 +514,16 @@ public class Channel implements VirtualChannel { private static final long serialVersionUID = 1L; } + /** + * Resets all the performance counters. + */ + public void resetPerformanceCounters() { + classLoadingCount.set(0); + classLoadingTime.set(0); + resourceLoadingCount.set(0); + resourceLoadingTime.set(0); + } + /** * {@inheritDoc} */ diff --git a/remoting/src/main/java/hudson/remoting/RemoteClassLoader.java b/remoting/src/main/java/hudson/remoting/RemoteClassLoader.java index b63b005f73..cea9b45c9e 100644 --- a/remoting/src/main/java/hudson/remoting/RemoteClassLoader.java +++ b/remoting/src/main/java/hudson/remoting/RemoteClassLoader.java @@ -21,6 +21,10 @@ import java.util.ArrayList; */ final class RemoteClassLoader extends ClassLoader { private final IClassLoader proxy; + /** + * Remote peer that the {@link #proxy} is connected to. + */ + private final Channel channel; private final Map resourceMap = new HashMap(); private final Map> resourcesMap = new HashMap>(); @@ -38,10 +42,14 @@ final class RemoteClassLoader extends ClassLoader { private RemoteClassLoader(ClassLoader parent, IClassLoader proxy) { super(parent); this.proxy = proxy; + this.channel = RemoteInvocationHandler.unwrap(proxy); } protected Class findClass(String name) throws ClassNotFoundException { + long startTime = System.nanoTime(); byte[] bytes = proxy.fetch(name); + channel.classLoadingTime.addAndGet(System.nanoTime()-startTime); + channel.classLoadingCount.incrementAndGet(); return defineClass(name, bytes, 0, bytes.length); } @@ -50,7 +58,10 @@ final class RemoteClassLoader extends ClassLoader { return resourceMap.get(name); try { + long startTime = System.nanoTime(); byte[] image = proxy.getResource(name); + channel.resourceLoadingTime.addAndGet(System.nanoTime()-startTime); + channel.resourceLoadingCount.incrementAndGet(); if(image==null) { resourceMap.put(name,null); return null; @@ -69,7 +80,10 @@ final class RemoteClassLoader extends ClassLoader { if(urls!=null) return urls.elements(); + long startTime = System.nanoTime(); byte[][] images = proxy.getResources(name); + channel.resourceLoadingTime.addAndGet(System.nanoTime()-startTime); + channel.resourceLoadingCount.incrementAndGet(); urls = new Vector(); for( byte[] image: images )