Nano Hash - криптовалюты, майнинг, программирование

Как настроить тестирование jmh для встроенного orientdb?

Я пытаюсь настроить тест jmh для встроенной базы данных orient. Набор тестов выглядит следующим образом:

@State(Scope.Benchmark)
public class OrientDbTest {
    private OObjectDatabaseTx db;
    private Person[] personList;

    @Setup
    public void setUp() throws IOException {
        deleteDir("/tmp/orientdb/");
        db = new OObjectDatabaseTx("plocal:/tmp/orientdb/person").create();
        ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
        loadData();
    }

    @TearDown
    public void cleanUp() {
        if (db != null) {
            ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
            db.commit();
            db.drop();
            db.close();
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void benchmarkInsertCompany() {
        ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
        db.getEntityManager().registerEntityClass(Person.class);

        for (Person person : personList) {
            db.save(person);
        }
    }

    void loadData() throws IOException {
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("data.json");
        ObjectMapper objectMapper = new ObjectMapper();
        personList = objectMapper.readValue(inputStream, Person[].class);
    }

    void deleteDir(String dirName) {
        File file = new File(dirName);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File child : files) {
                    if (child.isDirectory()) {
                        deleteDir(child.getAbsolutePath());
                    } else {
                        child.delete();
                    }
                }
            } else {
                file.delete();
            }
        }
    }
}

Этот проект является проектом gradle, и я использую плагин gradle-jmh. Вот настройки jmh в файле build.gradle:

jmh {
    jmhVersion = '1.14'
    iterations = 10 // Number of measurement iterations to do.
    fork = 2 // How many times to forks a single benchmark. Use 0 to disable forking altogether
    jvmArgs = '-server -XX:MaxDirectMemorySize=15986m'
    resultsFile = project.file("${project.buildDir}/reports/jmh/results.txt") // results file
    profilers = ['cl', 'gc', 'hs_thr'] // Use profilers to collect additional data. Supported profilers: [cl, comp, gc, stack, perf, perfnorm, perfasm, xperf, xperfasm, hs_cl, hs_comp, hs_gc, hs_rt, hs_thr]
    resultFormat = 'CSV' // Result format type (one of CSV, JSON, NONE, SCSV, TEXT)
    threads = 4 // Number of worker threads to run with.
    timeUnit = 'ms' // Output time unit. Available time units are: [m, s, ms, us, ns].
    warmupForks = 2 // How many warmup forks to make for a single benchmark. 0 to disable warmup forks.
    warmupIterations = 10 // Number of warmup iterations to do.
}

Когда я запускаю тест, я получаю следующую ошибку:

INFO: OrientDB auto-config DISKCACHE=10,384MB (heap=3,554MB direct=15,986MB os=15,986MB)
<failure>

com.orientechnologies.orient.core.exception.OStorageExistsException: Cannot create new storage 'plocal:/tmp/orientdb/person' because it is not closed
        DB name="person"
        at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.create(OAbstractPaginatedStorage.java:423)
        at com.orientechnologies.orient.core.storage.impl.local.paginated.OLocalPaginatedStorage.create(OLocalPaginatedStorage.java:125)
        at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.create(ODatabaseDocumentTx.java:429)
        at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.create(ODatabaseDocumentTx.java:389)
        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.create(ODatabaseWrapperAbstract.java:75)
        at org.dizitart.no2.benchmark.OrientDbTest.setUp(OrientDbTest.java:24)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest._jmh_tryInit_f_orientdbtest0_G(OrientDbTest_benchmarkInsertCompany_jmhTest.java:400)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest.benchmarkInsertCompany_AverageTime(OrientDbTest_benchmarkInsertCompany_jmhTest.java:149)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:430)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:412)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

Что я делаю неправильно в настройке здесь?

ИЗМЕНИТЬ:

Прочитав это, я изменил код следующим образом:

public class OrientDbTest {

    @State(Scope.Benchmark)
    public static class TestState {
        private OObjectDatabaseTx db;
        private Person[] personList;
        private BenchmarkTestHelper testHelper = new BenchmarkTestHelper();

        @Setup(Level.Trial)
        public void setUp() throws IOException {
            System.out.println("started setup code");
            testHelper.deleteDir("/tmp/orientdb/");

            try {
                db = new OObjectDatabaseTx("plocal:/tmp/orientdb/person").open(null, null);
                db.getEntityManager().registerEntityClass(Person.class);
                personList = testHelper.loadData();
            } finally {
                if (db != null) {
                    db.close();
                }
            }
        }

