load_external.cpp
1 // Copyright (c) 2022-present The Bitcoin Core 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 // Use span-serialization to avoid writing the size first. 48 ss << std::span{benchmark::data::block413567}; 49 50 // Create the test file. 51 { 52 // "wb+" is "binary, O_RDWR | O_CREAT | O_TRUNC". 53 FILE* file{fsbridge::fopen(blkfile, "wb+")}; 54 // Make the test block file about 128 MB in length. 55 for (size_t i = 0; i < node::MAX_BLOCKFILE_SIZE / ss.size(); ++i) { 56 if (fwrite(ss.data(), 1, ss.size(), file) != ss.size()) { 57 throw std::runtime_error("write to test file failed\n"); 58 } 59 } 60 fclose(file); 61 } 62 63 std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent; 64 FlatFilePos pos; 65 bench.run([&] { 66 // "rb" is "binary, O_RDONLY", positioned to the start of the file. 67 // The file will be closed by LoadExternalBlockFile(). 68 AutoFile file{fsbridge::fopen(blkfile, "rb")}; 69 testing_setup->m_node.chainman->LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent); 70 }); 71 fs::remove(blkfile); 72 } 73 74 BENCHMARK(LoadExternalBlockFile);