BenchmarkReftable.java

  1. /*
  2.  * Copyright (C) 2017, Google Inc. and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.pgm.debug;

  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import static org.eclipse.jgit.lib.Constants.HEAD;
  13. import static org.eclipse.jgit.lib.Constants.MASTER;
  14. import static org.eclipse.jgit.lib.Constants.R_HEADS;
  15. import static org.eclipse.jgit.lib.Ref.Storage.NEW;
  16. import static org.eclipse.jgit.lib.Ref.Storage.PACKED;

  17. import java.io.BufferedReader;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.io.InputStreamReader;
  23. import java.util.ArrayList;
  24. import java.util.List;
  25. import java.util.stream.Collectors;

  26. import org.eclipse.jgit.internal.storage.file.FileReftableStack;
  27. import org.eclipse.jgit.internal.storage.io.BlockSource;
  28. import org.eclipse.jgit.internal.storage.reftable.RefCursor;
  29. import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
  30. import org.eclipse.jgit.lib.Config;
  31. import org.eclipse.jgit.lib.ObjectId;
  32. import org.eclipse.jgit.lib.ObjectIdRef;
  33. import org.eclipse.jgit.lib.Ref;
  34. import org.eclipse.jgit.lib.SymbolicRef;
  35. import org.eclipse.jgit.pgm.Command;
  36. import org.eclipse.jgit.pgm.TextBuiltin;
  37. import org.eclipse.jgit.util.RefList;
  38. import org.kohsuke.args4j.Argument;
  39. import org.kohsuke.args4j.Option;

  40. @Command
  41. class BenchmarkReftable extends TextBuiltin {
  42.     enum Test {
  43.         SCAN,
  44.         SEEK_COLD, SEEK_HOT,
  45.         BY_ID_COLD, BY_ID_HOT,
  46.         WRITE_STACK,
  47.         GET_REFS_EXCLUDING_REF
  48.     }

  49.     @Option(name = "--tries")
  50.     private int tries = 10;

  51.     @Option(name = "--test")
  52.     private Test test = Test.SCAN;

  53.     @Option(name = "--ref")
  54.     private String ref;

  55.     @Option(name = "--object-id")
  56.     private String objectId;

  57.     @Argument(index = 0)
  58.     private String lsRemotePath;

  59.     @Argument(index = 1)
  60.     private String reftablePath;

  61.     /** {@inheritDoc} */
  62.     @Override
  63.     protected void run() throws Exception {
  64.         switch (test) {
  65.         case SCAN:
  66.             scan();
  67.             break;

  68.         case SEEK_COLD:
  69.             seekCold(ref);
  70.             break;
  71.         case SEEK_HOT:
  72.             seekHot(ref);
  73.             break;

  74.         case BY_ID_COLD:
  75.             byIdCold(ObjectId.fromString(objectId));
  76.             break;
  77.         case BY_ID_HOT:
  78.             byIdHot(ObjectId.fromString(objectId));
  79.             break;
  80.         case WRITE_STACK:
  81.             writeStack();
  82.             break;
  83.         case GET_REFS_EXCLUDING_REF :
  84.             getRefsExcludingWithSeekPast(ref);
  85.             getRefsExcludingWithFilter(ref);
  86.             break;
  87.     }
  88.     }

  89.     private void printf(String fmt, Object... args) throws IOException {
  90.         errw.println(String.format(fmt, args));
  91.     }

  92.     @SuppressWarnings({ "nls", "boxing" })
  93.     private void writeStack() throws Exception {
  94.         File dir = new File(reftablePath);
  95.         File stackFile = new File(reftablePath + ".stack");

  96.         dir.mkdirs();

  97.         long start = System.currentTimeMillis();
  98.         try (FileReftableStack stack = new FileReftableStack(stackFile, dir,
  99.                 null, () -> new Config())) {

  100.             List<Ref> refs = readLsRemote().asList();
  101.             for (Ref r : refs) {
  102.                 final long j = stack.getMergedReftable().maxUpdateIndex() + 1;
  103.                 if (!stack.addReftable(w -> {
  104.                     w.setMaxUpdateIndex(j).setMinUpdateIndex(j).begin()
  105.                             .writeRef(r);
  106.                 })) {
  107.                     throw new IOException("should succeed");
  108.                 }
  109.             }
  110.             long dt = System.currentTimeMillis() - start;
  111.             printf("%12s %10d ms  avg %6d us/write", "reftable", dt,
  112.                     (dt * 1000) / refs.size());
  113.         }
  114.     }

  115.     @SuppressWarnings({ "nls", "boxing" })
  116.     private void scan() throws Exception {
  117.         long start, tot;

  118.         start = System.currentTimeMillis();
  119.         for (int i = 0; i < tries; i++) {
  120.             readLsRemote();
  121.         }
  122.         tot = System.currentTimeMillis() - start;
  123.         printf("%12s %10d ms  %6d ms/run", "packed-refs", tot, tot / tries);

  124.         start = System.currentTimeMillis();
  125.         for (int i = 0; i < tries; i++) {
  126.             try (FileInputStream in = new FileInputStream(reftablePath);
  127.                     BlockSource src = BlockSource.from(in);
  128.                     ReftableReader reader = new ReftableReader(src)) {
  129.                 try (RefCursor rc = reader.allRefs()) {
  130.                     while (rc.next()) {
  131.                         rc.getRef();
  132.                     }
  133.                 }
  134.             }
  135.         }
  136.         tot = System.currentTimeMillis() - start;
  137.         printf("%12s %10d ms  %6d ms/run", "reftable", tot, tot / tries);
  138.     }

  139.     private RefList<Ref> readLsRemote()
  140.             throws IOException, FileNotFoundException {
  141.         RefList.Builder<Ref> list = new RefList.Builder<>();
  142.         try (BufferedReader br = new BufferedReader(new InputStreamReader(
  143.                 new FileInputStream(lsRemotePath), UTF_8))) {
  144.             Ref last = null;
  145.             String line;
  146.             while ((line = br.readLine()) != null) {
  147.                 ObjectId id = ObjectId.fromString(line.substring(0, 40));
  148.                 String name = line.substring(41, line.length());
  149.                 if (last != null && name.endsWith("^{}")) { //$NON-NLS-1$
  150.                     last = new ObjectIdRef.PeeledTag(PACKED, last.getName(),
  151.                             last.getObjectId(), id);
  152.                     list.set(list.size() - 1, last);
  153.                     continue;
  154.                 }

  155.                 if (name.equals(HEAD)) {
  156.                     last = new SymbolicRef(name, new ObjectIdRef.Unpeeled(NEW,
  157.                             R_HEADS + MASTER, null));
  158.                 } else {
  159.                     last = new ObjectIdRef.PeeledNonTag(PACKED, name, id);
  160.                 }
  161.                 list.add(last);
  162.             }
  163.         }
  164.         list.sort();
  165.         return list.toRefList();
  166.     }

  167.     @SuppressWarnings({ "nls", "boxing" })
  168.     private void seekCold(String refName) throws Exception {
  169.         long start, tot;

  170.         int lsTries = Math.min(tries, 64);
  171.         start = System.nanoTime();
  172.         for (int i = 0; i < lsTries; i++) {
  173.             readLsRemote().get(refName);
  174.         }
  175.         tot = System.nanoTime() - start;
  176.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
  177.                 tot / 1000,
  178.                 (((double) tot) / lsTries) / 1000,
  179.                 lsTries);

  180.         start = System.nanoTime();
  181.         for (int i = 0; i < tries; i++) {
  182.             try (FileInputStream in = new FileInputStream(reftablePath);
  183.                     BlockSource src = BlockSource.from(in);
  184.                     ReftableReader reader = new ReftableReader(src)) {
  185.                 try (RefCursor rc = reader.seekRef(refName)) {
  186.                     while (rc.next()) {
  187.                         rc.getRef();
  188.                     }
  189.                 }
  190.             }
  191.         }
  192.         tot = System.nanoTime() - start;
  193.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
  194.                 tot / 1000,
  195.                 (((double) tot) / tries) / 1000,
  196.                 tries);
  197.     }

  198.     @SuppressWarnings({ "nls", "boxing" })
  199.     private void seekHot(String refName) throws Exception {
  200.         long start, tot;

  201.         int lsTries = Math.min(tries, 64);
  202.         start = System.nanoTime();
  203.         RefList<Ref> lsRemote = readLsRemote();
  204.         for (int i = 0; i < lsTries; i++) {
  205.             lsRemote.get(refName);
  206.         }
  207.         tot = System.nanoTime() - start;
  208.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
  209.                 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);

  210.         start = System.nanoTime();
  211.         try (FileInputStream in = new FileInputStream(reftablePath);
  212.                 BlockSource src = BlockSource.from(in);
  213.                 ReftableReader reader = new ReftableReader(src)) {
  214.             for (int i = 0; i < tries; i++) {
  215.                 try (RefCursor rc = reader.seekRef(refName)) {
  216.                     while (rc.next()) {
  217.                         rc.getRef();
  218.                     }
  219.                 }
  220.             }
  221.         }
  222.         tot = System.nanoTime() - start;
  223.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
  224.                 tot / 1000, (((double) tot) / tries) / 1000, tries);
  225.     }

  226.     @SuppressWarnings({ "nls", "boxing" })
  227.     private void byIdCold(ObjectId id) throws Exception {
  228.         long start, tot;

  229.         int lsTries = Math.min(tries, 64);
  230.         start = System.nanoTime();
  231.         for (int i = 0; i < lsTries; i++) {
  232.             for (Ref r : readLsRemote()) {
  233.                 if (id.equals(r.getObjectId())) {
  234.                     continue;
  235.                 }
  236.             }
  237.         }
  238.         tot = System.nanoTime() - start;
  239.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
  240.                 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);

  241.         start = System.nanoTime();
  242.         for (int i = 0; i < tries; i++) {
  243.             try (FileInputStream in = new FileInputStream(reftablePath);
  244.                     BlockSource src = BlockSource.from(in);
  245.                     ReftableReader reader = new ReftableReader(src)) {
  246.                 try (RefCursor rc = reader.byObjectId(id)) {
  247.                     while (rc.next()) {
  248.                         rc.getRef();
  249.                     }
  250.                 }
  251.             }
  252.         }
  253.         tot = System.nanoTime() - start;
  254.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
  255.                 tot / 1000, (((double) tot) / tries) / 1000, tries);
  256.     }

  257.     @SuppressWarnings({ "nls", "boxing" })
  258.     private void byIdHot(ObjectId id) throws Exception {
  259.         long start, tot;

  260.         int lsTries = Math.min(tries, 64);
  261.         start = System.nanoTime();
  262.         RefList<Ref> lsRemote = readLsRemote();
  263.         for (int i = 0; i < lsTries; i++) {
  264.             for (Ref r : lsRemote) {
  265.                 if (id.equals(r.getObjectId())) {
  266.                     continue;
  267.                 }
  268.             }
  269.         }
  270.         tot = System.nanoTime() - start;
  271.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
  272.                 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);

  273.         start = System.nanoTime();
  274.         try (FileInputStream in = new FileInputStream(reftablePath);
  275.                 BlockSource src = BlockSource.from(in);
  276.                 ReftableReader reader = new ReftableReader(src)) {
  277.             for (int i = 0; i < tries; i++) {
  278.                 try (RefCursor rc = reader.byObjectId(id)) {
  279.                     while (rc.next()) {
  280.                         rc.getRef();
  281.                     }
  282.                 }
  283.             }
  284.         }
  285.         tot = System.nanoTime() - start;
  286.         printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
  287.                 tot / 1000, (((double) tot) / tries) / 1000, tries);
  288.     }

  289.     @SuppressWarnings({"nls", "boxing"})
  290.     private void getRefsExcludingWithFilter(String prefix) throws Exception {
  291.         long startTime = System.nanoTime();
  292.         List<Ref> allRefs = new ArrayList<>();
  293.         try (FileInputStream in = new FileInputStream(reftablePath);
  294.                 BlockSource src = BlockSource.from(in);
  295.                 ReftableReader reader = new ReftableReader(src)) {
  296.             try (RefCursor rc = reader.allRefs()) {
  297.                 while (rc.next()) {
  298.                     allRefs.add(rc.getRef());
  299.                 }
  300.             }
  301.         }
  302.         int total = allRefs.size();
  303.         allRefs = allRefs.stream().filter(r -> r.getName().startsWith(prefix)).collect(Collectors.toList());
  304.         int notStartWithPrefix = allRefs.size();
  305.         int startWithPrefix = total - notStartWithPrefix;
  306.         long totalTime = System.nanoTime() - startTime;
  307.         printf("total time the action took using filter: %10d usec", totalTime / 1000);
  308.         printf("number of refs that start with prefix: %d", startWithPrefix);
  309.         printf("number of refs that don't start with prefix: %d", notStartWithPrefix);
  310.     }

  311.     @SuppressWarnings({"nls", "boxing"})
  312.     private void getRefsExcludingWithSeekPast(String prefix) throws Exception {
  313.         long start = System.nanoTime();
  314.         try (FileInputStream in = new FileInputStream(reftablePath);
  315.                 BlockSource src = BlockSource.from(in);
  316.                 ReftableReader reader = new ReftableReader(src)) {
  317.             try (RefCursor rc = reader.allRefs()) {
  318.                 while (rc.next()) {
  319.                     if (rc.getRef().getName().startsWith(prefix)) {
  320.                         break;
  321.                     }
  322.                 }
  323.                 rc.seekPastPrefix(prefix);
  324.                 while (rc.next()) {
  325.                     rc.getRef();
  326.                 }
  327.             }
  328.         }
  329.         long tot = System.nanoTime() - start;
  330.         printf("total time the action took using seek: %10d usec", tot / 1000);
  331.     }
  332. }