        @TearDown(Level.Trial)
        public void cleanUp() {
            System.out.println("started cleanup code");
            if (db != null) {
                ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
                db.commit();
                db.drop();
                db.close();
            }
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void benchmarkInsertCompany(TestState state, Blackhole blackhole) {
        OObjectDatabaseTx db = state.db;
        Person[] personList = state.personList;

        ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
        for (Person person : personList) {
            blackhole.consume(db.save(person));
        }
    }
}


class BenchmarkTestHelper {
    Person[] loadData() throws IOException {
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("data.json");
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(inputStream, Person[].class);
    }

    void deleteDir(String dirName) {
        File file = new File(dirName);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File child : files) {
                    if (child.isDirectory()) {
                        deleteDir(child.getAbsolutePath());
                    } else {
                        child.delete();
                    }
                }
                file.delete();
            } else {                   
                file.delete();
            }
        }
    }
}

После новой настройки я получаю следующую ошибку:

# JMH 1.14 (released 19 days ago)
# VM version: JDK 1.8.0_77, VM 25.77-b03
# VM invoker: /home/anindya/app/jdk1.8.0_77/jre/bin/java
# VM options: -server -XX:MaxDirectMemorySize=15986m
# Warmup: 10 iterations, 1 s each
# Measurement: 10 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: org.dizitart.no2.benchmark.OrientDbTest.benchmarkInsertCompany

# Run progress: 50.00% complete, ETA 00:01:28
# Warmup Fork: 1 of 2
# Warmup Iteration   1: started setup code
Sep 26, 2016 11:15:57 AM com.orientechnologies.common.log.OLogManager log
INFO: OrientDB auto-config DISKCACHE=10,384MB (heap=3,554MB direct=15,986MB os=15,986MB)
started setup code
started setup code
started setup code
<failure>

com.orientechnologies.orient.core.exception.OStorageExistsException: Cannot create new storage 'plocal:/tmp/orientdb/person' because it is not closed
        DB name="person"
        at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.create(OAbstractPaginatedStorage.java:423)
        at com.orientechnologies.orient.core.storage.impl.local.paginated.OLocalPaginatedStorage.create(OLocalPaginatedStorage.java:125)
        at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.create(ODatabaseDocumentTx.java:429)
        at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.create(ODatabaseDocumentTx.java:389)
        at com.orientechnologies.orient.core.db.ODatabaseWrapperAbstract.create(ODatabaseWrapperAbstract.java:75)
        at org.dizitart.no2.benchmark.OrientDbTest$TestState.setUp(OrientDbTest.java:28)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest._jmh_tryInit_f_teststate1_G(OrientDbTest_benchmarkInsertCompany_jmhTest.java:409)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest.benchmarkInsertCompany_AverageTime(OrientDbTest_benchmarkInsertCompany_jmhTest.java:153)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:430)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:412)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

...

# Run progress: 87.50% complete, ETA 00:00:18
# Fork: 2 of 2
# Warmup Iteration   1: started setup code
Sep 26, 2016 11:16:38 AM com.orientechnologies.common.log.OLogManager log
INFO: OrientDB auto-config DISKCACHE=10,384MB (heap=3,554MB direct=15,986MB os=15,986MB)
started setup code
started setup code
started setup code
<failure>

java.lang.ClassCastException: com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx cannot be cast to com.orientechnologies.orient.object.db.OObjectDatabaseTx
        at org.dizitart.no2.benchmark.OrientDbTest$TestState.setUp(OrientDbTest.java:28)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest._jmh_tryInit_f_teststate1_G(OrientDbTest_benchmarkInsertCompany_jmhTest.java:409)
        at org.dizitart.no2.benchmark.generated.OrientDbTest_benchmarkInsertCompany_jmhTest.benchmarkInsertCompany_AverageTime(OrientDbTest_benchmarkInsertCompany_jmhTest.java:153)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:430)
        at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:412)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)


Sep 26, 2016 11:16:49 AM com.orientechnologies.common.log.OLogManager log
INFO: Orient Engine is shutting down...
Sep 26, 2016 11:16:49 AM com.orientechnologies.common.log.OLogManager log
INFO: - shutdown storage: person...


Ответы:


1

Итак, есть пара проблем:

а) Сам метод setUp() глючит, выдает:

java.lang.ClassCastException: com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx cannot be cast to com.orientechnologies.orient.object.db.OObjectDatabaseTx
    at jmh.demo.OrientDbTest$TestState.setUp(OrientDbTest.java:30)
    at jmh.demo.generated.OrientDbTest_benchmarkInsert_jmhTest._jmh_tryInit_f_teststate1_G(OrientDbTest_benchmarkInsert_jmhTest.java:409)
    at jmh.demo.generated.OrientDbTest_benchmarkInsert_jmhTest.benchmarkInsert_AverageTime(OrientDbTest_benchmarkInsert_jmhTest.java:153)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
