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