简体   繁体   中英

Constant Time std::unordered_map<size_t, size_t> and personal hashmap implementation

I implemented my own hashmap and I wanted to benchmark it vs std::unordered_map. I use functions like the following to measure the nanoseconds it takes to do setting, successful gets, and unsuccessful gets:

size_t umap_put_speed(std::unordered_map<size_t, size_t> &umap, size_t key, size_t value){
    auto t1 = high_resolution_clock::now();
    umap[key] = value;
    auto t2 = high_resolution_clock::now();
    auto ns_int = duration_cast<nanoseconds>(t2 - t1);
    return ns_int.count();
}

size_t umap_get_speed(std::unordered_map<size_t, size_t> &umap, size_t key){
    auto t1 = high_resolution_clock::now();
    umap.find(key);
    auto t2 = high_resolution_clock::now();
    auto ns_int = duration_cast<nanoseconds>(t2 - t1);
    return ns_int.count();
}

size_t single_put_speed(HashMap<size_t, size_t, GenericHash<size_t> > &hmap, size_t key, size_t value){
    auto t1 = high_resolution_clock::now();
    hmap.put(key, value);
    auto t2 = high_resolution_clock::now();
    auto ns_int = duration_cast<nanoseconds>(t2 - t1);
    return ns_int.count();
}

size_t single_get_speed(HashMap<size_t, size_t, GenericHash<size_t> > &hmap, size_t key){
    size_t value;
    auto t1 = high_resolution_clock::now();
    hmap.get(key, value);
    auto t2 = high_resolution_clock::now();
    auto ns_int = duration_cast<nanoseconds>(t2 - t1);
    return ns_int.count();
}

I then write the times to a CSV file as follows:

void test_put_speed(){
    std::ofstream benchmark_put;
    benchmark_put.open("benchmarks/put.csv");
    
    benchmark_put << "Num Entries,Linear Map,Unordered Map\n";
    
    // Declare hashmaps
    HashMap<size_t, size_t, GenericHash<size_t> > lmap(SMALL_SIZE);
    std::unordered_map<size_t, size_t> umap;
    
    // Put times
    size_t time_lmap_put = 0;
    size_t time_umap_put = 0;
    
    size_t count = 0;
    for(size_t i = 0; i < MAX_ELEM; i++){
        if(count == WINDOW_SIZE){
            benchmark_put << i << ", ";
            benchmark_put << time_lmap_put/(count) << ", ";
            benchmark_put << time_umap_put/(count) << "\n";
    
            time_lmap_put = 0;
            time_umap_put = 0;
    
            count = 0;
        }
    
        time_lmap_put += lmap_put_speed(lmap, i, i);
        time_umap_put += umap_put_speed(umap, i, i);
    
        count += 1;
    }    
}

However, I get the following nanoseconds for insertion, successful searches, and unsuccessful searches:

基准图。线性地图是我的实现

I know that hashmaps are designed to take on average O(1) time, but for over a million items, I would have thought that the items I'm adding would leak from the cache into main memory, causing accesses to be slower. Is there something that I'm doing wrong fundamentally? Or is my understanding of why I'm expecting performance to be slower incorrect?

While this isn't a solution per se, it is how I ended up getting some results that I was more happy with. I changed two things. First, instead of measuring individual insertions, lookups, and removals, I measured the time it took to chain K operations together. This gave me a much clearer picture of how much faster/slower my implementation was compared to unordered_map. My new functions looked like the following:

double umap_insert_speed(std::unordered_map<size_t, size_t> &umap, std::vector<size_t> keys){
    auto t1 = steady_clock::now();
    for(size_t key : keys){
        umap[key] = 1;    
    }
    auto t2 = steady_clock::now();
    duration<double> s_double = t2 - t1;
    return s_double.count();
}

This generated graphs like the following:

在此处输入图片说明

The second thing I changed was how to get around my timing function not even calling the emplace functions. I simply added a running sum to the loop so I would be using the emplaced values:

double umap_emplace_speed(std::unordered_map<size_t, size_t> &umap, std::vector<size_t> keys){
    size_t value;
    size_t sum = 0;
    auto t1 = steady_clock::now();
    for(size_t key: keys){
        umap.emplace(key, value);
        sum += value;
    }
    auto t2 = steady_clock::now();
    duration<double> s_double = t2 - t1;
    return s_double.count();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM