diff options
Diffstat (limited to 'src/test/java/com/jsyn/research/BenchMultiThreading.java')
-rw-r--r-- | src/test/java/com/jsyn/research/BenchMultiThreading.java | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/test/java/com/jsyn/research/BenchMultiThreading.java b/src/test/java/com/jsyn/research/BenchMultiThreading.java new file mode 100644 index 0000000..24624c5 --- /dev/null +++ b/src/test/java/com/jsyn/research/BenchMultiThreading.java @@ -0,0 +1,152 @@ +/* + * Copyright 2009 Phil Burk, Mobileer Inc + * + * Licensed 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 com.jsyn.research; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO: Use thread pools, or maybe JMH? +public class BenchMultiThreading { + + private static final Logger LOGGER = LoggerFactory.getLogger(BenchMultiThreading.class); + + private static final int FRAMES_PER_BLOCK = 64; + int numThreads = 4; + int numLoops = 100000; + private ArrayList<CustomThread> threadList; + + static class CustomThread extends Thread { + long frameCount = 0; + long desiredFrame = 0; + Object semaphore = new Object(); + Object goSemaphore = new Object(); + volatile boolean go = true; + long startNano; + long stopNano; + long maxElapsed; + + @Override + public void run() { + try { + startNano = System.nanoTime(); + while (go) { + // Watch for long delays. + stopNano = System.nanoTime(); + long elapsed = stopNano - startNano; + startNano = System.nanoTime(); + if (elapsed > maxElapsed) { + maxElapsed = elapsed; + } + + synchronized (semaphore) { + // Audio synthesis would occur here. + frameCount += 1; + // LOGGER.debug( this + " generating frame " + + // frameCount ); + semaphore.notify(); + } + synchronized (goSemaphore) { + while (desiredFrame <= frameCount) { + goSemaphore.wait(); + } + } + long stopNano = System.nanoTime(); + } + } catch (InterruptedException e) { + LOGGER.debug("CustomThread interrupted. "); + } + LOGGER.debug("Finishing " + this); + } + + public void abort() { + go = false; + interrupt(); + } + + public void waitForFrame(long targetFrame) throws InterruptedException { + synchronized (semaphore) { + while (frameCount < targetFrame) { + semaphore.wait(); + } + } + } + + public void generateFrame(long desiredFrame) { + synchronized (goSemaphore) { + this.desiredFrame = desiredFrame; + goSemaphore.notify(); + } + } + + } + + @Test + public void testMultiThreads() { + threadList = new ArrayList<>(); + for (int i = 0; i < numThreads; i++) { + CustomThread thread = new CustomThread(); + threadList.add(thread); + thread.start(); + } + + long frameCount = 0; + long startTime = System.currentTimeMillis(); + try { + for (int i = 0; i < numLoops; i++) { + frameCount += 1; + waitForThreads(frameCount); + // LOGGER.debug("got frame " + frameCount ); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + long stopTime = System.currentTimeMillis(); + long elapsedTime = stopTime - startTime; + double elapsedSeconds = 0.001 * elapsedTime; + double blocksPerSecond = numLoops / elapsedSeconds; + System.out.format("blocksPerSecond = %10.3f\n", blocksPerSecond); + double framesPerSecond = blocksPerSecond * FRAMES_PER_BLOCK; + System.out.format("audio framesPerSecond = %10.3f at %d frames per block\n", + framesPerSecond, FRAMES_PER_BLOCK); + + for (CustomThread thread : threadList) { + System.out.format("max elapsed time is %d nanos or %f msec\n", thread.maxElapsed, + (thread.maxElapsed / 1000000.0)); + } + for (CustomThread thread : threadList) { + assertEquals(frameCount, thread.frameCount, "BlockCount must match "); + thread.abort(); + } + + } + + private void waitForThreads(long frameCount) throws InterruptedException { + for (CustomThread thread : threadList) { + // Ask threads to wake up and generate up to this frame. + thread.generateFrame(frameCount); + } + for (CustomThread thread : threadList) { + // Wait for all the threads to catch up. + thread.waitForFrame(frameCount); + } + } +} |