nfs-utils-0001: client_lookup() non-FQDN branch O(N) linked list scan per call in support/export/client.c:289. With N unique wildcard/netgroup/subnet clients, export_read totals O(N^2). Fix: hash table for hostname lookup. 119x at N=4000. nfs-utils-0002: get_exportlist() in utils/mountd/mountd.c, lookup_or_create_elist_entry O(E) path scan + insert_group O(G) dedup scan, both per export = O(E^2) total. Fix: hash tables for path lookup and group dedup. 73x at N=4000. MOAD-0002 (intertangle): clientlist/exportlist globals are standard single-threaded daemon design, single execution context. CLEAN. MOAD-0003 (leaked context): no __thread or pthread_getspecific. CLEAN. MOAD-0004 (logged secret): gssd logs keytab paths and principal names (not credentials). No key material logged. CLEAN. MOAD-0005 (thundering herd): caches protected by ple_lock mutex in gssd, single-threaded event loop in mountd. CLEAN.
170 lines
5.5 KiB
C++
170 lines
5.5 KiB
C++
// Unit test for speed-dreams-0001: ReUpdateStandings std::find O(N^2) -> unordered_map O(N)
|
|
// Tests that hash-based lookup produces identical results to linear scan.
|
|
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <chrono>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <algorithm>
|
|
|
|
struct tReStandings {
|
|
std::string drvName;
|
|
int points;
|
|
|
|
bool operator==(const std::string &b) const { return drvName == b; }
|
|
};
|
|
|
|
// Original: O(runDrv * curDrv) linear scan
|
|
static std::vector<tReStandings> update_standings_original(
|
|
const std::vector<tReStandings> &existing,
|
|
const std::vector<std::pair<std::string, int>> &raceResults)
|
|
{
|
|
std::vector<tReStandings> standings = existing;
|
|
|
|
for (const auto &result : raceResults) {
|
|
auto found = std::find(standings.begin(), standings.end(), result.first);
|
|
if (found == standings.end()) {
|
|
tReStandings st;
|
|
st.drvName = result.first;
|
|
st.points = result.second;
|
|
standings.push_back(st);
|
|
} else {
|
|
found->points += result.second;
|
|
}
|
|
}
|
|
|
|
return standings;
|
|
}
|
|
|
|
// Patched: O(runDrv + curDrv) hash lookup
|
|
static std::vector<tReStandings> update_standings_patched(
|
|
const std::vector<tReStandings> &existing,
|
|
const std::vector<std::pair<std::string, int>> &raceResults)
|
|
{
|
|
std::vector<tReStandings> standings = existing;
|
|
std::unordered_map<std::string, size_t> standingsIndex;
|
|
|
|
for (size_t i = 0; i < standings.size(); i++)
|
|
standingsIndex[standings[i].drvName] = i;
|
|
|
|
for (const auto &result : raceResults) {
|
|
auto indexIt = standingsIndex.find(result.first);
|
|
if (indexIt == standingsIndex.end()) {
|
|
tReStandings st;
|
|
st.drvName = result.first;
|
|
st.points = result.second;
|
|
standings.push_back(st);
|
|
standingsIndex[result.first] = standings.size() - 1;
|
|
} else {
|
|
standings[indexIt->second].points += result.second;
|
|
}
|
|
}
|
|
|
|
return standings;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
// Test 1: Correctness with small data
|
|
{
|
|
std::vector<tReStandings> existing = {{"Alice", 10}, {"Bob", 20}, {"Carol", 5}};
|
|
std::vector<std::pair<std::string, int>> results = {
|
|
{"Bob", 15}, {"Dave", 8}, {"Alice", 12}, {"Eve", 3}
|
|
};
|
|
|
|
auto orig = update_standings_original(existing, results);
|
|
auto patched = update_standings_patched(existing, results);
|
|
|
|
assert(orig.size() == patched.size());
|
|
for (size_t i = 0; i < orig.size(); i++) {
|
|
assert(orig[i].drvName == patched[i].drvName);
|
|
assert(orig[i].points == patched[i].points);
|
|
}
|
|
printf("PASS: correctness with small data\n");
|
|
}
|
|
|
|
// Test 2: All new drivers
|
|
{
|
|
std::vector<tReStandings> existing;
|
|
std::vector<std::pair<std::string, int>> results = {
|
|
{"A", 1}, {"B", 2}, {"C", 3}
|
|
};
|
|
|
|
auto orig = update_standings_original(existing, results);
|
|
auto patched = update_standings_patched(existing, results);
|
|
|
|
assert(orig.size() == patched.size());
|
|
for (size_t i = 0; i < orig.size(); i++) {
|
|
assert(orig[i].drvName == patched[i].drvName);
|
|
assert(orig[i].points == patched[i].points);
|
|
}
|
|
printf("PASS: all new drivers\n");
|
|
}
|
|
|
|
// Test 3: All existing drivers
|
|
{
|
|
std::vector<tReStandings> existing = {{"A", 10}, {"B", 20}};
|
|
std::vector<std::pair<std::string, int>> results = {
|
|
{"A", 5}, {"B", 10}
|
|
};
|
|
|
|
auto orig = update_standings_original(existing, results);
|
|
auto patched = update_standings_patched(existing, results);
|
|
|
|
assert(orig.size() == 2);
|
|
assert(orig[0].points == 15);
|
|
assert(orig[1].points == 30);
|
|
assert(orig.size() == patched.size());
|
|
for (size_t i = 0; i < orig.size(); i++) {
|
|
assert(orig[i].drvName == patched[i].drvName);
|
|
assert(orig[i].points == patched[i].points);
|
|
}
|
|
printf("PASS: all existing drivers\n");
|
|
}
|
|
|
|
// Test 4: Performance at scale (N=500 drivers, R=200 race results)
|
|
{
|
|
const int N = 500;
|
|
const int R = 200;
|
|
|
|
std::vector<tReStandings> existing;
|
|
for (int i = 0; i < N; i++) {
|
|
tReStandings st;
|
|
st.drvName = "Driver_" + std::to_string(i);
|
|
st.points = i * 10;
|
|
existing.push_back(st);
|
|
}
|
|
|
|
std::vector<std::pair<std::string, int>> results;
|
|
for (int i = 0; i < R; i++)
|
|
results.push_back({"Driver_" + std::to_string(i % N), 5});
|
|
|
|
// Warm up
|
|
update_standings_original(existing, results);
|
|
update_standings_patched(existing, results);
|
|
|
|
const int ITERS = 500;
|
|
|
|
auto t0 = std::chrono::high_resolution_clock::now();
|
|
for (int i = 0; i < ITERS; i++)
|
|
update_standings_original(existing, results);
|
|
auto t1 = std::chrono::high_resolution_clock::now();
|
|
for (int i = 0; i < ITERS; i++)
|
|
update_standings_patched(existing, results);
|
|
auto t2 = std::chrono::high_resolution_clock::now();
|
|
|
|
double orig_us = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count();
|
|
double patched_us = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();
|
|
double ratio = orig_us / patched_us;
|
|
|
|
printf("PASS: performance N=%d R=%d: original=%.0fus patched=%.0fus ratio=%.1fx\n",
|
|
N, R, orig_us, patched_us, ratio);
|
|
|
|
assert(ratio > 2.0);
|
|
}
|
|
|
|
printf("ALL TESTS PASSED\n");
|
|
return 0;
|
|
}
|