...

б) метод @Setup для @State(Benchmark) предполагается выполнять только один раз. Но из-за ошибки в JMH, если первый поток завершился ошибкой с исключением выше , то другие потоки также попытаются ввести @Setup, а затем попытаются открыть базу данных, но потерпят неудачу, потому что она уже открыта?

Фактически, сбой (a) виден даже в исходном сообщении, и то, какое исключение будет сообщено от нескольких потоков, входящих в @Setup, будет зависеть от чистой удачи (это стало лучше в JMH 1.14.1). Это надежно завершается ошибкой с этим правильным исключением, если вы устанавливаете threads=1. Кроме того, путь очистки в setUp() выглядит несовместимым с tearDown(), что может объяснить, почему повторно введенные потоки не могут открыть БД.

Итог: прежде чем выполнять многопоточные тесты, попробуйте выполнить однопоточные.

26.09.2016
  • Спасибо за комментарий. Использование вилки было виновником. Я отправил рабочий код в ответ 26.09.2016
  • Подожди, нет! Если ваш тест работает с fork(0), но не с fork(1), то ваш тест не работает. Вы не должны обмениваться данными между различными испытаниями. Кроме того, половина JMH не работает должным образом с нулевыми форками, из-за чего выводит страшное сообщение. 27.09.2016
  • Я пытался использовать fork(1), но после этого orientdb заходит в тупик с этим кодом. В журнале я получаю только как - (прерывание*)(прерывание*)... 27.09.2016
  • Существуют ли какие-либо сценарии реальной жизни, в которых jmh используется на общих ресурсах, таких как база данных? Даже в orientdb есть тесты jmh для внутренних структур данных, но не для самой базы данных. 27.09.2016

  • 2

    db.drop(); не выполняется, поэтому вы получаете сообщение об ошибке: Cannot create new storage because it is not closed

    26.09.2016

    3

    Ответ Алексея помог мне понять, что использование fork в тесте было неправильным. Я публикую здесь рабочий код, чтобы не загромождать вопрос.

    public class OrientDbTest {
    
        @State(Scope.Benchmark)
        public static class TestState {
            private OObjectDatabaseTx db;
            private Person[] personList;
    
            @Setup(Level.Trial)
            public void setUp() throws IOException {
                System.out.println("started setup code");
                try {
                    personList = loadData();
                    deleteDir("/tmp/orientdb/");
                    db = new OObjectDatabaseTx("plocal:/tmp/orientdb/person");
                    if (db.exists()) {
                        db.open("admin", "admin");
                        db.drop();
                    }
                    db.create();
                    db.getEntityManager().registerEntityClass(Person.class);
                    db.getEntityManager().registerEntityClass(Address.class);
                    db.getEntityManager().registerEntityClass(PrivateData.class);
                } catch (Throwable e) {
                    System.out.println("error in creating db ");
                    e.printStackTrace();
                }
            }
    
            @TearDown(Level.Trial)
            public void cleanUp() {
                System.out.println("started cleanup code");
                if (db != null) {
                    ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
                    db.commit();
                    db.close();
                }
            }
    
            private void deleteDir(String dirName) {
                File file = new File(dirName);
                if (file.exists()) {
                    File[] files = file.listFiles();
                    if (files != null) {
                        for (File child : files) {
                            if (child.isDirectory()) {
                                deleteDir(child.getAbsolutePath());
                            } else {
                                child.delete();
                            }
                        }
                        file.delete();
                    } else {
                        file.delete();
                    }
                }
            }
    
            private Person[] loadData() throws IOException {
                InputStream inputStream = Thread.currentThread()
                        .getContextClassLoader().getResourceAsStream("data.json");
                ObjectMapper objectMapper = new ObjectMapper();
                return objectMapper.readValue(inputStream, Person[].class);
            }
        }
    
        @Benchmark
        @BenchmarkMode(Mode.AverageTime)
        @OutputTimeUnit(TimeUnit.MICROSECONDS)
        @Fork(0)
        public void benchmarkInsert(TestState state, Blackhole blackhole) {
            OObjectDatabaseTx db = state.db;
            Person[] personList = state.personList;
    
            if (db == null) {
                System.out.println("db null.. exiting");
                System.exit(0);
            }
    
            ODatabaseRecordThreadLocal.INSTANCE.set(db.getUnderlying());
            for (Person person : personList) {
                blackhole.consume(db.save(person));
            }
        }
    
    26.09.2016
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..