2016-09-25 79 views
2

我正在嘗試爲嵌入的東方分貝設置一個jmh測試。測試套件如下:如何爲嵌入的orientdb設置jmh測試?

@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插件。這裏是的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) 

我在做什麼錯在這裏設置?

編輯

閱讀this後,我修改了代碼如下:

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... 
+0

這看起來不像JMH故障。查看創建/清除過程是否正常工作:例如將它們放入'main'中,並嘗試連續運行create-cleanup-create-cleanup。我不認爲'deleteDir'你實際上刪除了所有文件夾(例如在刪除文件夾內容之後)。 –

+0

你有沒有使用相同的東方實例的其他進程? –

+0

不是。不是來自測試實例外部。但我懷疑是另一個線程試圖創建它時,其他jmh線程持有數據庫。 –

回答

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) 
... 

b)中爲@State(Benchmark)@Setup方法應該只執行一次。但是,由於bug in JMH,如果第一個線程失敗並出現上述異常,那麼其他線程也會嘗試輸入@Setup,然後他們會嘗試打開數據庫,但失敗,因爲它已經打開?

事實上,即使在原始文章中,失敗(a)也是可見的,並且從多個進入@Setup的線程報告什麼異常取決於運氣如何(這在JMH 1.14.1中變得更好)。如果你設置threads = 1,它可靠地失敗,並有適當的異常。另外,setUp()中的清理路徑與tearDown()看起來不一致,這可以解釋爲什麼重新輸入的線程無法打開數據庫。底線:在進行多線程測試之前,請嘗試單線程測試。

+0

感謝您的評論。使用叉是罪魁禍首。我在回答中發佈了工作代碼 –

+0

等等,不!如果你的測試使用'fork(0)',但不使用'fork(1)',那麼你的測試就會中斷。你不應該在不同的試驗之間共享數據。此外,JMH的一半不能正常使用零叉,因此它會打印一條可怕的消息。 –

+0

我用fork(1)嘗試過,但之後orientdb進入這種代碼的某種類型的死鎖。在日誌中,我只能得到像 - (中斷*)(中斷*)... –

0

db.drop(); ISN沒有執行,所以你得到錯誤:Cannot create new storage because it is not closed

0

阿列克謝的回答幫助我弄清楚,在測試中使用分叉是錯誤的。我在此發佈工作代碼以避免問題更加混亂。

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)); 
     } 
    }