load_external.cpp raw

   1  // Copyright (c) 2022 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or https://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <bench/bench.h>
   6  #include <bench/data/block413567.raw.h>
   7  #include <chainparams.h>
   8  #include <flatfile.h>
   9  #include <node/blockstorage.h>
  10  #include <span.h>
  11  #include <streams.h>
  12  #include <test/util/setup_common.h>
  13  #include <uint256.h>
  14  #include <util/fs.h>
  15  #include <validation.h>
  16  
  17  #include <cstdint>
  18  #include <cstdio>
  19  #include <map>
  20  #include <memory>
  21  #include <stdexcept>
  22  #include <vector>
  23  
  24  /**
  25   * The LoadExternalBlockFile() function is used during -reindex and -loadblock.
  26   *
  27   * Create a test file that's similar to a datadir/blocks/blk?????.dat file,
  28   * It contains around 134 copies of the same block (typical size of real block files).
  29   * For each block in the file, LoadExternalBlockFile() won't find its parent,
  30   * and so will skip the block. (In the real system, it will re-read the block
  31   * from disk later when it encounters its parent.)
  32   *
  33   * This benchmark measures the performance of deserializing the block (or just
  34   * its header, beginning with PR 16981).
  35   */
  36  static void LoadExternalBlockFile(benchmark::Bench& bench)
  37  {
  38      const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
  39  
  40      // Create a single block as in the blocks files (magic bytes, block size,
  41      // block data) as a stream object.
  42      const fs::path blkfile{testing_setup.get()->m_path_root / "blk.dat"};
  43      DataStream ss{};
  44      auto params{testing_setup->m_node.chainman->GetParams()};
  45      ss << params.MessageStart();
  46      ss << static_cast<uint32_t>(benchmark::data::block413567.size());
  47      // We can't use the streaming serialization (ss << benchmark::data::block413567)
  48      // because that first writes a compact size.
  49      ss << Span{benchmark::data::block413567};
  50  
  51      // Create the test file.
  52      {
  53          // "wb+" is "binary, O_RDWR | O_CREAT | O_TRUNC".
  54          FILE* file{fsbridge::fopen(blkfile, "wb+")};
  55          // Make the test block file about 128 MB in length.
  56          for (size_t i = 0; i < node::MAX_BLOCKFILE_SIZE / ss.size(); ++i) {
  57              if (fwrite(ss.data(), 1, ss.size(), file) != ss.size()) {
  58                  throw std::runtime_error("write to test file failed\n");
  59              }
  60          }
  61          fclose(file);
  62      }
  63  
  64      std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
  65      FlatFilePos pos;
  66      bench.run([&] {
  67          // "rb" is "binary, O_RDONLY", positioned to the start of the file.
  68          // The file will be closed by LoadExternalBlockFile().
  69          AutoFile file{fsbridge::fopen(blkfile, "rb")};
  70          testing_setup->m_node.chainman->LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
  71      });
  72      fs::remove(blkfile);
  73  }
  74  
  75  BENCHMARK(LoadExternalBlockFile, benchmark::PriorityLevel::HIGH);
  76