From ee059c44fee65033ca82a858fc2f15eaff3eeea6 Mon Sep 17 00:00:00 2001 From: dmiller Date: Wed, 2 Nov 2022 02:12:39 +0000 Subject: [PATCH] Big optimization of doAnyOutstandingRetransmits Retransmitting does not change the set of incomplete hosts, so there's no need to use a map to store the current position in the outstanding probes queue. Using a vector is much faster. Additionally, improper use of std::map::find() and std::map::operator[] meant that the O(logN) lookup was happening 4 times for a single host for each iteration through the loop. Complexity for N targets is now O(N), not O(N logN) --- scan_engine.cc | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/scan_engine.cc b/scan_engine.cc index 110c77f5f..8d86780fd 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -2437,14 +2437,18 @@ static void retransmitProbe(UltraScanInfo *USI, HostScanStats *hss, USI->gstats->probes_sent++; } +struct ProbeCacheNode { + HostScanStats *hss; + std::list::iterator probeI; +}; + /* Go through the ProbeQueue of each host, identify any timed out probes, then try to retransmit them as appropriate */ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) { std::multiset::iterator hostI; - std::list::iterator probeI; /* A cache of the last processed probe from each host, to avoid re-examining a bunch of probes to find the next one that needs to be retransmitted. */ - std::map::iterator> probe_cache; + std::vector probe_cache; HostScanStats *host = NULL; UltraProbe *probe = NULL; int retrans = 0; /* Number of retransmissions during a loop */ @@ -2457,14 +2461,29 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) { if (o.debugging) tv_start = USI->now; + probe_cache.reserve(USI->numIncompleteHosts()); + for (hostI = USI->incompleteHosts.begin(); + hostI != USI->incompleteHosts.end(); + hostI++) { + struct ProbeCacheNode pcn; + pcn.hss = *hostI; + /* Skip this host if it has nothing to send. */ + if (pcn.hss->num_probes_active == 0 + && pcn.hss->num_probes_waiting_retransmit == 0) + continue; + assert(!pcn.hss->probes_outstanding.empty()); + pcn.probeI = pcn.hss->probes_outstanding.end(); + probe_cache.push_back(pcn); + } /* Loop until we get through all the hosts without a retransmit or we're not OK to send any more. */ do { retrans = 0; - for (hostI = USI->incompleteHosts.begin(); - hostI != USI->incompleteHosts.end() && USI->gstats->sendOK(NULL); - hostI++) { - host = *hostI; + for (std::vector::iterator pci = probe_cache.begin(); + pci != probe_cache.end() && USI->gstats->sendOK(NULL); + pci++) { + host = pci->hss; + std::list::iterator &probeI = pci->probeI; /* Skip this host if it has nothing to send. */ if ((host->num_probes_active == 0 && host->num_probes_waiting_retransmit == 0)) @@ -2473,12 +2492,6 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) { continue; assert(!host->probes_outstanding.empty()); - /* Initialize the probe cache if necessary. */ - if (probe_cache.find(host) == probe_cache.end()) - probe_cache[host] = host->probes_outstanding.end(); - /* Restore the probe iterator from the cache. */ - probeI = probe_cache[host]; - maxtries = host->allowedTryno(NULL, NULL); do { probeI--; @@ -2508,8 +2521,6 @@ static void doAnyOutstandingRetransmits(UltraScanInfo *USI) { /* Wrap the probe iterator around. */ if (probeI == host->probes_outstanding.begin()) probeI = host->probes_outstanding.end(); - /* Cache the probe iterator. */ - probe_cache[host] = probeI; } } while (USI->gstats->sendOK(NULL) && retrans != 0);