diff --git a/sys/netinet/in_fib_dxr.c b/sys/netinet/in_fib_dxr.c index ec32819a5a6d..fa7fd3b9fc6c 100644 --- a/sys/netinet/in_fib_dxr.c +++ b/sys/netinet/in_fib_dxr.c @@ -203,6 +203,12 @@ struct dxr_aux { uint32_t rtbl_top; uint32_t rtbl_work_frags; uint32_t work_chunk; + + /* Rebuild stats, debugging */ + uint32_t range_updates; + uint32_t range_refs; + uint32_t range_unrefs; + uint32_t trie_updates; }; /* Main lookup structure container */ @@ -234,13 +240,13 @@ SYSCTL_DECL(_net_route_algo); SYSCTL_NODE(_net_route_algo, OID_AUTO, dxr, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "DXR tunables"); -VNET_DEFINE_STATIC(int, max_trie_holes) = 8; +VNET_DEFINE_STATIC(int, max_trie_holes) = 10; #define V_max_trie_holes VNET(max_trie_holes) SYSCTL_INT(_net_route_algo_dxr, OID_AUTO, max_trie_holes, CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(max_trie_holes), 0, "Trie fragmentation threshold before triggering a full rebuild"); -VNET_DEFINE_STATIC(int, max_range_holes) = 16; +VNET_DEFINE_STATIC(int, max_range_holes) = 100; #define V_max_range_holes VNET(max_range_holes) SYSCTL_INT(_net_route_algo_dxr, OID_AUTO, max_range_holes, CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(max_range_holes), 0, @@ -388,6 +394,8 @@ chunk_ref(struct dxr_aux *da, uint32_t chunk) uint32_t size = chunk_size(da, fdesc); uint32_t hash = chunk_hash(da, fdesc); + da->range_refs++; + /* Find an existing descriptor */ LIST_FOREACH(cdp, &da->chunk_hashtbl[hash & CHUNK_HASH_MASK], cd_hash_le) { @@ -478,6 +486,8 @@ chunk_unref(struct dxr_aux *da, uint32_t chunk) uint32_t size = chunk_size(da, fdesc); uint32_t hash = chunk_hash(da, fdesc); + da->range_unrefs++; + /* Find an existing descriptor */ LIST_FOREACH(cdp, &da->chunk_hashtbl[hash & CHUNK_HASH_MASK], cd_hash_le) @@ -707,6 +717,8 @@ update_chunk(struct dxr_aux *da, uint32_t chunk) uint32_t first = chunk << DXR_RANGE_SHIFT; uint32_t last = first | DXR_RANGE_MASK; + da->range_updates++; + if (da->direct_tbl[chunk].fragments != FRAGS_MARK_HIT) chunk_unref(da, chunk); @@ -817,6 +829,7 @@ dxr_build(struct dxr *dxr) da->refcnt = 1; LIST_INIT(&da->all_chunks); LIST_INIT(&da->all_trie); + da->unused_chunks_cnt = 0; da->rtbl_size = RTBL_SIZE_INCR; da->range_tbl = NULL; da->xtbl_size = XTBL_SIZE_INCR; @@ -845,6 +858,10 @@ dxr_build(struct dxr *dxr) } #endif da->fd = dxr->fd; + da->range_updates = 0; + da->range_refs = 0; + da->range_unrefs = 0; + da->trie_updates = 0; microuptime(&t0); @@ -855,6 +872,28 @@ dxr_build(struct dxr *dxr) da->unused_chunks_cnt > V_max_range_holes) range_rebuild = 1; if (range_rebuild) { + /* Dump fragmentation stats */ + if (da->unused_chunks_cnt != 0) { +#define NSIZES 32 + uint32_t size_cnt[NSIZES]; + char out_buf[NSIZES * 10]; + char *p = out_buf; + + bzero(size_cnt, sizeof(size_cnt)); + LIST_FOREACH(cdp, &da->unused_chunks, cd_hash_le) + if (cdp->cd_max_size < NSIZES) + size_cnt[cdp->cd_max_size]++; + else + size_cnt[0]++; + + for (i = 0; i < NSIZES; i++) + if (size_cnt[i]) + p += sprintf(p, "%d:%d ", i, + size_cnt[i]); + FIB_PRINTF(LOG_INFO, da->fd, "frags %s", out_buf); +#undef NSIZES + } + /* Bulk cleanup */ bzero(da->chunk_hashtbl, sizeof(da->chunk_hashtbl)); while ((cdp = LIST_FIRST(&da->all_chunks)) != NULL) { @@ -915,7 +954,15 @@ dxr_build(struct dxr *dxr) for (i = da->updates_low >> dxr_x; i <= da->updates_high >> dxr_x; i++) { - trie_unref(da, i); + if (!trie_rebuild) { + m = 0; + for (int j = 0; j < (1 << dxr_x); j += 32) + m |= da->updates_mask[((i << dxr_x) + j) >> 5]; + if (m == 0) + continue; + trie_unref(da, i); + } + da->trie_updates++; ti = trie_ref(da, i); if (ti < 0) return; @@ -979,10 +1026,13 @@ dxr_build(struct dxr *dxr) FIB_PRINTF(LOG_INFO, da->fd, "%d.%02d KBytes, %d.%02d Bytes/prefix", dxr_tot_size / 1024, dxr_tot_size * 100 / 1024 % 100, i / 100, i % 100); + FIB_PRINTF(LOG_INFO, da->fd, "%d range updates, %d refs, %d unrefs", + da->range_updates, da->range_refs, da->range_unrefs); i = (t1.tv_sec - t0.tv_sec) * 1000000 + t1.tv_usec - t0.tv_usec; FIB_PRINTF(LOG_INFO, da->fd, "range table %s in %u.%03u ms", range_rebuild ? "rebuilt" : "updated", i / 1000, i % 1000); #ifdef DXR2 + FIB_PRINTF(LOG_INFO, da->fd, "%d trie updates", da->trie_updates); i = (t2.tv_sec - t1.tv_sec) * 1000000 + t2.tv_usec - t1.tv_usec; FIB_PRINTF(LOG_INFO, da->fd, "trie %s in %u.%03u ms", trie_rebuild ? "rebuilt" : "updated", i / 1000, i % 1000); @@ -1131,6 +1181,9 @@ dxr_change_rib_batch(struct rib_head *rnh, struct fib_change_queue *q, struct rib_rtable_info rinfo; int update_delta = 0; #endif + int plen_min = 32; + int plen_max = 0; + int plen_acc = 0; KASSERT(data != NULL, ("%s: NULL data", __FUNCTION__)); KASSERT(q != NULL, ("%s: NULL q", __FUNCTION__)); @@ -1164,7 +1217,15 @@ dxr_change_rib_batch(struct rib_head *rnh, struct fib_change_queue *q, da->updates_low = start; if (end > da->updates_high) da->updates_high = end; + + plen_acc += plen; + if (plen < plen_min) + plen_min = plen; + if (plen > plen_max) + plen_max = plen; } + FIB_PRINTF(LOG_INFO, da->fd, "plen min %d max %d avg %d", plen_min, + plen_max, plen_acc / q->count); #ifdef INVARIANTS fib_get_rtable_info(fib_get_rh(da->fd), &rinfo);