jetty-9 ConcurrentScheduler refinements
This commit is contained in:
parent
c3776764f4
commit
e29e55ffcc
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.util.thread;
|
||||||
|
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
|
|
||||||
|
public class ScheduledExecutionServiceScheduler extends AbstractLifeCycle implements Scheduler
|
||||||
|
{
|
||||||
|
ScheduledExecutorService _service;
|
||||||
|
|
||||||
|
public ScheduledExecutionServiceScheduler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStart() throws Exception
|
||||||
|
{
|
||||||
|
_service=new ScheduledThreadPoolExecutor(1);
|
||||||
|
super.doStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStop() throws Exception
|
||||||
|
{
|
||||||
|
super.doStop();
|
||||||
|
_service=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Task schedule(final Runnable task, final long delay, final TimeUnit units)
|
||||||
|
{
|
||||||
|
final Future<?> future = _service.schedule(task,delay,units);
|
||||||
|
return new Task()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean cancel()
|
||||||
|
{
|
||||||
|
return future.cancel(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,290 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
|
import java.lang.management.CompilationMXBean;
|
||||||
|
import java.lang.management.GarbageCollectorMXBean;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.MemoryMXBean;
|
||||||
|
import java.lang.management.MemoryPoolMXBean;
|
||||||
|
import java.lang.management.MemoryUsage;
|
||||||
|
import java.lang.management.OperatingSystemMXBean;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class BenchmarkHelper implements Runnable
|
||||||
|
{
|
||||||
|
private final OperatingSystemMXBean operatingSystem;
|
||||||
|
private final CompilationMXBean jitCompiler;
|
||||||
|
private final MemoryMXBean heapMemory;
|
||||||
|
private final AtomicInteger starts = new AtomicInteger();
|
||||||
|
private volatile MemoryPoolMXBean youngMemoryPool;
|
||||||
|
private volatile MemoryPoolMXBean survivorMemoryPool;
|
||||||
|
private volatile MemoryPoolMXBean oldMemoryPool;
|
||||||
|
private volatile boolean hasMemoryPools;
|
||||||
|
private volatile ScheduledFuture<?> memoryPoller;
|
||||||
|
private volatile GarbageCollectorMXBean youngCollector;
|
||||||
|
private volatile GarbageCollectorMXBean oldCollector;
|
||||||
|
private volatile boolean hasCollectors;
|
||||||
|
private volatile ScheduledExecutorService scheduler;
|
||||||
|
private volatile boolean polling;
|
||||||
|
private volatile long lastYoungUsed;
|
||||||
|
private volatile long startYoungCollections;
|
||||||
|
private volatile long startYoungCollectionsTime;
|
||||||
|
private volatile long totalYoungUsed;
|
||||||
|
private volatile long lastSurvivorUsed;
|
||||||
|
private volatile long totalSurvivorUsed;
|
||||||
|
private volatile long lastOldUsed;
|
||||||
|
private volatile long startOldCollections;
|
||||||
|
private volatile long startOldCollectionsTime;
|
||||||
|
private volatile long totalOldUsed;
|
||||||
|
private volatile long startTime;
|
||||||
|
private volatile long startProcessCPUTime;
|
||||||
|
private volatile long startJITCTime;
|
||||||
|
|
||||||
|
public BenchmarkHelper()
|
||||||
|
{
|
||||||
|
this.operatingSystem = ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
this.jitCompiler = ManagementFactory.getCompilationMXBean();
|
||||||
|
this.heapMemory = ManagementFactory.getMemoryMXBean();
|
||||||
|
|
||||||
|
List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
|
||||||
|
for (MemoryPoolMXBean memoryPool : memoryPools)
|
||||||
|
{
|
||||||
|
if ("PS Eden Space".equals(memoryPool.getName()) ||
|
||||||
|
"Par Eden Space".equals(memoryPool.getName()) ||
|
||||||
|
"G1 Eden".equals(memoryPool.getName()))
|
||||||
|
youngMemoryPool = memoryPool;
|
||||||
|
else if ("PS Survivor Space".equals(memoryPool.getName()) ||
|
||||||
|
"Par Survivor Space".equals(memoryPool.getName()) ||
|
||||||
|
"G1 Survivor".equals(memoryPool.getName()))
|
||||||
|
survivorMemoryPool = memoryPool;
|
||||||
|
else if ("PS Old Gen".equals(memoryPool.getName()) ||
|
||||||
|
"CMS Old Gen".equals(memoryPool.getName()) ||
|
||||||
|
"G1 Old Gen".equals(memoryPool.getName()))
|
||||||
|
oldMemoryPool = memoryPool;
|
||||||
|
}
|
||||||
|
hasMemoryPools = youngMemoryPool != null && survivorMemoryPool != null && oldMemoryPool != null;
|
||||||
|
|
||||||
|
List<GarbageCollectorMXBean> garbageCollectors = ManagementFactory.getGarbageCollectorMXBeans();
|
||||||
|
for (GarbageCollectorMXBean garbageCollector : garbageCollectors)
|
||||||
|
{
|
||||||
|
if ("PS Scavenge".equals(garbageCollector.getName()) ||
|
||||||
|
"ParNew".equals(garbageCollector.getName()) ||
|
||||||
|
"G1 Young Generation".equals(garbageCollector.getName()))
|
||||||
|
youngCollector = garbageCollector;
|
||||||
|
else if ("PS MarkSweep".equals(garbageCollector.getName()) ||
|
||||||
|
"ConcurrentMarkSweep".equals(garbageCollector.getName()) ||
|
||||||
|
"G1 Old Generation".equals(garbageCollector.getName()))
|
||||||
|
oldCollector = garbageCollector;
|
||||||
|
}
|
||||||
|
hasCollectors = youngCollector != null && oldCollector != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (!hasMemoryPools)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long young = youngMemoryPool.getUsage().getUsed();
|
||||||
|
long survivor = survivorMemoryPool.getUsage().getUsed();
|
||||||
|
long old = oldMemoryPool.getUsage().getUsed();
|
||||||
|
|
||||||
|
if (!polling)
|
||||||
|
{
|
||||||
|
polling = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lastYoungUsed <= young)
|
||||||
|
{
|
||||||
|
totalYoungUsed += young - lastYoungUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastSurvivorUsed <= survivor)
|
||||||
|
{
|
||||||
|
totalSurvivorUsed += survivor - lastSurvivorUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastOldUsed <= old)
|
||||||
|
{
|
||||||
|
totalOldUsed += old - lastOldUsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// May need something more here, like "how much was collected"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastYoungUsed = young;
|
||||||
|
lastSurvivorUsed = survivor;
|
||||||
|
lastOldUsed = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean startStatistics()
|
||||||
|
{
|
||||||
|
// Support for multiple nodes requires to ignore start requests after the first
|
||||||
|
// but also requires that requests after the first wait until the initialization
|
||||||
|
// is completed (otherwise node #2 may start the run while the server is GC'ing)
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (starts.incrementAndGet() > 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
System.gc();
|
||||||
|
System.err.println("\n========================================");
|
||||||
|
System.err.println("Statistics Started at " + new Date());
|
||||||
|
System.err.println("Operative System: " + operatingSystem.getName() + " " + operatingSystem.getVersion() + " " + operatingSystem.getArch());
|
||||||
|
System.err.println("JVM : " + System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name") + " runtime " + System.getProperty("java.vm.version") + " " + System.getProperty("java.runtime.version"));
|
||||||
|
System.err.println("Processors: " + operatingSystem.getAvailableProcessors());
|
||||||
|
if (operatingSystem instanceof com.sun.management.OperatingSystemMXBean)
|
||||||
|
{
|
||||||
|
com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)operatingSystem;
|
||||||
|
long totalMemory = os.getTotalPhysicalMemorySize();
|
||||||
|
long freeMemory = os.getFreePhysicalMemorySize();
|
||||||
|
System.err.println("System Memory: " + percent(totalMemory - freeMemory, totalMemory) + "% used of " + gibiBytes(totalMemory) + " GiB");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("System Memory: N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryUsage heapMemoryUsage = heapMemory.getHeapMemoryUsage();
|
||||||
|
System.err.println("Used Heap Size: " + mebiBytes(heapMemoryUsage.getUsed()) + " MiB");
|
||||||
|
System.err.println("Max Heap Size: " + mebiBytes(heapMemoryUsage.getMax()) + " MiB");
|
||||||
|
if (hasMemoryPools)
|
||||||
|
{
|
||||||
|
long youngGenerationHeap = heapMemoryUsage.getMax() - oldMemoryPool.getUsage().getMax();
|
||||||
|
System.err.println("Young Generation Heap Size: " + mebiBytes(youngGenerationHeap) + " MiB");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Young Generation Heap Size: N/A");
|
||||||
|
}
|
||||||
|
System.err.println("- - - - - - - - - - - - - - - - - - - - ");
|
||||||
|
|
||||||
|
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
polling = false;
|
||||||
|
memoryPoller = scheduler.scheduleWithFixedDelay(this, 0, 250, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
lastYoungUsed = 0;
|
||||||
|
if (hasCollectors)
|
||||||
|
{
|
||||||
|
startYoungCollections = youngCollector.getCollectionCount();
|
||||||
|
startYoungCollectionsTime = youngCollector.getCollectionTime();
|
||||||
|
}
|
||||||
|
totalYoungUsed = 0;
|
||||||
|
lastSurvivorUsed = 0;
|
||||||
|
totalSurvivorUsed = 0;
|
||||||
|
lastOldUsed = 0;
|
||||||
|
if (hasCollectors)
|
||||||
|
{
|
||||||
|
startOldCollections = oldCollector.getCollectionCount();
|
||||||
|
startOldCollectionsTime = oldCollector.getCollectionTime();
|
||||||
|
}
|
||||||
|
totalOldUsed = 0;
|
||||||
|
|
||||||
|
startTime = System.nanoTime();
|
||||||
|
if (operatingSystem instanceof com.sun.management.OperatingSystemMXBean)
|
||||||
|
{
|
||||||
|
com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)operatingSystem;
|
||||||
|
startProcessCPUTime = os.getProcessCpuTime();
|
||||||
|
}
|
||||||
|
startJITCTime = jitCompiler.getTotalCompilationTime();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean stopStatistics()
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (starts.decrementAndGet() > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memoryPoller.cancel(false);
|
||||||
|
scheduler.shutdown();
|
||||||
|
|
||||||
|
System.err.println("- - - - - - - - - - - - - - - - - - - - ");
|
||||||
|
System.err.println("Statistics Ended at " + new Date());
|
||||||
|
long elapsedTime = System.nanoTime() - startTime;
|
||||||
|
System.err.println("Elapsed time: " + TimeUnit.NANOSECONDS.toMillis(elapsedTime) + " ms");
|
||||||
|
long elapsedJITCTime = jitCompiler.getTotalCompilationTime() - startJITCTime;
|
||||||
|
System.err.println("\tTime in JIT compilation: " + elapsedJITCTime + " ms");
|
||||||
|
if (hasCollectors)
|
||||||
|
{
|
||||||
|
long elapsedYoungCollectionsTime = youngCollector.getCollectionTime() - startYoungCollectionsTime;
|
||||||
|
long youngCollections = youngCollector.getCollectionCount() - startYoungCollections;
|
||||||
|
System.err.println("\tTime in Young Generation GC: " + elapsedYoungCollectionsTime + " ms (" + youngCollections + " collections)");
|
||||||
|
long elapsedOldCollectionsTime = oldCollector.getCollectionTime() - startOldCollectionsTime;
|
||||||
|
long oldCollections = oldCollector.getCollectionCount() - startOldCollections;
|
||||||
|
System.err.println("\tTime in Old Generation GC: " + elapsedOldCollectionsTime + " ms (" + oldCollections + " collections)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("\tTime in GC: N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMemoryPools)
|
||||||
|
{
|
||||||
|
System.err.println("Garbage Generated in Young Generation: " + mebiBytes(totalYoungUsed) + " MiB");
|
||||||
|
System.err.println("Garbage Generated in Survivor Generation: " + mebiBytes(totalSurvivorUsed) + " MiB");
|
||||||
|
System.err.println("Garbage Generated in Old Generation: " + mebiBytes(totalOldUsed) + " MiB");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Garbage Generated: N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operatingSystem instanceof com.sun.management.OperatingSystemMXBean)
|
||||||
|
{
|
||||||
|
com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)operatingSystem;
|
||||||
|
long elapsedProcessCPUTime = os.getProcessCpuTime() - startProcessCPUTime;
|
||||||
|
System.err.println("Average CPU Load: " + ((float)elapsedProcessCPUTime * 100 / elapsedTime) + "/" + (100 * operatingSystem.getAvailableProcessors()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Average CPU Load: N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println("----------------------------------------\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float percent(long dividend, long divisor)
|
||||||
|
{
|
||||||
|
return (float)dividend * 100 / divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float mebiBytes(long bytes)
|
||||||
|
{
|
||||||
|
return (float)bytes / 1024 / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float gibiBytes(long bytes)
|
||||||
|
{
|
||||||
|
return (float)bytes / 1024 / 1024 / 1024;
|
||||||
|
}
|
||||||
|
}
|
|
@ -142,7 +142,7 @@ public class SchedulerTest
|
||||||
@Slow
|
@Slow
|
||||||
public void testManySchedulesAndCancels() throws Exception
|
public void testManySchedulesAndCancels() throws Exception
|
||||||
{
|
{
|
||||||
schedule(500,5000,2000,50);
|
schedule(500,3000,1800,50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue