blob: 5b0d9b2195e4177c6727f261174542ef9a26403f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <benchmark/benchmark.h>
#include <memory>
#include <unordered_map>
#include <random>
#include <iostream>
#include <climits>
#include "hash_map.h"
#include "celix_long_hash_map.h"
#include "celix_hash_map_internal.h"
class LongHashmapBenchmark {
public:
explicit LongHashmapBenchmark(int64_t _nrOfEntries) : testVectorsMap{createRandomMap(_nrOfEntries)} {}
~LongHashmapBenchmark() {
celix_longHashMap_destroy(celixHashMap);
hashMap_destroy(deprecatedHashMap, false, false);
}
LongHashmapBenchmark(LongHashmapBenchmark&&) = delete;
LongHashmapBenchmark& operator=(LongHashmapBenchmark&&) = delete;
LongHashmapBenchmark(const LongHashmapBenchmark&) = delete;
LongHashmapBenchmark& operator=(const LongHashmapBenchmark&) = delete;
void fillStdMap() {
for (const auto& pair : testVectorsMap) {
stdMap.emplace(pair.first, pair.second);
}
}
void fillCelixHashMap() {
for (const auto& pair : testVectorsMap) {
celix_longHashMap_putLong(celixHashMap, pair.first, pair.second);
}
}
void fillDeprecatedCelixHashMap() {
for (const auto& pair : testVectorsMap) {
hashMap_put(deprecatedHashMap, reinterpret_cast<void*>(pair.first), reinterpret_cast<void*>(pair.second));
}
}
std::unordered_map<long, int> createRandomMap(int64_t nrOfEntries) {
std::unordered_map<long, int> result{};
while (result.size() < (size_t)nrOfEntries) {
auto key = createRandomKey();
if (result.size() == (size_t)nrOfEntries/2) {
midEntryKey = key;
}
result[key] = createRandomValue();
}
return result;
}
long createRandomKey() {
return keyDistribution(generator);
}
int createRandomValue() {
return valDistribution(generator);
}
std::default_random_engine generator{};
std::uniform_int_distribution<long> keyDistribution{LONG_MIN,LONG_MAX};
std::uniform_int_distribution<int> valDistribution{INT_MIN,INT_MAX};
long midEntryKey{0};
const std::unordered_map<long, int> testVectorsMap;
std::unordered_map<long, int> stdMap{};
hash_map_t* deprecatedHashMap{hashMap_create(nullptr, nullptr, nullptr, nullptr)};
celix_long_hash_map_t* celixHashMap{celix_longHashMap_create()};
};
static void LongHashmapBenchmark_addEntryToStdMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillStdMap();
assert(benchmark.stdMap.size() == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
benchmark.stdMap[42] = 42;
}
state.SetItemsProcessed(state.iterations());
}
static void LongHashmapBenchmark_addEntryToCelixHashmap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillCelixHashMap();
assert(celix_longHashMap_size(benchmark.celixHashMap) == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
celix_longHashMap_putLong(benchmark.celixHashMap, 42, 42);
}
state.SetItemsProcessed(state.iterations());
}
static void LongHashmapBenchmark_addEntryToDeprecatedHashmap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillDeprecatedCelixHashMap();
assert((size_t)hashMap_size(benchmark.deprecatedHashMap) == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
hashMap_put(benchmark.deprecatedHashMap, (void*)42, (void*)42);
}
state.SetItemsProcessed(state.iterations());
}
static void LongHashmapBenchmark_findEntryFromStdMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillStdMap();
assert(benchmark.stdMap.size() == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
auto it = benchmark.stdMap.find(benchmark.midEntryKey);
if (it == benchmark.stdMap.end()) {
std::cerr << "Cannot find entry " << benchmark.midEntryKey << " for std unordered_map." << std::endl;
abort();
}
}
state.SetItemsProcessed(state.iterations());
}
static void LongHashmapBenchmark_findEntryFromCelixMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillCelixHashMap();
assert(celix_longHashMap_size(benchmark.celixHashMap) == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
bool hasKey = celix_longHashMap_hasKey(benchmark.celixHashMap, benchmark.midEntryKey);
if (!hasKey) {
std::cerr << "Cannot find entry " << benchmark.midEntryKey << " for celix hash map." <<std::endl;
abort();
}
}
state.SetItemsProcessed(state.iterations());
auto stats = celix_longHashMap_getStatistics(benchmark.celixHashMap);
state.counters["nrOfBuckets"] = (double)stats.nrOfBuckets;
state.counters["resizeCount"] = (double)stats.resizeCount;
state.counters["averageNrOfEntriesPerBucket"] = stats.averageNrOfEntriesPerBucket;
state.counters["stdDeviationNrOfEntriesPerBucket"] = stats.stdDeviationNrOfEntriesPerBucket;
}
static void LongHashmapBenchmark_findEntryFromDeprecatedMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
benchmark.fillDeprecatedCelixHashMap();
assert((size_t)hashMap_size(benchmark.deprecatedHashMap) == (size_t)state.range(0));
for (auto _ : state) {
// This code gets timed
void* entry = hashMap_get(benchmark.deprecatedHashMap, reinterpret_cast<void*>(benchmark.midEntryKey));
if (entry == nullptr) {
std::cerr << "Cannot find entry " << benchmark.midEntryKey << " for deprecated hash map." << std::endl;
abort();
}
}
state.SetItemsProcessed(state.iterations());
}
static void LongHashmapBenchmark_fillStdMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
for (auto _ : state) {
benchmark.fillStdMap();
state.PauseTiming();
benchmark.stdMap.clear();
state.ResumeTiming();
}
state.SetItemsProcessed(state.iterations() * benchmark.testVectorsMap.size());
}
static void LongHashmapBenchmark_fillCelixHashMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
for (auto _ : state) {
benchmark.fillCelixHashMap();
state.PauseTiming();
celix_longHashMap_clear(benchmark.celixHashMap);
state.ResumeTiming();
}
state.SetItemsProcessed(state.iterations() * benchmark.testVectorsMap.size());
}
static void LongHashmapBenchmark_fillDeprecatedHashMap(benchmark::State& state) {
LongHashmapBenchmark benchmark{state.range(0)};
for (auto _ : state) {
benchmark.fillDeprecatedCelixHashMap();
state.PauseTiming();
hashMap_clear(benchmark.deprecatedHashMap, false, false);
state.ResumeTiming();
}
state.SetItemsProcessed(state.iterations() * benchmark.testVectorsMap.size());
}
#define CELIX_BENCHMARK(name) \
BENCHMARK(name)->MeasureProcessCPUTime()->UseRealTime()->Unit(benchmark::kNanosecond) \
->RangeMultiplier(10)->Range(10, 100000)
CELIX_BENCHMARK(LongHashmapBenchmark_addEntryToStdMap); //reference
CELIX_BENCHMARK(LongHashmapBenchmark_addEntryToCelixHashmap);
CELIX_BENCHMARK(LongHashmapBenchmark_addEntryToDeprecatedHashmap);
CELIX_BENCHMARK(LongHashmapBenchmark_findEntryFromStdMap); //reference
CELIX_BENCHMARK(LongHashmapBenchmark_findEntryFromCelixMap);
CELIX_BENCHMARK(LongHashmapBenchmark_findEntryFromDeprecatedMap);
CELIX_BENCHMARK(LongHashmapBenchmark_fillStdMap); //reference
CELIX_BENCHMARK(LongHashmapBenchmark_fillCelixHashMap);
CELIX_BENCHMARK(LongHashmapBenchmark_fillDeprecatedHashMap);