From ba6a2e3fd2ca937b1027345c1638a0c2c0527110 Mon Sep 17 00:00:00 2001 From: jrandom <jrandom> Date: Sun, 13 Jun 2004 20:03:21 +0000 Subject: [PATCH] unit test for the bandwidth limiting functionality (TrivialBandwidthLimiter, BandwidthLimiter, BandwidthLimited{In,Out}putStream) --- .../transport/BandwidthLimiterTest.java | 209 ++++++++++++++++++ .../i2p/router/transport/FakeInputStream.java | 27 +++ .../router/transport/NullOutputStream.java | 11 + 3 files changed, 247 insertions(+) create mode 100644 router/java/test/net/i2p/router/transport/BandwidthLimiterTest.java create mode 100644 router/java/test/net/i2p/router/transport/FakeInputStream.java create mode 100644 router/java/test/net/i2p/router/transport/NullOutputStream.java diff --git a/router/java/test/net/i2p/router/transport/BandwidthLimiterTest.java b/router/java/test/net/i2p/router/transport/BandwidthLimiterTest.java new file mode 100644 index 0000000000..23ae110454 --- /dev/null +++ b/router/java/test/net/i2p/router/transport/BandwidthLimiterTest.java @@ -0,0 +1,209 @@ +package net.i2p.router.transport; + +import net.i2p.router.RouterContext; +import net.i2p.util.Log; + +import java.io.IOException; + +import java.util.Random; +import java.util.Properties; + +/** + * Stress out the bandwidth limiter by running a series of push and pull tests + * through bandwidth limited streams. This includes pushing data through + * unthrottled streams, through streams throttled at 4KBps, 32KBps, and 256KBps, + * pulling data through those same rates, as well as doing so with 10 concurrent + * threads (and, in turn, 10 concurrent streams all using the same BandwidthLimiter). + * + * Note: this takes a long time to run (~1 hour) since the 4KBps push/pull of 1MB with + * 10 concurrent threads is, well, slow. + * + */ +public class BandwidthLimiterTest { + private RouterContext _context; + private Log _log; + private final static int NUM_MB = 1; + + public BandwidthLimiterTest() { + _context = new RouterContext(null); + _log = _context.logManager().getLog(BandwidthLimiterTest.class); + //_context.jobQueue().runQueue(1); + } + + public void prepareLimiter(int inKBps, int outKBps, int inBurst, int outBurst) { + Properties props = new Properties(); + props.setProperty(TrivialBandwidthLimiter.PROP_INBOUND_BANDWIDTH, ""+inKBps); + props.setProperty(TrivialBandwidthLimiter.PROP_OUTBOUND_BANDWIDTH, ""+outKBps); + props.setProperty(TrivialBandwidthLimiter.PROP_INBOUND_BANDWIDTH_PEAK, ""+inBurst); + props.setProperty(TrivialBandwidthLimiter.PROP_OUTBOUND_BANDWIDTH_PEAK, ""+outBurst); + //props.setProperty(TrivialBandwidthLimiter.PROP_REPLENISH_FREQUENCY, ""+10*1000); + System.setProperties(props); + ((TrivialBandwidthLimiter)_context.bandwidthLimiter()).reinitialize(); + } + + /** + * Using the configured limiter, determine how long it takes to shove + * numBytes through a BandwidthLimitedOutputStream (broken up into numBytesPerWrite) + * chunks. + * + */ + public long testOutboundThrottle(int numBytes, int numBytesPerWrite) { + byte source[] = new byte[numBytesPerWrite]; + new Random().nextBytes(source); + NullOutputStream target = new NullOutputStream(); + BandwidthLimitedOutputStream out = new BandwidthLimitedOutputStream(_context, target, null); + long before = System.currentTimeMillis(); + try { + for (int i = 0; i < numBytes; i += numBytesPerWrite) { + int num = numBytesPerWrite; + if (numBytesPerWrite + i >= numBytes) + num = numBytes - i; + //_log.info("** Writing " + num + " bytes starting at " + i); + out.write(source, 0, num); + } + } catch (IOException ioe) {} + long after = System.currentTimeMillis(); + return after-before; + } + + /** + * Using the configured limiter, determine how long it takes to read + * numBytes through a BandwidthLimitedInputStream (broken up into numBytesPerRead) + * chunks. + * + */ + public long testInboundThrottle(int numBytes, int numBytesPerRead) { + FakeInputStream source = new FakeInputStream(numBytes); + BandwidthLimitedInputStream in = new BandwidthLimitedInputStream(_context, source, null); + long before = System.currentTimeMillis(); + try { + byte buf[] = new byte[numBytesPerRead]; + int read = 0; + while ( (read = in.read(buf)) != -1) { + //_log.info("** Read " + read + " bytes"); + // gobble the data. who cares + } + } catch (IOException ioe) {} + long after = System.currentTimeMillis(); + return after-before; + } + + /** + * Run a series of tests on outbound throttling (shoving lots of data through pipes + * with various limits) and log the times. + * + */ + public void testOutbound() { + prepareLimiter(-1, -1, -1, -1); + long ms = testOutboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** Unlimited pushed " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(-1, 4, -1, 5*1024*1024); + ms = testOutboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** 4KBps pushed " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(-1, 32, -1, 5*1024*1024); + ms = testOutboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** 32KBps pushed " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(-1, 256, -1, 5*1024*1024); + ms = testOutboundThrottle(NUM_MB*1024*1024, 256*1024); + _log.info("** 256KBps pushed " + NUM_MB + "MB in " + ms + "ms"); + } + + /** + * Run a series of tests on inbound throttling (pulling lots of data through pipes + * with various limits) and log the times. + * + */ + public void testInbound() { + prepareLimiter(-1, -1, -1, -1); + long ms = testInboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** Unlimited pulled " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(4, -1, 5*1024*1024, -1); + ms = testInboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** 4KBps pulled " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(32, -1, 5*1024*1024, -1); + ms = testInboundThrottle(NUM_MB*1024*1024, 32*1024); + _log.info("** 32KBps pulled " + NUM_MB + "MB in " + ms + "ms"); + prepareLimiter(256, -1, 5*1024*1024, -1); + ms = testInboundThrottle(NUM_MB*1024*1024, 256*1024); + _log.info("** 256KBps pulled " + NUM_MB + "MB in " + ms + "ms"); + } + + + public void testOutboundContention() { + prepareLimiter(-1, -1, -1, -1); + long start = System.currentTimeMillis(); + long runningTimes[] = testOutboundContention(10, NUM_MB*1024*1024); + long end = System.currentTimeMillis(); + _log.info("** Done with unlimited " + NUM_MB + "MB test with 10 concurrent threads after " + (end-start) + "ms: " + displayTimes(runningTimes)); + prepareLimiter(-1, 4, -1, 5*1024*1024); + start = System.currentTimeMillis(); + runningTimes = testOutboundContention(10, NUM_MB*1024*1024); + end = System.currentTimeMillis(); + _log.info("** Done with 4KBps " + NUM_MB + "MB test with 10 concurrent threads after " + (end-start) + "ms: " + displayTimes(runningTimes)); + prepareLimiter(-1, 32, -1, 5*1024*1024); + start = System.currentTimeMillis(); + runningTimes = testOutboundContention(10, NUM_MB*1024*1024); + end = System.currentTimeMillis(); + _log.info("** Done with 32KBps " + NUM_MB + "MB test with 10 concurrent threads after " + (end-start) + "ms: " + displayTimes(runningTimes)); + prepareLimiter(-1, 256, -1, 5*1024*1024); + start = System.currentTimeMillis(); + runningTimes = testOutboundContention(10, NUM_MB*1024*1024); + end = System.currentTimeMillis(); + _log.info("** Done with 256KBps " + NUM_MB + "MB test with 10 concurrent threads after " + (end-start) + "ms: " + displayTimes(runningTimes)); + } + + private String displayTimes(long times[]) { + StringBuffer rv = new StringBuffer(); + for (int i = 0; i < times.length; i++) { + rv.append(times[i]); + if (i + 1 <= times.length) + rv.append(' '); + } + return rv.toString(); + } + + private long[] testOutboundContention(int numConcurrent, int numBytes) { + OutboundRunner threads[] = new OutboundRunner[numConcurrent]; + for (int i = 0; i < numConcurrent; i++) { + threads[i] = new OutboundRunner(numBytes); + } + _log.debug("Starting up outbound contention test for " + numBytes + " with " + numConcurrent + " runners"); + for (int i = 0; i < numConcurrent; i++) + threads[i].start(); + for (int i = 0; i < numConcurrent; i++) { + try { + threads[i].join(); + } catch (InterruptedException ie) {} + } + long rv[] = new long[numConcurrent]; + for (int i = 0; i < numConcurrent; i++) + rv[i] = threads[i].getRunningTime(); + return rv; + } + + private static int __runnerNum = 0; + private class OutboundRunner extends Thread { + private int _numBytes; + private int _runnerNum; + private long _runningTime; + public OutboundRunner(int numBytes) { + _numBytes = numBytes; + _runnerNum = ++__runnerNum; + } + public void run() { + Thread.currentThread().setName("Out" + _runnerNum); + _runningTime = testOutboundThrottle(_numBytes, 8*1024); + _log.debug("Outbound runner " + _runnerNum + " pushed " + _numBytes + " in " + _runningTime + "ms"); + } + public long getRunningTime() { return _runningTime; } + } + + + public static void main(String args[]) { + BandwidthLimiterTest test = new BandwidthLimiterTest(); + test.testOutbound(); + test.testInbound(); + test.testOutboundContention(); + System.exit(0); + } +} \ No newline at end of file diff --git a/router/java/test/net/i2p/router/transport/FakeInputStream.java b/router/java/test/net/i2p/router/transport/FakeInputStream.java new file mode 100644 index 0000000000..e08ddb1481 --- /dev/null +++ b/router/java/test/net/i2p/router/transport/FakeInputStream.java @@ -0,0 +1,27 @@ +package net.i2p.router.transport; + +import java.io.InputStream; + +/** + * Read up to a specified number of bytes, then EOF. + * Uses pretty much no memory. + * + */ +public class FakeInputStream extends InputStream { + private volatile int _numRead; + private int _size; + + public FakeInputStream(int size) { + _size = size; + _numRead = 0; + } + public int read() { + int rv = 0; + if (_numRead >= _size) + rv = -1; + else + rv = 42; + _numRead++; + return rv; + } +} \ No newline at end of file diff --git a/router/java/test/net/i2p/router/transport/NullOutputStream.java b/router/java/test/net/i2p/router/transport/NullOutputStream.java new file mode 100644 index 0000000000..d878113c36 --- /dev/null +++ b/router/java/test/net/i2p/router/transport/NullOutputStream.java @@ -0,0 +1,11 @@ +package net.i2p.router.transport; + +import java.io.OutputStream; + +/** + * Output stream for when we don't care whats written + * + */ +public class NullOutputStream extends OutputStream { + public void write(int param) {} +} \ No newline at end of file -- GitLab