From: Kefu Chai Date: Wed, 6 May 2026 03:32:03 +0000 (+0800) Subject: test/osd: add perf test for calc_pg_upmaps with mutual overfull upmap pairs X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1c8d6876b1ab9bce8fd454be848ddf8f15e2973e;p=ceph.git test/osd: add perf test for calc_pg_upmaps with mutual overfull upmap pairs Reproduces the scenario from https://tracker.ceph.com/issues/63137: 500 cohort OSDs all at deviation +2, linked by pg_upmap_items rings with R=5 pairs each. Before the fix, every incoming pair triggered a test_change call that got rejected -- calc_pg_upmaps took ~11 minutes. After, it exits in ~200ms. Signed-off-by: Kefu Chai --- diff --git a/src/test/osd/TestOSDMap.cc b/src/test/osd/TestOSDMap.cc index db9a3c210024..a804bc99322e 100644 --- a/src/test/osd/TestOSDMap.cc +++ b/src/test/osd/TestOSDMap.cc @@ -1925,6 +1925,84 @@ TEST_F(OSDMapTest, TryDropRemapOverfullBothOverfull) { } } +TEST_F(OSDMapTest, BUG_63137_calc_pg_upmaps_perf) { + // https://tracker.ceph.com/issues/63137 + // + // try_drop_remap_overfull used to call test_change (full stddev recompute + // over all OSDs) for every incoming pg_upmap_items pair that cannot improve + // distribution. With R incoming pairs per cohort OSD, that is O(n_cohort*R) + // wasted test_change calls. + // + // Setup (size=1, n_osds=600, pg_num=6000, target=10 per OSD): + // cohort OSDs 0..499: 12 PGs each (deviation +2) + // sink OSDs 500..599: 0 PGs each (deviation -10) + // + // pg_upmap: pg(i*12+j) -> osd.i for i in 0..499, j in 0..11 + // pg_upmap_items: pg(i*12+k) [osd.i -> osd.(i+k)%500] k in 1..R + // + // After all upmaps each cohort OSD has (12-R) natural + R incoming = 12 PGs. + // When processing overfull osd.i, there are R incoming ring pairs with + // um_from also at deviation +2. Old code tried dropping each and paid + // test_change; new code skips them with the um_from overload check. + const int n_cohort = 500; + const int n_sink = 100; + const int n_osds = n_cohort + n_sink; + const int pgs_per_cohort = 12; + const int total_pgs = n_cohort * pgs_per_cohort; + const int R = 5; + + set_up_map(n_osds, true); + + int pool_id; + { + OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1); + pending_inc.new_pool_max = osdmap.get_pool_max(); + pool_id = ++pending_inc.new_pool_max; + pg_pool_t empty; + auto p = pending_inc.get_new_pool(pool_id, &empty); + p->size = 1; + p->min_size = 1; + p->set_pg_num(total_pgs); + p->set_pgp_num(total_pgs); + p->type = pg_pool_t::TYPE_REPLICATED; + p->crush_rule = 0; + p->set_flag(pg_pool_t::FLAG_HASHPSPOOL); + pending_inc.new_pool_names[pool_id] = "perf_pool"; + osdmap.apply_incremental(pending_inc); + ASSERT_TRUE(osdmap.have_pg_pool(pool_id)); + } + + // pg_upmap: assign all PGs for cohort OSD i to osd.i + // pg_upmap_items ring: pg(i*12+k) [osd.i -> osd.(i+k)%n_cohort] + { + OSDMap::Incremental inc(osdmap.get_epoch() + 1); + for (int i = 0; i < n_cohort; ++i) { + for (int j = 0; j < pgs_per_cohort; ++j) { + pg_t pg = osdmap.raw_pg_to_pg(pg_t(i * pgs_per_cohort + j, pool_id)); + inc.new_pg_upmap[pg] = mempool::osdmap::vector{i}; + } + for (int k = 1; k <= R; ++k) { + pg_t pg = osdmap.raw_pg_to_pg(pg_t(i * pgs_per_cohort + k, pool_id)); + int um_to = (i + k) % n_cohort; + inc.new_pg_upmap_items[pg] = + mempool::osdmap::vector>{{i, um_to}}; + } + } + osdmap.apply_incremental(inc); + } + + { + set only_pools = {pool_id}; + OSDMap::Incremental pending_inc(osdmap.get_epoch() + 1); + auto start = mono_clock::now(); + osdmap.calc_pg_upmaps(g_ceph_context, 1, 10000, only_pools, &pending_inc); + auto latency = mono_clock::now() - start; + std::cout << "calc_pg_upmaps (63137 scenario, n_cohort=" << n_cohort + << " R=" << R << ") latency: " << timespan_str(latency) + << std::endl; + } +} + TEST_F(OSDMapTest, BUG_42052) { // https://tracker.ceph.com/issues/42052 set_up_map(6, true);