Сравнительный анализ безблокировочного стека с помощью Java и JMH - PullRequest
0 голосов
/ 25 февраля 2019

Для одного из моих университетских курсов мне необходимо реализовать реализацию стека без блокировок и выполнить его тестирование, чтобы увидеть, как оно масштабируется с учетом количества потоков и распределения операций.Недавно я обнаружил JMH и решил применить его к компоненту сравнительного анализа домашнего задания.Я просто не уверен, что я реализую это так элегантно, как мог бы.

Мой профессор хочет, чтобы мы измерили время, необходимое для выполнения 1, 2, 4, 8, 16 и 32 потоков3 разных распределения операций.Я смоделировал это ниже:

package kylemart.multicore.assignment2;

import org.openjdk.jmh.annotations.*;

// Annotations here... 
public class P1StackBenchmarks {

    @Benchmark
    public void runScenarioA(ScenarioA scenario) throws InterruptedException {
        runThreads(scenario.threads);
    }

    @Benchmark
    public void runScenarioB(ScenarioB scenario) throws InterruptedException {
        runThreads(scenario.threads);
    }

    @Benchmark
    public void runScenarioC(ScenarioC scenario) throws InterruptedException {
        runThreads(scenario.threads);
    }

    private void runThreads(Thread[] threads) throws InterruptedException {
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            thread.join();
        }
    }

    @State(Scope.Benchmark)
    public static class BenchmarkParameters {

        @Param({"1", "2", "4", "8", "16", "32"})
        int threadCount;

        static final int iterations = 500_000;
    }

    @State(Scope.Thread)
    public static abstract class Scenario {

        Thread[] threads;
        PStack<Object> stack;
        Object object;

        @Setup(Level.Invocation)
        public void setup(BenchmarkParameters params) {
            threads = new Thread[params.threadCount];
            stack = new P1Stack<>();
            object = new Object();
            Runnable runnable = () -> {
                for (int iteration = 0; iteration < params.iterations; iteration++) {
                    operations();
                }
            };
            for (int index = 0; index < threads.length; index++) {
                threads[index] = new Thread(runnable);
            }
        }

        protected abstract void operations();
    }

    public static class ScenarioA extends Scenario {

        @Override
        protected void operations() {
            // stack.push(object);
            // ...
        }
    }

    public static class ScenarioB extends Scenario {

        @Override
        protected void operations() {
            // stack.push(object);
            // ...
        }
    }

    public static class ScenarioC extends Scenario {

        @Override
        protected void operations() {
            // stack.push(object);
            // ...
        }
    }
}

Каждый сценарий, A, B и C, имеет метод operations(), который определяет набор операций стека с определенной частотой pop(), * 1008.* и size() звонки.Абстрактный класс Scenario является «шаблоном» для этих конкретных сценариев.Предполагая, что аннотации являются наследуемыми (что, по-видимому, имеет место - хотя не против того, чтобы кто-то проверял это), я бы ожидал, что экземпляры трех конкретных классов сценариев будут видоизменены в единичные потоки (то есть @State(Scope.Thread)) иего метод setup() запускается перед каждым вызовом эталонного метода (то есть @Setup(Level.Invocation)).Благодаря этому я смогу создать и настроить потоки каждого сценария до того, как мы начнем запускать потоки.

Есть какие-либо проблемы с этой реализацией?Есть ли в JMH другие средства, которые облегчили бы решение / реализацию этой проблемы?Спасибо!

...