/* * Copyright 2003-2015 JetBrains s.r.o. * * 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 jetbrains.mps.generator.test; import jetbrains.mps.generator.GenerationCanceledException; import jetbrains.mps.generator.impl.GenerationFailureException; import jetbrains.mps.generator.impl.GenerationTaskPool; import jetbrains.mps.generator.impl.IGenerationTaskPool.GenerationTask; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** * Evgeny Gryaznov, Apr 7, 2010 */ public class ParallelPoolTest extends TestCase { private static Logger LOG = LogManager.getLogger(ParallelPoolTest.class); private static class CustomTask implements GenerationTask { private AtomicBoolean isFinished = new AtomicBoolean(false); private final long amountOfWork; private CustomTask(long amountOfWork) { this.amountOfWork = amountOfWork; } public boolean isFinished() { return isFinished.get(); } @Override public void run() throws GenerationCanceledException, GenerationFailureException { isFinished.set(false); long localCounter = amountOfWork; long fract = 1; while (fract < amountOfWork) { fract <<= 1; } fract = (fract >> 6); long fractCounter; long start = System.currentTimeMillis(); while (localCounter > 0) { fractCounter = fract; while (fractCounter > 0) { fractCounter--; } localCounter -= fract; } long end = System.currentTimeMillis(); LOG.info("Took " + (end - start) / 1000. + " secs"); isFinished.set(true); } } private static class CancelTask extends CustomTask { public CancelTask(long delay) { super(delay); } @Override public void run() throws GenerationCanceledException, GenerationFailureException { super.run(); throw new GenerationCanceledException(); } } private static long get2SecsOperation() { int measureTime = 500; long count2secs = 0; long startTime = System.currentTimeMillis(); long endTime = startTime + measureTime; while (System.currentTimeMillis() < endTime) { long localCounter = 0; while (localCounter < 10000000l) { localCounter++; } count2secs += localCounter; } endTime = System.currentTimeMillis(); long amountOfWork = count2secs * measureTime / (endTime - startTime); long localCounter = amountOfWork; startTime = System.currentTimeMillis(); while (localCounter > 0) { localCounter--; } endTime = System.currentTimeMillis(); amountOfWork = amountOfWork * 2000 / (endTime - startTime); return amountOfWork; } private static CustomTask[] createTasks(long amountOfWork, int numberOfTasks) { List<CustomTask> tasks = new ArrayList<CustomTask>(); for (int i = 0; i < numberOfTasks; i++) { tasks.add(new CustomTask(amountOfWork)); } return tasks.toArray(new CustomTask[numberOfTasks]); } public void testPoolSpeed() { int cores = Runtime.getRuntime().availableProcessors(); if (cores < 3) { // cannot proceed return; } long amountFor2secs = get2SecsOperation(); LOG.info("Work amount: " + amountFor2secs + " ticks"); long start = System.currentTimeMillis(); GenerationTaskPool pool = new GenerationTaskPool(4); final CustomTask[] generationTasks = createTasks(amountFor2secs, 4); for (GenerationTask t : generationTasks) { pool.addTask(t); } try { pool.waitForCompletion(); } catch (GenerationCanceledException e) { Assert.fail(); } catch (GenerationFailureException e) { Assert.fail(); } long end = System.currentTimeMillis(); for (CustomTask t : generationTasks) { Assert.assertTrue(t.isFinished()); } LOG.info("Total " + (end - start) / 1000. + " seconds to complete 4 x 2secs tasks"); Assert.assertTrue("too slow: " + (end - start), (end - start) < 4500); // at least 2 core cpu pool.dispose(); } public void testPoolCancelling() { int cores = Runtime.getRuntime().availableProcessors(); if (cores < 3) { // cannot proceed return; } long amountFor2secs = get2SecsOperation(); long duration = doCancelTest(amountFor2secs * 4, 0, 1000); LOG.info("Total " + duration / 1000. + " seconds, when cancelled after 1 sec."); Assert.assertTrue(duration < 1500 && duration > 970); } public void testPoolCancelling2() { int cores = Runtime.getRuntime().availableProcessors(); if (cores < 3) { // cannot proceed return; } long amountFor2secs = get2SecsOperation(); long duration = doCancelTest(amountFor2secs * 4, Math.round(amountFor2secs * 0.8), 0); LOG.info("Total " + duration / 1000. + " seconds (should be 2 secs), when cancelled after 1.6 secs"); Assert.assertTrue(duration < 2300 && duration > 1700); } private long doCancelTest(long taskWork, long cancelDelayWork, long msPoolWaitDelay) { final long start = System.currentTimeMillis(); GenerationTaskPool pool = new GenerationTaskPool(4); final CustomTask[] generationTasks = createTasks(taskWork, 4); pool.addTask(new CancelTask(cancelDelayWork)); for (GenerationTask t : generationTasks) { pool.addTask(t); } boolean canceledExc = false; try { if (msPoolWaitDelay > 0) { // let the pool detect cancellation after specified delay Thread.sleep(msPoolWaitDelay); } pool.waitForCompletion(); } catch (GenerationCanceledException e) { canceledExc = true; } catch (GenerationFailureException e) { } catch (InterruptedException ex) { } pool.dispose(); Assert.assertTrue(canceledExc); long end = System.currentTimeMillis(); for (CustomTask t : generationTasks) { Assert.assertFalse("task should not be finished", t.isFinished()); } return end - start; } }