bench: add benchmark for GetMappedAS() #35285

pull 0xB10C wants to merge 1 commits into bitcoin:master from 0xB10C:2026-05-asmap-lookup-bench changing 2 files +165 −0
  1. 0xB10C commented at 5:19 PM on May 13, 2026: contributor

    With #28792 merged, we can use the embedded ASMap file to benchmark the IP -> ASN lookups. Before, this would have been cumbersome as it required having a real, external ASMap file. We want to benchmark against a real file, as a smaller test file has significantly faster lookups.

    The benchmarks cover individual IP address lookups of mapped and unmapped IPv4 and IPv6 addresses along with a multi-IP lookup. For the IPs we assume to be mapped, we assert that they are mapped. Updating the embedded ASMap file might change the benchmark results slightly as some lookups will be a bit faster and others slower.

    $ ./build/bin/bench_bitcoin --filter=ASMapGetMappedAS.* -min-time=5000
    
        |               ns/op |                op/s |    err% |     total | benchmark
        |--------------------:|--------------------:|--------:|----------:|:----------
        |              460.41 |        2,171,994.61 |    0.2% |      5.48 | `ASMapGetMappedASCloudflarev4`
        |              356.96 |        2,801,460.45 |    0.0% |      5.33 | `ASMapGetMappedASCloudflarev6`
        |              476.58 |        2,098,304.01 |    0.1% |      5.51 | `ASMapGetMappedASGooglev4`
        |              359.17 |        2,784,224.15 |    0.0% |      5.33 | `ASMapGetMappedASGooglev6`
        |              398.82 |        2,507,410.35 |    0.1% |      5.50 | `ASMapGetMappedASMulti`
        |              346.11 |        2,889,237.31 |    0.3% |      5.32 | `ASMapGetMappedASQuad9v4`
        |              274.21 |        3,646,832.70 |    0.1% |      5.50 | `ASMapGetMappedASQuad9v6`
        |                5.32 |      187,875,440.96 |    0.1% |      5.50 | `ASMapGetMappedASUnmappedv4`
        |               65.19 |       15,339,680.04 |    0.1% |      5.51 | `ASMapGetMappedASUnmappedv6`
    

    LLM disclosure: while I wrote the initial benchmarks, I had a LLM review it and point out style nits and typos to me.

  2. DrahtBot added the label Tests on May 13, 2026
  3. DrahtBot commented at 5:20 PM on May 13, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35285.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK l0rinc, fjahr, sipa
    Stale ACK sedited, jurraca

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. in src/bench/asmap.cpp:43 in 4980824bf9
      38 | +    });
      39 | +}
      40 | +
      41 | +static void AsMapGetMappedASQuad9v4(benchmark::Bench& bench)
      42 | +{
      43 | +    std::vector<CNetAddr> addrs{LookupHost("9.9.9.9", false).value()};
    


    sedited commented at 9:08 AM on May 14, 2026:

    How does doing these lookups have an impact on #31349?


    0xB10C commented at 9:52 AM on May 14, 2026:

    My understanding is that this primarly maps from String to CNetAddr and there's no lookup for IPs. We're also setting fAllowLookup = false.

    This is used in e.g. https://github.com/bitcoin/bitcoin/blob/9961229360cbf34ab114b831341e7760a58a4edd/src/bench/addrman.cpp#L130 and various unit and fuzz tests already.


    vasild commented at 9:45 AM on May 15, 2026:

    Yeah, fAllowLookup = false rulez


    l0rinc commented at 10:21 AM on May 15, 2026:

    We should probably annotate the parameter with fAllowLookup to clarify that, see #35285 (review)

  5. sedited commented at 9:10 AM on May 14, 2026: contributor

    Concept ACK

  6. sedited requested review from jurraca on May 14, 2026
  7. sedited requested review from fjahr on May 14, 2026
  8. sedited approved
  9. sedited commented at 10:00 AM on May 14, 2026: contributor

    ACK 4980824bf96681cd2c5a2a93c70d83276d3e2690

  10. in src/bench/asmap.cpp:1 in 4980824bf9
       0 | @@ -0,0 +1,167 @@
       1 | +// Copyright (c) 2026-present The Bitcoin Core developers
    


    fjahr commented at 2:17 PM on May 14, 2026:

    nit: Lately we've converged on omitting the year entirely

    // Copyright (c) The Bitcoin Core developers
    

    0xB10C commented at 12:16 PM on May 15, 2026:

    Done.

  11. in src/bench/asmap.cpp:15 in 4980824bf9
      10 | +#include <node/data/ip_asn.dat.h>
      11 | +#include <util/asmap.h>
      12 | +
      13 | +// GetMappedAS benchmarks cover individual IP lookups and a multi-IP lookup.
      14 | +// For lookups, the embedded ASMap file is used, which might change over
      15 | +// time. To avoid looking up unmapped IPs in benchmarks, the individual IPs
    


    fjahr commented at 2:24 PM on May 14, 2026:

    nit: The check functionality makes this sentence kind of redundant because it prevents running benchmarks on unmapped IPs as it's done currently, right? Except the ones were it's explicitly done of course.


    0xB10C commented at 12:16 PM on May 15, 2026:

    Dropped the big comment and split it up to be closer to the check and the IP list for the multi benchmark.

  12. jurraca commented at 2:29 PM on May 14, 2026: contributor

    ACK 4980824

    Approach makes sense, and choices for well known IP networks shouldn't be an issue. Tested with and without --min-time=5000, and noting that I consistently get "unstable" (just over 5% usually) for AsMapGetMappedASUnmappedv4 when not using --min-time.

  13. in src/bench/CMakeLists.txt:77 in 4980824bf9 outdated
      70 | @@ -70,6 +71,10 @@ target_link_libraries(bench_bitcoin
      71 |    Boost::headers
      72 |  )
      73 |  
      74 | +if(WITH_EMBEDDED_ASMAP)
      75 | +  target_compile_definitions(bench_bitcoin PRIVATE ENABLE_EMBEDDED_ASMAP=1)
      76 | +endif()
      77 | +
    


    fjahr commented at 2:40 PM on May 14, 2026:

    nit: This would be a bit cleaner solution because you could get rid of the #ifdef wrapper in asmap.cpp and if it is disabled the file is just ignored rather than creating an empty compile unit, I think (untested).

    if(WITH_EMBEDDED_ASMAP)
      target_sources(bench_bitcoin PRIVATE asmap.cpp)
    endif()
    
  14. in src/bench/asmap.cpp:41 in 4980824bf9
      36 | +            ankerl::nanobench::doNotOptimizeAway(netgroupman.GetMappedAS(addr));
      37 | +        }
      38 | +    });
      39 | +}
      40 | +
      41 | +static void AsMapGetMappedASQuad9v4(benchmark::Bench& bench)
    


    fjahr commented at 2:50 PM on May 14, 2026:

    micro-nit: I have long given up on getting people to agree on a uniform capitalization of ASMap/ASmap/AsMap/Asmap but having As and AS present in the same function name still makes me shiver a bit 😉

  15. fjahr commented at 2:53 PM on May 14, 2026: contributor

    Code review ACK 4980824bf96681cd2c5a2a93c70d83276d3e2690

    Great to have a benchmark for this, thanks for adding them. Happy to re-review quickly if you want to address some of my nits.

  16. in src/bench/asmap.cpp:167 in 4980824bf9
     162 | +BENCHMARK(AsMapGetMappedASGooglev6);
     163 | +BENCHMARK(AsMapGetMappedASUnmappedv4);
     164 | +BENCHMARK(AsMapGetMappedASUnmappedv6);
     165 | +BENCHMARK(AsMapGetMappedASMulti);
     166 | +
     167 | +#endif
    


    l0rinc commented at 3:03 PM on May 14, 2026:
    #endif // ENABLE_EMBEDDED_ASMAP
    
  17. in src/bench/asmap.cpp:37 in 4980824bf9
      32 | +    }
      33 | +
      34 | +    bench.run([&] {
      35 | +        for (const CNetAddr& addr : addrs) {
      36 | +            ankerl::nanobench::doNotOptimizeAway(netgroupman.GetMappedAS(addr));
      37 | +        }
    


    l0rinc commented at 3:08 PM on May 14, 2026:

    Instead of doing the work twice (which basically constitutes a warmup run), we could do the validation internally and avoid the nanobench optimization gate:

        bench.run([&] {
            for (const CNetAddr& addr : addrs) {
                const auto mapped_as{netgroupman.GetMappedAS(addr)};
                assert((mapped_as > 0) == check);
            }
        });
    

    0xB10C commented at 9:59 AM on May 15, 2026:

    I assume (and haven't checked) the assert to be quite quick as it's likely only a few instructions, but to be direct and clear about what we want to benchmark, I moved the check out of the benchmark run. We only care about the GetMappedAS performance here.


    l0rinc commented at 10:18 AM on May 15, 2026:

    That would introduce a warmup run (which could theoretically skew the results), and it's needlessly verbose. It seems a lot simpler to me to just do the assertions inline, like we do in many other benchmarks.


    sipa commented at 12:12 PM on May 15, 2026:

    I don't think the effect of a warmup run is a problem. The same is achieved by just running the benchmark for longer, as the relative impact of warmup will reduce. That's just the nature of micro-benchmarks like this: you're effectively always benchmarking the warm-cache regime.

    That said, I agree that separating the loop is overly verbose, and the cost of putting it in the main benchmark loop should be negligible.


    0xB10C commented at 12:18 PM on May 15, 2026:

    Alright. Checking inside the benchmark now.

  18. in src/bench/asmap.cpp:22 in 4980824bf9
      17 | +// soon. The IPs for the multi-lookup benchmark are randomly sampled from
      18 | +// different ASNs to ensure a mix of lookup times. Some of these could be
      19 | +// unmapped when upgrading the embedded ASMap file, which will cause the
      20 | +// benchmarks to assert and the IPs will need to be updated or changed.
      21 | +
      22 | +static void BenchGetMappedAS(benchmark::Bench& bench, const std::vector<CNetAddr>& addrs, bool check)
    


    l0rinc commented at 3:09 PM on May 14, 2026:

    We could accept an std::span<const CNetAddr> instead and let the single-address benchmarks use fixed-size arrays while the multi-address benchmark can still pass its vector:

    static void BenchGetMappedAS(benchmark::Bench& bench, std::span<const CNetAddr> addrs, bool check)
    
  19. in src/bench/asmap.cpp:152 in 4980824bf9
     147 | +
     148 | +    std::vector<CNetAddr> addrs;
     149 | +    addrs.reserve(ips.size());
     150 | +    for (const auto& ip : ips) {
     151 | +        addrs.emplace_back(LookupHost(ip, false).value());
     152 | +    }
    


    l0rinc commented at 3:13 PM on May 14, 2026:

    To avoid introducing a bias by grouping similar values (which may be closeby) we could shuffle the addresses (and maybe sort the raw strings in the source by IPv4 first, v6 next):

    FastRandomContext rng{/*fDeterministic=*/true};
    std::ranges::shuffle(addrs, rng);
    

    If we used the above span and LookupAddr suggestions this would simply become:

        std::array addrs{
            LookupAddr("5.8.10.1"),
            LookupAddr("14.53.20.1"),
            LookupAddr("34.86.160.1"),
            LookupAddr("67.68.205.1"),
            LookupAddr("68.163.58.1"),
            LookupAddr("69.138.189.1"),
            LookupAddr("72.211.58.1"),
            LookupAddr("73.124.158.1"),
            LookupAddr("77.179.43.1"),
            LookupAddr("80.79.125.1"),
            LookupAddr("81.217.170.1"),
            LookupAddr("82.216.149.1"),
            LookupAddr("84.52.201.1"),
            LookupAddr("87.184.174.1"),
            LookupAddr("90.221.151.1"),
            LookupAddr("95.31.136.1"),
            LookupAddr("99.234.174.1"),
            LookupAddr("105.98.199.1"),
            LookupAddr("146.190.174.1"),
            LookupAddr("154.16.157.1"),
            LookupAddr("172.81.183.1"),
            LookupAddr("173.24.74.1"),
            LookupAddr("195.99.226.1"),
            LookupAddr("213.197.14.1"),
            LookupAddr("220.255.248.1"),
        
            LookupAddr("2001:67c:e60:c0c::1"),
            LookupAddr("2001:99a:213:27f0::1"),
            LookupAddr("2001:9e8:894b:be00::1"),
            LookupAddr("2001:16a2:c0b0:58b7::1"),
            LookupAddr("2406:2d40:1ebc:3508::1"),
            LookupAddr("2600:1015:a020:1e00::1"),
            LookupAddr("2600:1700:4228:a800::1"),
            LookupAddr("2601:cd:ce01:9610::1"),
            LookupAddr("2601:603:5000:3309::1"),
            LookupAddr("2603:800c:25f0:8350::1"),
            LookupAddr("2604:3d09:f89:d100::1"),
            LookupAddr("2607:fb90:236f:821f::1"),
            LookupAddr("2800:2331:5440:ba3::1"),
            LookupAddr("2a00:16e0:1012:c108::1"),
            LookupAddr("2a00:23c6:9d44:7801::1"),
            LookupAddr("2a00:79c0:609:4900::1"),
            LookupAddr("2a01:4f8:13a:1f8d::1"),
            LookupAddr("2a01:e0a:8a3:ab90::1"),
            LookupAddr("2a02:810b:449e:c900::1"),
            LookupAddr("2a02:8308:20d:e800::1"),
            LookupAddr("2a0a:ef40:331:4401::1"),
            LookupAddr("2a0c:5a86:a002:e700::1"),
            LookupAddr("2a10:3781:1d7:1::1"),
            LookupAddr("2a12:26c0:3303:a100::1"),
            LookupAddr("2a12:a800:2:1::1"),
        };
    };
    FastRandomContext rng{/*fDeterministic=*/true};
    std::ranges::shuffle(addrs, rng);
    
  20. in src/bench/asmap.cpp:49 in 4980824bf9
      44 | +    BenchGetMappedAS(bench, addrs, /*check=*/true);
      45 | +}
      46 | +
      47 | +static void AsMapGetMappedASQuad9v6(benchmark::Bench& bench)
      48 | +{
      49 | +    std::vector<CNetAddr> addrs{LookupHost("2620:fe::fe", false).value()};
    


    l0rinc commented at 3:15 PM on May 14, 2026:

    We could extract a helper for this to centralize the lookups:

    static CNetAddr LookupAddr(const std::string& address) { return LookupHost(address, /*fAllowLookup=*/false).value(); }
    
  21. in src/bench/asmap.cpp:165 in 4980824bf9
     160 | +BENCHMARK(AsMapGetMappedASCloudflarev6);
     161 | +BENCHMARK(AsMapGetMappedASGooglev4);
     162 | +BENCHMARK(AsMapGetMappedASGooglev6);
     163 | +BENCHMARK(AsMapGetMappedASUnmappedv4);
     164 | +BENCHMARK(AsMapGetMappedASUnmappedv6);
     165 | +BENCHMARK(AsMapGetMappedASMulti);
    


    l0rinc commented at 3:30 PM on May 14, 2026:

    We don't necessarily have to define each of these separately, we could simply iterate over the categories and create the benchmarks:

    const std::array<std::tuple<std::string, std::string>, 8> lookup_cases{{
        {"Quad9v4", "9.9.9.9"},
        {"Quad9v6", "2620:fe::fe"},
        {"Cloudflarev4", "1.1.1.1"},
        {"Cloudflarev6", "2606:4700:4700::1111"},
        {"Googlev4", "8.8.8.8"},
        {"Googlev6", "2001:4860:4860::8888"},
        {"Unmappedv4", "203.0.113.0"}, // Reserved as per RFC 5737 (unmapped)
        {"Unmappedv6", "3fff::1"}, // Reserved as per RFC 9637 (unmapped)
    }};
    
    for (const auto& [name_suffix, address] : lookup_cases) {
        const bool check{name_suffix.find("Unmapped") == std::string::npos}; // Detect mapped/unmapped drift.
        BenchGetMappedAS(bench, name_suffix, LookupAddr(address), check);
    }
    

    with:

    static void BenchGetMappedAS(benchmark::Bench& bench, const std::string& name_suffix, std::span<const CNetAddr> addrs, bool check)
    {
        std::span<const std::byte> asmap{node::data::ip_asn};
        assert(!asmap.empty() && CheckStandardAsmap(asmap));
        auto netgroupman{NetGroupManager::WithEmbeddedAsmap(asmap)};
    
        bench.name("AsMapGetMappedAS" + name_suffix).run([&] {
            for (auto& addr : addrs) {
                const auto mapped_as{netgroupman.GetMappedAS(addr)};
                assert((mapped_as > 0) == check);
            }
        });
    }
    

    0xB10C commented at 12:25 PM on May 15, 2026:

    I slightly favor the individual BENCHMARK()'s. This allows grepping for e.g. ASMapGetMappedASMulti if it starts to fail. I checked a few other files in src/bench/ and it seemed that we mostly have individual ones.


    l0rinc commented at 1:22 PM on May 15, 2026:

    There are multiple flavors, some are just naming (https://github.com/bitcoin/bitcoin/blob/ecc9a84f854e5b77dfc8876cf7c9b8d0f3de89d0/src/bench/cluster_linearize.cpp#L57) others have generator templates https://github.com/bitcoin/bitcoin/blob/2529f255554be31582797594d299fb74987bc0df/src/bench/prevector.cpp#L114 and others are just listing every instance. I have a slight preference for deduplication (grepping is trivial in both cases, especially if we don't extract their common prefix), but it's not blocking of course.

  22. in src/bench/asmap.cpp:34 in 4980824bf9
      29 | +        for (const CNetAddr& addr : addrs) {
      30 | +            assert(netgroupman.GetMappedAS(addr) > 0);
      31 | +        }
      32 | +    }
      33 | +
      34 | +    bench.run([&] {
    


    l0rinc commented at 3:36 PM on May 14, 2026:

    Since we're iterating we might as well provide an averaging so that the results are more uniform (e.g. the multi isn't skewed):

    bench.batch(addrs.size()).run([&] {
    

    0xB10C commented at 10:16 AM on May 15, 2026:

    Nice, ty. I wasn't aware of .batch() and agree that this is what we want to use here.


    sipa commented at 12:14 PM on May 15, 2026:

    This does not appear to be resolved.

    EDIT: now it is


    0xB10C commented at 12:21 PM on May 15, 2026:

    Sorry, didn't yet push before marking it resolved.

  23. l0rinc changes_requested
  24. l0rinc commented at 3:46 PM on May 14, 2026: contributor

    Concept ACK.

    Started leaving suggestions one by one while adjusting locally to explain my suggestions, but it's probably easier to provide the end-result to simplify the evaluation:

    // Copyright (c) The Bitcoin Core developers
    // Distributed under the MIT software license, see the accompanying
    // file COPYING or http://www.opensource.org/licenses/mit-license.php.
    
    #ifdef ENABLE_EMBEDDED_ASMAP
    
    #include <util/asmap.h>
    
    #include <bench/bench.h>
    #include <netbase.h>
    #include <netgroup.h>
    #include <node/data/ip_asn.dat.h>
    #include <random.h>
    
    #include <algorithm>
    #include <array>
    #include <cassert>
    #include <span>
    #include <string>
    #include <tuple>
    
    static void BenchGetMappedAS(benchmark::Bench& bench, const std::string& name_suffix, std::span<const CNetAddr> addrs, bool check)
    {
        std::span asmap{node::data::ip_asn};
        assert(!asmap.empty() && CheckStandardAsmap(asmap));
        auto netgroupman{NetGroupManager::WithEmbeddedAsmap(asmap)};
    
        bench.name("AsMapGetMappedAS" + name_suffix).batch(addrs.size()).run([&] {
            for (auto& addr : addrs) {
                auto mapped_as{netgroupman.GetMappedAS(addr)};
                assert((mapped_as > 0) == check);
            }
        });
    }
    
    static CNetAddr LookupAddr(const std::string& address) { return LookupHost(address, /*fAllowLookup=*/false).value(); }
    
    static void AsMapGetMappedAS(benchmark::Bench& bench)
    {
        const std::array<std::tuple<std::string, std::string>, 8> lookup_cases{{
            {"Quad9v4", "9.9.9.9"},
            {"Quad9v6", "2620:fe::fe"},
            {"Cloudflarev4", "1.1.1.1"},
            {"Cloudflarev6", "2606:4700:4700::1111"},
            {"Googlev4", "8.8.8.8"},
            {"Googlev6", "2001:4860:4860::8888"},
            {"Unmappedv4", "203.0.113.0"}, // Reserved as per RFC 5737 (unmapped)
            {"Unmappedv6", "3fff::1"}, // Reserved as per RFC 9637 (unmapped)
        }};
    
        for (auto& [name_suffix, address] : lookup_cases) {
            bool check{name_suffix.find("Unmapped") == std::string::npos}; // Detect mapped/unmapped drift.
            BenchGetMappedAS(bench, name_suffix, std::array{LookupAddr(address)}, check);
        }
    
        // A list of 25 IPv4 and 25 IPv6 addresses randomly sampled across 50 ASNs.
        // These have been masked to /24 and /64 respectively.
        std::array addrs{
            LookupAddr("5.8.10.1"),
            LookupAddr("14.53.20.1"),
            LookupAddr("34.86.160.1"),
            LookupAddr("67.68.205.1"),
            LookupAddr("68.163.58.1"),
            LookupAddr("69.138.189.1"),
            LookupAddr("72.211.58.1"),
            LookupAddr("73.124.158.1"),
            LookupAddr("77.179.43.1"),
            LookupAddr("80.79.125.1"),
            LookupAddr("81.217.170.1"),
            LookupAddr("82.216.149.1"),
            LookupAddr("84.52.201.1"),
            LookupAddr("87.184.174.1"),
            LookupAddr("90.221.151.1"),
            LookupAddr("95.31.136.1"),
            LookupAddr("99.234.174.1"),
            LookupAddr("105.98.199.1"),
            LookupAddr("146.190.174.1"),
            LookupAddr("154.16.157.1"),
            LookupAddr("172.81.183.1"),
            LookupAddr("173.24.74.1"),
            LookupAddr("195.99.226.1"),
            LookupAddr("213.197.14.1"),
            LookupAddr("220.255.248.1"),
    
            LookupAddr("2001:67c:e60:c0c::1"),
            LookupAddr("2001:99a:213:27f0::1"),
            LookupAddr("2001:9e8:894b:be00::1"),
            LookupAddr("2001:16a2:c0b0:58b7::1"),
            LookupAddr("2406:2d40:1ebc:3508::1"),
            LookupAddr("2600:1015:a020:1e00::1"),
            LookupAddr("2600:1700:4228:a800::1"),
            LookupAddr("2601:cd:ce01:9610::1"),
            LookupAddr("2601:603:5000:3309::1"),
            LookupAddr("2603:800c:25f0:8350::1"),
            LookupAddr("2604:3d09:f89:d100::1"),
            LookupAddr("2607:fb90:236f:821f::1"),
            LookupAddr("2800:2331:5440:ba3::1"),
            LookupAddr("2a00:16e0:1012:c108::1"),
            LookupAddr("2a00:23c6:9d44:7801::1"),
            LookupAddr("2a00:79c0:609:4900::1"),
            LookupAddr("2a01:4f8:13a:1f8d::1"),
            LookupAddr("2a01:e0a:8a3:ab90::1"),
            LookupAddr("2a02:810b:449e:c900::1"),
            LookupAddr("2a02:8308:20d:e800::1"),
            LookupAddr("2a0a:ef40:331:4401::1"),
            LookupAddr("2a0c:5a86:a002:e700::1"),
            LookupAddr("2a10:3781:1d7:1::1"),
            LookupAddr("2a12:26c0:3303:a100::1"),
            LookupAddr("2a12:a800:2:1::1"),
        };
        FastRandomContext rng{/*fDeterministic=*/true};
        std::ranges::shuffle(addrs, rng);
    
        BenchGetMappedAS(bench, "Multi", addrs, /*check=*/true);
    }
    
    BENCHMARK(AsMapGetMappedAS);
    
    #endif // ENABLE_EMBEDDED_ASMAP
    

    which produces the following results for me locally:

    rm -rfd build && cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_BENCH=ON && ninja -C build -j$(nproc) &&
    build/bin/bench_bitcoin -filter='AsMapGetMappedAS.*'

    | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 349.18 | 2,863,851.03 | 0.5% | 0.01 | AsMapGetMappedASQuad9v4 | 324.84 | 3,078,397.27 | 2.6% | 0.01 | AsMapGetMappedASQuad9v6 | 471.04 | 2,122,949.81 | 1.3% | 0.01 | AsMapGetMappedASCloudflarev4 | 412.50 | 2,424,262.71 | 1.7% | 0.01 | AsMapGetMappedASCloudflarev6 | 484.80 | 2,062,702.85 | 2.2% | 0.01 | AsMapGetMappedASGooglev4 | 399.10 | 2,505,644.85 | 1.2% | 0.01 | AsMapGetMappedASGooglev6 | 6.85 | 146,068,377.86 | 3.6% | 0.01 | AsMapGetMappedASUnmappedv4 | 83.94 | 11,912,821.70 | 1.3% | 0.01 | AsMapGetMappedASUnmappedv6 | 424.98 | 2,353,046.87 | 0.8% | 0.01 | AsMapGetMappedASMulti

  25. 0xB10C force-pushed on May 15, 2026
  26. 0xB10C force-pushed on May 15, 2026
  27. DrahtBot added the label CI failed on May 15, 2026
  28. DrahtBot commented at 12:50 PM on May 15, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task No wallet: https://github.com/bitcoin/bitcoin/actions/runs/25917242867/job/76176847375</sub> <sub>LLM reason (✨ experimental): CI failed due to a C++ build error: asmap.cpp could not find the header node/data/ip_asn.dat.h (file not found).</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  29. 0xB10C commented at 12:55 PM on May 15, 2026: contributor

    Thanks @fjahr & @l0rinc! Included your suggestions. I didn't do #35285 (review) as I slightly perfer the individual BENCHMARK()s, but happy to include this if you have a strong opinion on this.

  30. bench: add benchmark for GetMappedAS()
    With #28792 merged, we can use the embedded ASMap file to benchmark
    the IP -> ASN lookups. Before, this would have been cumbersome as it
    required having a real, external ASMap file. We want to benchmark
    against a real file, as a smaller test file has significantly faster
    lookups.
    
    The benchmarks cover individual IP address lookups of mapped and
    unmapped IPv4 and IPv6 addresses along with a multi-IP lookup.
    For the IPs we assume to be mapped, we assert that they are mapped.
    Updating the embedded ASMap file might change the benchmark results
    slightly as some lookups will be a bit faster and others slower.
    
    ```
    $ ./build/bin/bench_bitcoin --filter=ASMapGetMappedAS.* -min-time=5000
    
    |               ns/op |                op/s |    err% |     total | benchmark
    |--------------------:|--------------------:|--------:|----------:|:----------
    |              460.41 |        2,171,994.61 |    0.2% |      5.48 | `ASMapGetMappedASCloudflarev4`
    |              356.96 |        2,801,460.45 |    0.0% |      5.33 | `ASMapGetMappedASCloudflarev6`
    |              476.58 |        2,098,304.01 |    0.1% |      5.51 | `ASMapGetMappedASGooglev4`
    |              359.17 |        2,784,224.15 |    0.0% |      5.33 | `ASMapGetMappedASGooglev6`
    |              398.82 |        2,507,410.35 |    0.1% |      5.50 | `ASMapGetMappedASMulti`
    |              346.11 |        2,889,237.31 |    0.3% |      5.32 | `ASMapGetMappedASQuad9v4`
    |              274.21 |        3,646,832.70 |    0.1% |      5.50 | `ASMapGetMappedASQuad9v6`
    |                5.32 |      187,875,440.96 |    0.1% |      5.50 | `ASMapGetMappedASUnmappedv4`
    |               65.19 |       15,339,680.04 |    0.1% |      5.51 | `ASMapGetMappedASUnmappedv6`
    ```
    
    Co-authored-by: Fabian Jahr <fjahr@protonmail.com>
    Co-authored-by: Lőrinc <pap.lorinc@gmail.com>
    096bb0b5c0
  31. 0xB10C force-pushed on May 15, 2026
  32. in src/bench/asmap.cpp:18 in 096bb0b5c0
      13 | +#include <array>
      14 | +#include <cassert>
      15 | +#include <span>
      16 | +#include <string>
      17 | +
      18 | +static void BenchGetMappedAS(benchmark::Bench& bench, std::span<const CNetAddr> addrs, bool check = true)
    


    sipa commented at 1:24 PM on May 15, 2026:

    Nit: wrap code with an anonymous namespace (namespace { ... }) instead of static functions.

  33. in src/bench/asmap.cpp:34 in 096bb0b5c0
      29 | +            assert((netgroupman.GetMappedAS(addr) > 0) == check);
      30 | +        }
      31 | +    });
      32 | +}
      33 | +
      34 | +static CNetAddr LookupAddr(const std::string& address) { return LookupHost(address, /*fAllowLookup=*/false).value(); }
    


    sipa commented at 1:26 PM on May 15, 2026:

    Nit, or suggestion for a follow-up: move this function to src/netbase. There are several other places in the codebase that can benefit from it.

  34. sipa commented at 1:30 PM on May 15, 2026: member

    ACK 731d08cd1864c764fc1fbb3fd5346913d00cb7aa. Only non-blocking nits.

  35. l0rinc commented at 1:33 PM on May 15, 2026: contributor

    ACK 096bb0b5c05965222c31d84fe96900157187f89d

    Since my last review most of my suggestions were either applied or explained.

    The commit message measurements were updated - could you please update them in the PR description as well?

    nit: I don't think "LLM disclosure" is useful, we either understand the change fully (in which case there's no point in stating which tools were used - we don't "disclose" that we had a bug that was found by the compiler or CI or spell checker, I don't see why LLMs are a special category) or we don't understand it fully (in which case we shouldn't push the change).

  36. DrahtBot requested review from sipa on May 15, 2026
  37. DrahtBot requested review from sedited on May 15, 2026
  38. DrahtBot requested review from fjahr on May 15, 2026
  39. l0rinc approved
  40. fjahr commented at 1:47 PM on May 15, 2026: contributor

    ACK 096bb0b5c05965222c31d84fe96900157187f89d @sipa: Your ack points to an outdated hash, maybe a mistake

  41. sipa commented at 2:03 PM on May 15, 2026: member

    ACK 096bb0b5c05965222c31d84fe96900157187f89d

  42. DrahtBot removed the label CI failed on May 15, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-15 21:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me