code: /*
   * Copyright 2014-2020 chronicle.software
   *
   * http://chronicle.software
   *
   * 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 net.openhft.chronicle.map.perf;
  
  import net.openhft.chronicle.bytes.Byteable;
  import net.openhft.chronicle.bytes.BytesStore;
  import net.openhft.chronicle.core.Jvm;
  import net.openhft.chronicle.core.OS;
  import net.openhft.chronicle.core.io.IOTools;
  import net.openhft.chronicle.core.util.NanoSampler;
  import net.openhft.chronicle.jlbh.JLBH;
  import net.openhft.chronicle.jlbh.JLBHOptions;
  import net.openhft.chronicle.jlbh.JLBHTask;
  import net.openhft.chronicle.map.ChronicleMap;
  import net.openhft.chronicle.map.ChronicleMapBuilder;
  import net.openhft.chronicle.threads.NamedThreadFactory;
  import net.openhft.chronicle.values.Array;
  import net.openhft.chronicle.values.MaxUtf8Length;
  import net.openhft.chronicle.values.Values;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.Random;
  import java.util.concurrent.ArrayBlockingQueue;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.ThreadPoolExecutor;
  import java.util.concurrent.TimeUnit;
  
  /**
   * model name      : Intel(R) Core(TM) i7-10710U CPU @ 1.10GHz
   * -------------------------------- SUMMARY (end to end) -----------------------------------------------------------
   * Percentile   run1         run2         run3         run4         run5      % Variation
   * 50:             0.66         0.63         0.64         0.64         0.64         0.83
   * 90:             0.81         0.77         0.78         0.79         0.78         1.02
   * 99:             1.36         1.18         1.19         1.21         1.19         1.78
   * 99.7:           1.76         1.34         1.36         1.48         1.36         6.69
   * 99.9:           2.86         2.00         1.84         2.78         2.33        25.45
   * 99.97:         20.80        20.80        18.88        20.80        20.80         6.35
   * 99.99:         23.10        23.10        22.85        23.23        23.10         1.11
   * worst:       4276.22      2035.71      2465.79      2121.73      2068.48        12.35
   * -------------------------------------------------------------------------------------------------------------------
   */
  public class MapJLBHTest implements JLBHTask {
      private static final int KEYS = Integer.getInteger("keys", 10_000_000);
      private static final int WARM_UP_ITERATIONS = Math.max(100_000, KEYS / 2);
      private static final String PATH = System.getProperty("path", OS.TMP);
      private static final int THROUGHPUT = Integer.getInteger("throughput", 1_000_000);
      private static final int THREADS = 6;
      private int count = 0;
      private ChronicleMap<Long, IFacade0> map;
      private NanoSampler readSampler;
      private NanoSampler writeSampler;
      private NanoSampler e2eSampler;
      private File mapFile = new File(PATH, "map" + System.nanoTime() + ".cm3");
      private ThreadLocal<Worker> workerTL = ThreadLocal.withInitial(Worker::new);
      private ExecutorService service = new ThreadPoolExecutor(THREADS, THREADS,
              1L, TimeUnit.MINUTES,
              new ArrayBlockingQueue<>(THREADS * 4),
              new NamedThreadFactory("worker", true),
              new ThreadPoolExecutor.CallerRunsPolicy());
  
      public static void main(String[] args) {
          //Create the JLBH options you require for the benchmark
          JLBHOptions options = new JLBHOptions()
                  .warmUpIterations(WARM_UP_ITERATIONS)
                  .iterations(Math.max(10_000_000, KEYS))
                  .throughput(THROUGHPUT)
                  .runs(5)
                  .recordOSJitter(false)
                  .accountForCoordinatedOmission(true)
                  .jlbhTask(new MapJLBHTest());
          new JLBH(options).start();
      }
  
      @Override
      public void init(JLBH jlbh) {
          IOTools.deleteDirWithFiles(mapFile.getParent(), 2);
          mapFile.getParentFile().mkdirs();
          mapFile.deleteOnExit();
          readSampler = jlbh.addProbe("Read");
          writeSampler = jlbh.addProbe("Write");
          e2eSampler = jlbh;
  
          IFacade0 datum = Values.newNativeReference(IFacade0.class);
          Byteable byteable = (Byteable) datum;
          long capacity = byteable.maxSize();
          System.out.println("Data size: " + capacity);
          byteable.bytesStore(BytesStore.nativeStore(capacity), 0, capacity);
  
          try {
              final long entries = KEYS;
              map = ChronicleMapBuilder.of(Long.class, IFacade0.class)
                      .constantValueSizeBySample(datum)
                      .entries(entries)
                      .sparseFile(true)
                      .maxBloatFactor(1.2)
                      .actualSegments(32)
                      .createPersistedTo(mapFile);
          } catch (IOException ex) {
              throw Jvm.rethrow(ex);
          }
      }
  
      @Override
      public void run(long startTimeNS) {
          service.execute(() -> workerTL.get().run(startTimeNS));
      }
  
      @Override
      public void complete() {
          map.close();
      }
  
      interface IFacadeBase {
          short getValue0();
  
          void setValue0(short value);
  
          byte getValue1();
  
          void setValue1(byte value);
  
          byte getValue2();
  
          void setValue2(byte value);
  
          int getValue3();
  
          void setValue3(int value);
  
          short getValue4();
  
          void setValue4(short value);
  
          boolean getValue5();
  
          void setValue5(boolean value);
  
          boolean getValue6();
  
          void setValue6(boolean value);
  
          short getValue7();
  
          void setValue7(short value);
  
          short getValue8();
  
          void setValue8(short value);
  
          long getValue9();
  
          void setValue9(long value);
  
          long getValue10();
  
          void setValue10(long value);
  
          long getValue11();
  
          void setValue11(long value);
  
          long getValue12();
  
          void setValue12(long value);
  
          long getValue13();
  
          void setValue13(long value);
  
          long getValue14();
  
          void setValue14(long value);
  
          long getValue15();
  
          void setValue15(long value);
  
          short getValue16();
  
          void setValue16(short value);
  
          short getValue17();
  
          void setValue17(short value);
  
          short getValue18();
  
          void setValue18(short value);
      }
  
      //IFacade (at the bottom) is the façade we need tested
  
      interface IFacadeSon extends IFacadeBase {
          long getValue19();
  
          void setValue19(long value);
  
          int getValue20();
  
          void setValue20(int value);
  
          int getValue21();
  
          void setValue21(int value);
  
          double getValue22();
  
          void setValue22(double value);
  
          String getValue23();
  
          void setValue23(@MaxUtf8Length(10) String value);
  
          int getValue24();
  
          void setValue24(int value);
  
          double getValue25();
  
          void setValue25(double value);
  
          byte getValue26();
  
          void setValue26(byte value);
  
          double getValue27();
  
          void setValue27(double value);
  
          double getValue28();
  
          void setValue28(double value);
      }
  
      interface IFacadeDaughter extends IFacadeBase {
  
          double getValue29();
  
          void setValue29(double value);
  
          double getValue30();
  
          void setValue30(double value);
  
          double getValue31();
  
          void setValue31(double value);
  
          double getValue32();
  
          void setValue32(double value);
  
          long getValue33();
  
          void setValue33(long value);
  
          String getValue34();
  
          void setValue34(@MaxUtf8Length(11) String value);
  
          int getValue35();
  
          void setValue35(int value);
  
          String getValue36();
  
          void setValue36(@MaxUtf8Length(11) String value);
  
          int getValue37();
  
          void setValue37(int value);
  
          long getValue38();
  
          void setValue38(long value);
  
          short getValue39();
  
          void setValue39(short value);
  
          long getValue40();
  
          void setValue40(long value);
  
          String getValue41();
  
          void setValue41(@MaxUtf8Length(43) String value);
  
          long getValue42();
  
          void setValue42(long value);
  
          long getValue43();
  
          void setValue43(long value);
  
          long getValue44();
  
          void setValue44(long value);
  
          long getValue45();
  
          void setValue45(long value);
  
          long getValue46();
  
          void setValue46(long value);
  
          byte getValue47();
  
          void setValue47(byte value);
  
          byte getValue48();
  
          void setValue48(byte value);
  
          double getValue49();
  
          void setValue49(double value);
  
          double getValue50();
  
          void setValue50(double value);
  
          double getValue51();
  
          void setValue51(double value);
  
          byte getValue52();
  
          void setValue52(byte value);
  
          byte getValue53();
  
          void setValue53(byte value);
  
          byte getValue54();
  
          void setValue54(byte value);
  
          byte getValue55();
  
          void setValue55(byte value);
  
          byte getValue56();
  
          void setValue56(byte value);
  
          long getValue57();
  
          void setValue57(long value);
  
          byte getValue58();
  
          void setValue58(byte value);
  
          double getValue59();
  
          void setValue59(double value);
  
          double getValue60();
  
          void setValue60(double value);
  
          double getValue61();
  
          void setValue61(double value);
  
          double getValue62();
  
          void setValue62(double value);
  
          double getValue63();
  
          void setValue63(double value);
  
          long getValue64();
  
          void setValue64(long value);
  
          long getValue65();
  
          void setValue65(long value);
  
          double getValue66();
  
          void setValue66(double value);
  
          double getValue67();
  
          void setValue67(double value);
  
          short getValue68();
  
          void setValue68(short value);
  
          String getValue69();
  
          void setValue69(@MaxUtf8Length(101) String value);
  
          String getValue70();
  
          void setValue70(@MaxUtf8Length(17) String value);
  
          boolean getValue71();
  
          void setValue71(boolean value);
  
          boolean getValue72();
  
          void setValue72(boolean value);
  
          String getValue73();
  
          void setValue73(@MaxUtf8Length(11) String value);
  
          String getValue74();
  
          void setValue74(@MaxUtf8Length(9) String value);
  
          byte getValue75();
  
          void setValue75(byte value);
  
          int getValue76();
  
          void setValue76(int value);
  
          int getValue77();
  
          void setValue77(int value);
  
          String getValue78();
  
          void setValue78(@MaxUtf8Length(3) String value);
  
          int getValue79();
  
          void setValue79(int value);
  
          double getValue80();
  
          void setValue80(double value);
  
          byte getValue81();
  
          void setValue81(byte value);
  
          byte getValue82();
  
          void setValue82(byte value);
  
          byte getValue83();
  
          void setValue83(byte value);
  
          byte getValue84();
  
          void setValue84(byte value);
  
          byte getValue85();
  
          void setValue85(byte value);
  
          byte getValue86();
  
          void setValue86(byte value);
  
          byte getValue87();
  
          void setValue87(byte value);
  
          byte getValue88();
  
          void setValue88(byte value);
  
          int getValue89();
  
          void setValue89(int value);
  
          int getValue90();
  
          void setValue90(int value);
  
          int getValue91();
  
          void setValue91(int value);
  
          int getValue92();
  
          void setValue92(int value);
  
          int getValue93();
  
          void setValue93(int value);
  
          int getValue94();
  
          void setValue94(int value);
  
          int getValue95();
  
          void setValue95(int value);
  
          int getValue96();
  
          void setValue96(int value);
  
          int getValue97();
  
          void setValue97(int value);
  
          int getValue98();
  
          void setValue98(int value);
  
          int getValue99();
  
          void setValue99(int value);
      }
  
      interface IFacade0 extends IFacadeBase {
          @Array(length = 3)
          void setSonAt(int idx, IFacadeSon son);
  
          IFacadeSon getSonAt(int idx);
      }
  
      interface IFacade extends IFacadeBase {
          @Array(length = 3)
          void setDaughterAt(int idx, IFacadeDaughter daughter);
  
          IFacadeDaughter getDaughterAt(int idx);
  
          @Array(length = 3)
          void setSonAt(int idx, IFacadeSon son);
  
          IFacadeSon getSonAt(int idx);
      }
  
      class Worker {
          private IFacade0 datum = Values.newNativeReference(IFacade0.class);
          private IFacade0 datum2 = Values.newNativeReference(IFacade0.class);
          private Random random = new Random();
  
          public Worker() {
              Byteable byteable = (Byteable) datum;
              long capacity = byteable.maxSize();
              byteable.bytesStore(BytesStore.nativeStore(capacity), 0, capacity);
          }
  
          public void run(long startTimeNS) {
              long runNo = generateKey();
              datum.setValue10(startTimeNS);
              long startWrite = System.nanoTime();
              map.put(runNo, datum);
              long endWrite = System.nanoTime();
              long writeTime = endWrite - startWrite;
  
              long runNo2 = generateKey();
              long startRead = System.nanoTime();
              IFacade0 dataRead = map.getUsing(runNo2, datum2);
              long endRead = System.nanoTime();
  
              synchronized (e2eSampler) {
                  writeSampler.sampleNanos(writeTime);
                  readSampler.sampleNanos(endRead - startRead);
                  e2eSampler.sampleNanos(endRead - startTimeNS);
              }
          }
  
          private long generateKey() {
              // warmup
              if (count < WARM_UP_ITERATIONS)
                  return count++;
              // logarithmic distribution
              return (long) Math.pow(KEYS, random.nextDouble());
          }
      }
  }
  