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