Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d47012a3e6 | |||
| e5e25a1aca | |||
| 84f12c7c6d | |||
| 7802f86bd6 | |||
| 43afec3b39 | |||
| bff349f1b1 | |||
| 9ce059f216 | |||
| 6090387c5e | |||
| 3096440505 | |||
| 8bd26dc8b6 | |||
| 70d67d0eea | |||
| fdd1ca05df | |||
| 2da7ca5338 | |||
| 81d128b100 | |||
| f18791a71b | |||
| 1436e96ff4 | |||
| 21f53ed6dd | |||
| e045dea04c | |||
| ac05d36102 | |||
| e9cdb317f6 | |||
| 270f187e2a | |||
| fb8182a10e | |||
| 69bc6c035d | |||
| a18ad919af | |||
| 434cab4952 | |||
| a90e9dde33 | |||
| 9ef1911eae | |||
| 18b3c5f8ed | |||
| 3691f90e23 | |||
| 4d940ab096 | |||
| c5aae5148e | |||
| 058c26e39a | |||
| 7337771aaf | |||
| abbe5e25a5 | |||
| 6d2fc45476 | |||
| 6f04aa9587 | |||
| 1037256a30 | |||
| f9358ed031 | |||
| 13448e4f9a | |||
| 7eb2d93a82 | |||
| 49f875c0f8 | |||
| 53032e556a | |||
| 233a7563b6 | |||
| d1f04abf42 | |||
| c578698da0 | |||
| 8df282b2e6 | |||
| 5f166a5e4e | |||
| f62e917226 | |||
| 611a3c250b | |||
| bbdac63362 | |||
| 0723dc073c | |||
| 3bd897ffe1 | |||
| 8c7b80e7ee | |||
| 4e5bf05518 |
@@ -653,7 +653,7 @@ jobs:
|
|||||||
benchmarks:
|
benchmarks:
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
needs: [format-taginfo-docs]
|
needs: [format-taginfo-docs]
|
||||||
runs-on: ubuntu-24.04
|
runs-on: self-hosted
|
||||||
env:
|
env:
|
||||||
CCOMPILER: clang-16
|
CCOMPILER: clang-16
|
||||||
CXXCOMPILER: clang++-16
|
CXXCOMPILER: clang++-16
|
||||||
@@ -664,37 +664,17 @@ jobs:
|
|||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
RUN_BIG_BENCHMARK: ${{ contains(github.event.pull_request.labels.*.name, 'Performance') }}
|
RUN_BIG_BENCHMARK: ${{ contains(github.event.pull_request.labels.*.name, 'Performance') }}
|
||||||
steps:
|
steps:
|
||||||
- name: Enable data.osm.pbf cache
|
|
||||||
if: ${{ ! env.RUN_BIG_BENCHMARK }}
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/data.osm.pbf
|
|
||||||
key: v1-data-osm-pbf
|
|
||||||
restore-keys: |
|
|
||||||
v1-data-osm-pbf
|
|
||||||
- name: Enable compiler cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.ccache
|
|
||||||
key: v1-ccache-benchmarks-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
v1-ccache-benchmarks-
|
|
||||||
- name: Enable Conan cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.conan
|
|
||||||
key: v1-conan-benchmarks-${{ github.sha }}
|
|
||||||
restore-keys: |
|
|
||||||
v1-conan-benchmarks-
|
|
||||||
- name: Checkout PR Branch
|
- name: Checkout PR Branch
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
path: pr
|
path: pr
|
||||||
- name: Install dependencies
|
- name: Activate virtualenv
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install "conan<2.0.0" "requests==2.31.0" "numpy==1.26.4" --break-system-packages
|
python3 -m venv .venv
|
||||||
sudo apt-get update -y && sudo apt-get install ccache
|
source .venv/bin/activate
|
||||||
|
echo PATH=$PATH >> $GITHUB_ENV
|
||||||
|
pip install "conan<2.0.0" "requests==2.31.0" "numpy==1.26.4"
|
||||||
- name: Prepare data
|
- name: Prepare data
|
||||||
run: |
|
run: |
|
||||||
if [ "$RUN_BIG_BENCHMARK" = "true" ]; then
|
if [ "$RUN_BIG_BENCHMARK" = "true" ]; then
|
||||||
@@ -722,50 +702,67 @@ jobs:
|
|||||||
path: base
|
path: base
|
||||||
- name: Build Base Branch
|
- name: Build Base Branch
|
||||||
run: |
|
run: |
|
||||||
|
cd base
|
||||||
|
npm ci --ignore-scripts
|
||||||
|
cd ..
|
||||||
mkdir base/build
|
mkdir base/build
|
||||||
cd base/build
|
cd base/build
|
||||||
cmake -DENABLE_CONAN=ON -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DENABLE_CONAN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_NODE_BINDINGS=ON ..
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
make -j$(nproc) benchmarks
|
make -j$(nproc) benchmarks
|
||||||
cd ..
|
cd ..
|
||||||
make -C test/data
|
make -C test/data
|
||||||
- name: Build PR Branch
|
- name: Build PR Branch
|
||||||
run: |
|
run: |
|
||||||
|
cd pr
|
||||||
|
npm ci --ignore-scripts
|
||||||
|
cd ..
|
||||||
mkdir -p pr/build
|
mkdir -p pr/build
|
||||||
cd pr/build
|
cd pr/build
|
||||||
cmake -DENABLE_CONAN=ON -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DENABLE_CONAN=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_NODE_BINDINGS=ON ..
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
make -j$(nproc) benchmarks
|
make -j$(nproc) benchmarks
|
||||||
cd ..
|
cd ..
|
||||||
make -C test/data
|
make -C test/data
|
||||||
# we run benchmarks in tmpfs to avoid impact of disk IO
|
# we run benchmarks in tmpfs to avoid impact of disk IO
|
||||||
- name: Create folder for tmpfs
|
- name: Create folder for tmpfs
|
||||||
run: mkdir -p /opt/benchmarks
|
run: |
|
||||||
|
# if by any chance it was mounted before(e.g. due to previous job failed), unmount it
|
||||||
|
sudo umount ~/benchmarks | true
|
||||||
|
rm -rf ~/benchmarks
|
||||||
|
mkdir -p ~/benchmarks
|
||||||
|
# see https://llvm.org/docs/Benchmarking.html
|
||||||
- name: Run PR Benchmarks
|
- name: Run PR Benchmarks
|
||||||
run: |
|
run: |
|
||||||
sudo mount -t tmpfs -o size=4g none /opt/benchmarks
|
sudo cset shield -c 2-3 -k on
|
||||||
cp -rf pr/build /opt/benchmarks/build
|
sudo mount -t tmpfs -o size=4g none ~/benchmarks
|
||||||
mkdir -p /opt/benchmarks/test
|
cp -rf pr/build ~/benchmarks/build
|
||||||
cp -rf pr/test/data /opt/benchmarks/test/data
|
cp -rf pr/lib ~/benchmarks/lib
|
||||||
cp -rf pr/profiles /opt/benchmarks/profiles
|
mkdir -p ~/benchmarks/test
|
||||||
|
cp -rf pr/test/data ~/benchmarks/test/data
|
||||||
|
cp -rf pr/profiles ~/benchmarks/profiles
|
||||||
|
|
||||||
./pr/scripts/ci/run_benchmarks.sh -f /opt/benchmarks -r $(pwd)/pr_results -s $(pwd)/pr -b /opt/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv
|
sudo cset shield --exec -- ./pr/scripts/ci/run_benchmarks.sh -f ~/benchmarks -r $(pwd)/pr_results -s $(pwd)/pr -b ~/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv
|
||||||
sudo umount /opt/benchmarks
|
sudo umount ~/benchmarks
|
||||||
|
sudo cset shield --reset
|
||||||
- name: Run Base Benchmarks
|
- name: Run Base Benchmarks
|
||||||
run: |
|
run: |
|
||||||
sudo mount -t tmpfs -o size=4g none /opt/benchmarks
|
sudo cset shield -c 2-3 -k on
|
||||||
cp -rf base/build /opt/benchmarks/build
|
sudo mount -t tmpfs -o size=4g none ~/benchmarks
|
||||||
mkdir -p /opt/benchmarks/test
|
cp -rf base/build ~/benchmarks/build
|
||||||
cp -rf base/test/data /opt/benchmarks/test/data
|
cp -rf base/lib ~/benchmarks/lib
|
||||||
cp -rf base/profiles /opt/benchmarks/profiles
|
mkdir -p ~/benchmarks/test
|
||||||
|
cp -rf base/test/data ~/benchmarks/test/data
|
||||||
|
cp -rf base/profiles ~/benchmarks/profiles
|
||||||
|
|
||||||
# TODO: remove it when base branch will have this file at needed location
|
# TODO: remove it when base branch will have this file at needed location
|
||||||
if [ ! -f /opt/benchmarks/test/data/portugal_to_korea.json ]; then
|
if [ ! -f ~/benchmarks/test/data/portugal_to_korea.json ]; then
|
||||||
cp base/src/benchmarks/portugal_to_korea.json /opt/benchmarks/test/data/portugal_to_korea.json
|
cp base/src/benchmarks/portugal_to_korea.json ~/benchmarks/test/data/portugal_to_korea.json
|
||||||
fi
|
fi
|
||||||
# we intentionally use scripts from PR branch to be able to update them and see results in the same PR
|
# we intentionally use scripts from PR branch to be able to update them and see results in the same PR
|
||||||
./pr/scripts/ci/run_benchmarks.sh -f /opt/benchmarks -r $(pwd)/base_results -s $(pwd)/pr -b /opt/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv
|
sudo cset shield --exec -- cset shield --exec -- ./pr/scripts/ci/run_benchmarks.sh -f ~/benchmarks -r $(pwd)/base_results -s $(pwd)/pr -b ~/benchmarks/build -o ~/data.osm.pbf -g ~/gps_traces.csv
|
||||||
sudo umount /opt/benchmarks
|
sudo umount ~/benchmarks
|
||||||
|
sudo cset shield --reset
|
||||||
- name: Post Benchmark Results
|
- name: Post Benchmark Results
|
||||||
run: |
|
run: |
|
||||||
python3 pr/scripts/ci/post_benchmark_results.py base_results pr_results
|
python3 pr/scripts/ci/post_benchmark_results.py base_results pr_results
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Unreleased
|
# Unreleased
|
||||||
- Changes from 5.27.1
|
- Changes from 5.27.1
|
||||||
- Features
|
- Features
|
||||||
|
- ADDED: Route pedestrians over highway=platform [#6993](https://github.com/Project-OSRM/osrm-backend/pull/6993)
|
||||||
- REMOVED: Remove all core-CH left-overs [#6920](https://github.com/Project-OSRM/osrm-backend/pull/6920)
|
- REMOVED: Remove all core-CH left-overs [#6920](https://github.com/Project-OSRM/osrm-backend/pull/6920)
|
||||||
- ADDED: Add support for a keepalive_timeout flag. [#6674](https://github.com/Project-OSRM/osrm-backend/pull/6674)
|
- ADDED: Add support for a keepalive_timeout flag. [#6674](https://github.com/Project-OSRM/osrm-backend/pull/6674)
|
||||||
- ADDED: Add support for a default_radius flag. [#6575](https://github.com/Project-OSRM/osrm-backend/pull/6575)
|
- ADDED: Add support for a default_radius flag. [#6575](https://github.com/Project-OSRM/osrm-backend/pull/6575)
|
||||||
|
|||||||
@@ -26,7 +26,15 @@ Feature: Foot - Access tags on ways
|
|||||||
| motorway | no | | |
|
| motorway | no | | |
|
||||||
| motorway | no | yes | x |
|
| motorway | no | yes | x |
|
||||||
| motorway | no | no | |
|
| motorway | no | no | |
|
||||||
|
| platform | | | x |
|
||||||
|
| platform | | yes | x |
|
||||||
|
| platform | | no | |
|
||||||
|
| platform | yes | | x |
|
||||||
|
| platform | yes | yes | x |
|
||||||
|
| platform | yes | no | |
|
||||||
|
| platform | no | | |
|
||||||
|
| platform | no | yes | x |
|
||||||
|
| platform | no | no | |
|
||||||
|
|
||||||
Scenario: Foot - Overwriting implied acccess on ways
|
Scenario: Foot - Overwriting implied acccess on ways
|
||||||
Then routability should be
|
Then routability should be
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ class CellCustomizer
|
|||||||
const std::vector<bool> &allowed_nodes,
|
const std::vector<bool> &allowed_nodes,
|
||||||
CellMetric &metric) const
|
CellMetric &metric) const
|
||||||
{
|
{
|
||||||
Heap heap_exemplar(graph.GetNumberOfNodes());
|
const auto number_of_nodes = graph.GetNumberOfNodes();
|
||||||
HeapPtr heaps(heap_exemplar);
|
HeapPtr heaps([number_of_nodes] { return Heap{number_of_nodes}; });
|
||||||
|
|
||||||
for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level)
|
for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define MEMINFO_HPP
|
#define MEMINFO_HPP
|
||||||
|
|
||||||
#include "util/log.hpp"
|
#include "util/log.hpp"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -10,22 +11,31 @@
|
|||||||
namespace osrm::util
|
namespace osrm::util
|
||||||
{
|
{
|
||||||
|
|
||||||
inline void DumpMemoryStats()
|
inline size_t PeakRAMUsedInBytes()
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
rusage usage;
|
rusage usage;
|
||||||
getrusage(RUSAGE_SELF, &usage);
|
getrusage(RUSAGE_SELF, &usage);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// Under linux, ru.maxrss is in kb
|
// Under linux, ru.maxrss is in kb
|
||||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss * 1024;
|
return usage.ru_maxrss * 1024;
|
||||||
#else // __linux__
|
#else // __linux__
|
||||||
// Under BSD systems (OSX), it's in bytes
|
// Under BSD systems (OSX), it's in bytes
|
||||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss;
|
return usage.ru_maxrss;
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
|
#else // _WIN32
|
||||||
|
return 0;
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DumpMemoryStats()
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
util::Log() << "RAM: peak bytes used: " << PeakRAMUsedInBytes();
|
||||||
#else // _WIN32
|
#else // _WIN32
|
||||||
util::Log() << "RAM: peak bytes used: <not implemented on Windows>";
|
util::Log() << "RAM: peak bytes used: <not implemented on Windows>";
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
}
|
}
|
||||||
} // namespace osrm::util
|
} // namespace osrm::util
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <bit>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <new>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace osrm::util
|
||||||
|
{
|
||||||
|
|
||||||
|
inline size_t align_up(size_t n, size_t alignment)
|
||||||
|
{
|
||||||
|
return (n + alignment - 1) & ~(alignment - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_next_power_of_two_exponent(size_t n)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(n > 0);
|
||||||
|
return (sizeof(size_t) * 8) - std::countl_zero(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryPool
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
constexpr static size_t MIN_CHUNK_SIZE_BYTES = 4096;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<MemoryPool> instance()
|
||||||
|
{
|
||||||
|
static thread_local std::shared_ptr<MemoryPool> instance;
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
instance = std::shared_ptr<MemoryPool>(new MemoryPool());
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T *allocate(std::size_t items_count)
|
||||||
|
{
|
||||||
|
static_assert(alignof(T) <= alignof(std::max_align_t),
|
||||||
|
"Type is over-aligned for this allocator.");
|
||||||
|
|
||||||
|
size_t free_list_index = get_next_power_of_two_exponent(items_count * sizeof(T));
|
||||||
|
auto &free_list = free_lists_[free_list_index];
|
||||||
|
if (free_list.empty())
|
||||||
|
{
|
||||||
|
size_t block_size_in_bytes = 1u << free_list_index;
|
||||||
|
block_size_in_bytes = align_up(block_size_in_bytes, alignof(std::max_align_t));
|
||||||
|
// check if there is space in current memory chunk
|
||||||
|
if (current_chunk_left_bytes_ < block_size_in_bytes)
|
||||||
|
{
|
||||||
|
allocate_chunk(block_size_in_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_list.push_back(current_chunk_ptr_);
|
||||||
|
current_chunk_left_bytes_ -= block_size_in_bytes;
|
||||||
|
current_chunk_ptr_ += block_size_in_bytes;
|
||||||
|
}
|
||||||
|
auto ptr = reinterpret_cast<T *>(free_list.back());
|
||||||
|
free_list.pop_back();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void deallocate(T *p, std::size_t n) noexcept
|
||||||
|
{
|
||||||
|
size_t free_list_index = get_next_power_of_two_exponent(n * sizeof(T));
|
||||||
|
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
|
||||||
|
free_lists_[free_list_index].push_back(reinterpret_cast<void *>(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
~MemoryPool()
|
||||||
|
{
|
||||||
|
for (auto chunk : chunks_)
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
||||||
|
std::free(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemoryPool() = default;
|
||||||
|
MemoryPool(const MemoryPool &) = delete;
|
||||||
|
MemoryPool &operator=(const MemoryPool &) = delete;
|
||||||
|
|
||||||
|
void allocate_chunk(size_t bytes)
|
||||||
|
{
|
||||||
|
auto chunk_size = std::max(bytes, MIN_CHUNK_SIZE_BYTES);
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
||||||
|
void *chunk = std::malloc(chunk_size);
|
||||||
|
if (!chunk)
|
||||||
|
{
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
chunks_.push_back(chunk);
|
||||||
|
current_chunk_ptr_ = static_cast<uint8_t *>(chunk);
|
||||||
|
current_chunk_left_bytes_ = chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have 64 free lists, one for each possible power of two
|
||||||
|
std::array<std::vector<void *>, sizeof(std::size_t) * 8> free_lists_;
|
||||||
|
|
||||||
|
// list of allocated memory chunks, we don't free them until the pool is destroyed
|
||||||
|
std::vector<void *> chunks_;
|
||||||
|
|
||||||
|
uint8_t *current_chunk_ptr_ = nullptr;
|
||||||
|
size_t current_chunk_left_bytes_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class PoolAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
PoolAllocator() noexcept : pool(MemoryPool::instance()){};
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
PoolAllocator(const PoolAllocator<U> &) noexcept : pool(MemoryPool::instance())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> struct rebind
|
||||||
|
{
|
||||||
|
using other = PoolAllocator<U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
T *allocate(std::size_t n) { return pool->allocate<T>(n); }
|
||||||
|
|
||||||
|
void deallocate(T *p, std::size_t n) noexcept { pool->deallocate<T>(p, n); }
|
||||||
|
|
||||||
|
PoolAllocator(const PoolAllocator &) = default;
|
||||||
|
PoolAllocator &operator=(const PoolAllocator &) = default;
|
||||||
|
PoolAllocator(PoolAllocator &&) noexcept = default;
|
||||||
|
PoolAllocator &operator=(PoolAllocator &&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// using shared_ptr guarantees that memory pool won't be destroyed before all allocators using
|
||||||
|
// it (important if there are static instances of PoolAllocator)
|
||||||
|
std::shared_ptr<MemoryPool> pool;
|
||||||
|
};
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator==(const PoolAllocator<T> &, const PoolAllocator<U> &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
bool operator!=(const PoolAllocator<T> &, const PoolAllocator<U> &)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace osrm::util
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
#ifndef OSRM_UTIL_QUERY_HEAP_HPP
|
#ifndef OSRM_UTIL_QUERY_HEAP_HPP
|
||||||
#define OSRM_UTIL_QUERY_HEAP_HPP
|
#define OSRM_UTIL_QUERY_HEAP_HPP
|
||||||
|
|
||||||
|
#include "util/pool_allocator.hpp"
|
||||||
|
#include <algorithm>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/heap/d_ary_heap.hpp>
|
#include <boost/heap/d_ary_heap.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm::util
|
namespace osrm::util
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -56,7 +55,11 @@ template <typename NodeID, typename Key> class UnorderedMapStorage
|
|||||||
void Clear() { nodes.clear(); }
|
void Clear() { nodes.clear(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<NodeID, Key> nodes;
|
template <typename K, typename V>
|
||||||
|
using UnorderedMap = std::
|
||||||
|
unordered_map<K, V, std::hash<K>, std::equal_to<K>, PoolAllocator<std::pair<const K, V>>>;
|
||||||
|
|
||||||
|
UnorderedMap<NodeID, Key> nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename NodeID,
|
template <typename NodeID,
|
||||||
@@ -142,10 +145,12 @@ class QueryHeap
|
|||||||
return weight > other.weight;
|
return weight > other.weight;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using HeapContainer = boost::heap::d_ary_heap<HeapData,
|
using HeapContainer = boost::heap::d_ary_heap<HeapData,
|
||||||
boost::heap::arity<4>,
|
boost::heap::arity<4>,
|
||||||
boost::heap::mutable_<true>,
|
boost::heap::mutable_<true>,
|
||||||
boost::heap::compare<std::greater<HeapData>>>;
|
boost::heap::compare<std::greater<HeapData>>,
|
||||||
|
boost::heap::allocator<PoolAllocator<HeapData>>>;
|
||||||
using HeapHandle = typename HeapContainer::handle_type;
|
using HeapHandle = typename HeapContainer::handle_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -160,6 +165,9 @@ class QueryHeap
|
|||||||
Data data;
|
Data data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QueryHeap(const QueryHeap &other) = delete;
|
||||||
|
QueryHeap(QueryHeap &&other) = delete;
|
||||||
|
|
||||||
template <typename... StorageArgs> explicit QueryHeap(StorageArgs... args) : node_index(args...)
|
template <typename... StorageArgs> explicit QueryHeap(StorageArgs... args) : node_index(args...)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|||||||
Generated
+12
-1
@@ -10,7 +10,8 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.11"
|
"@mapbox/node-pre-gyp": "^1.0.11",
|
||||||
|
"seedrandom": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.18.10",
|
"@babel/cli": "^7.18.10",
|
||||||
@@ -14652,6 +14653,11 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/seedrandom": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "5.7.2",
|
"version": "5.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||||
@@ -30296,6 +30302,11 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"seedrandom": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
|
||||||
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.7.2",
|
"version": "5.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||||
|
|||||||
+7
-4
@@ -4,7 +4,8 @@
|
|||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++ designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++ designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.11"
|
"@mapbox/node-pre-gyp": "^1.0.11",
|
||||||
|
"seedrandom": "^3.0.5"
|
||||||
},
|
},
|
||||||
"browserify": {
|
"browserify": {
|
||||||
"transform": [
|
"transform": [
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
"jsonpath": "^1.1.1",
|
"jsonpath": "^1.1.1",
|
||||||
"mkdirp": "^0.5.6",
|
"mkdirp": "^0.5.6",
|
||||||
"node-addon-api": "^5.0.0",
|
"node-addon-api": "^5.0.0",
|
||||||
|
"node-cmake": "^2.5.1",
|
||||||
"node-timeout": "0.0.4",
|
"node-timeout": "0.0.4",
|
||||||
"polyline": "^0.2.0",
|
"polyline": "^0.2.0",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
@@ -64,12 +66,13 @@
|
|||||||
"tape": "^4.16.0",
|
"tape": "^4.16.0",
|
||||||
"turf": "^3.0.14",
|
"turf": "^3.0.14",
|
||||||
"uglify-js": "^3.17.0",
|
"uglify-js": "^3.17.0",
|
||||||
"xmlbuilder": "^4.2.1",
|
"xmlbuilder": "^4.2.1"
|
||||||
"node-cmake": "^2.5.1"
|
|
||||||
},
|
},
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"binary": {
|
"binary": {
|
||||||
"napi_versions": [8],
|
"napi_versions": [
|
||||||
|
8
|
||||||
|
],
|
||||||
"module_name": "node_osrm",
|
"module_name": "node_osrm",
|
||||||
"module_path": "./lib/binding_napi_v{napi_build_version}/",
|
"module_path": "./lib/binding_napi_v{napi_build_version}/",
|
||||||
"host": "https://github.com",
|
"host": "https://github.com",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ function setup()
|
|||||||
path = walking_speed,
|
path = walking_speed,
|
||||||
steps = walking_speed,
|
steps = walking_speed,
|
||||||
pedestrian = walking_speed,
|
pedestrian = walking_speed,
|
||||||
|
platform = walking_speed,
|
||||||
footway = walking_speed,
|
footway = walking_speed,
|
||||||
pier = walking_speed,
|
pier = walking_speed,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const readline = require('readline');
|
||||||
|
const seedrandom = require('seedrandom');
|
||||||
|
|
||||||
|
|
||||||
|
let RNG;
|
||||||
|
|
||||||
|
class GPSData {
|
||||||
|
constructor(gpsTracesFilePath) {
|
||||||
|
this.tracks = {};
|
||||||
|
this.coordinates = [];
|
||||||
|
this.trackIds = [];
|
||||||
|
this._loadGPSTraces(gpsTracesFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadGPSTraces(gpsTracesFilePath) {
|
||||||
|
const expandedPath = path.resolve(gpsTracesFilePath);
|
||||||
|
const data = fs.readFileSync(expandedPath, 'utf-8');
|
||||||
|
const lines = data.split('\n');
|
||||||
|
const headers = lines[0].split(',');
|
||||||
|
|
||||||
|
const latitudeIndex = headers.indexOf('Latitude');
|
||||||
|
const longitudeIndex = headers.indexOf('Longitude');
|
||||||
|
const trackIdIndex = headers.indexOf('TrackID');
|
||||||
|
|
||||||
|
for (let i = 1; i < lines.length; i++) {
|
||||||
|
if (lines[i].trim() === '') continue;
|
||||||
|
const row = lines[i].split(',');
|
||||||
|
|
||||||
|
const latitude = parseFloat(row[latitudeIndex]);
|
||||||
|
const longitude = parseFloat(row[longitudeIndex]);
|
||||||
|
const trackId = row[trackIdIndex];
|
||||||
|
|
||||||
|
const coord = [longitude, latitude];
|
||||||
|
this.coordinates.push(coord);
|
||||||
|
|
||||||
|
if (!this.tracks[trackId]) {
|
||||||
|
this.tracks[trackId] = [];
|
||||||
|
}
|
||||||
|
this.tracks[trackId].push(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.trackIds = Object.keys(this.tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomCoordinate() {
|
||||||
|
const randomIndex = Math.floor(RNG() * this.coordinates.length);
|
||||||
|
return this.coordinates[randomIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomTrack() {
|
||||||
|
const randomIndex = Math.floor(RNG() * this.trackIds.length);
|
||||||
|
const trackId = this.trackIds[randomIndex];
|
||||||
|
return this.tracks[trackId];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function runOSRMMethod(osrm, method, coordinates) {
|
||||||
|
const time = await new Promise((resolve, reject) => {
|
||||||
|
const startTime = process.hrtime();
|
||||||
|
osrm[method]({coordinates}, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
if (['NoSegment', 'NoMatch', 'NoRoute', 'NoTrips'].includes(err.message)) {
|
||||||
|
resolve(null);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const endTime = process.hrtime(startTime);
|
||||||
|
resolve(endTime[0] + endTime[1] / 1e9);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function nearest(osrm, gpsData) {
|
||||||
|
const times = [];
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
const coord = gpsData.getRandomCoordinate();
|
||||||
|
times.push(await runOSRMMethod(osrm, 'nearest', [coord]));
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function route(osrm, gpsData) {
|
||||||
|
const times = [];
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
const from = gpsData.getRandomCoordinate();
|
||||||
|
const to = gpsData.getRandomCoordinate();
|
||||||
|
|
||||||
|
|
||||||
|
times.push(await runOSRMMethod(osrm, 'route', [from, to]));
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function table(osrm, gpsData) {
|
||||||
|
const times = [];
|
||||||
|
for (let i = 0; i < 250; i++) {
|
||||||
|
const numPoints = Math.floor(RNG() * 3) + 15;
|
||||||
|
const coordinates = [];
|
||||||
|
for (let i = 0; i < numPoints; i++) {
|
||||||
|
coordinates.push(gpsData.getRandomCoordinate());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
times.push(await runOSRMMethod(osrm, 'table', coordinates));
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function match(osrm, gpsData) {
|
||||||
|
const times = [];
|
||||||
|
for (let i = 0; i < 1000; i++) {
|
||||||
|
const numPoints = Math.floor(RNG() * 50) + 50;
|
||||||
|
const coordinates = gpsData.getRandomTrack().slice(0, numPoints);
|
||||||
|
|
||||||
|
|
||||||
|
times.push(await runOSRMMethod(osrm, 'match', coordinates));
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function trip(osrm, gpsData) {
|
||||||
|
const times = [];
|
||||||
|
for (let i = 0; i < 250; i++) {
|
||||||
|
const numPoints = Math.floor(RNG() * 2) + 5;
|
||||||
|
const coordinates = [];
|
||||||
|
for (let i = 0; i < numPoints; i++) {
|
||||||
|
coordinates.push(gpsData.getRandomCoordinate());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
times.push(await runOSRMMethod(osrm, 'trip', coordinates));
|
||||||
|
}
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bootstrapConfidenceInterval(data, numSamples = 1000, confidenceLevel = 0.95) {
|
||||||
|
let means = [];
|
||||||
|
let dataLength = data.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < numSamples; i++) {
|
||||||
|
let sample = [];
|
||||||
|
for (let j = 0; j < dataLength; j++) {
|
||||||
|
let randomIndex = Math.floor(RNG() * dataLength);
|
||||||
|
sample.push(data[randomIndex]);
|
||||||
|
}
|
||||||
|
let sampleMean = sample.reduce((a, b) => a + b, 0) / sample.length;
|
||||||
|
means.push(sampleMean);
|
||||||
|
}
|
||||||
|
|
||||||
|
means.sort((a, b) => a - b);
|
||||||
|
let lowerBoundIndex = Math.floor((1 - confidenceLevel) / 2 * numSamples);
|
||||||
|
let upperBoundIndex = Math.floor((1 + confidenceLevel) / 2 * numSamples);
|
||||||
|
let mean = means.reduce((a, b) => a + b, 0) / means.length;
|
||||||
|
let lowerBound = means[lowerBoundIndex];
|
||||||
|
let upperBound = means[upperBoundIndex];
|
||||||
|
|
||||||
|
return { mean: mean, lowerBound: lowerBound, upperBound: upperBound };
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateConfidenceInterval(data) {
|
||||||
|
let { mean, lowerBound, upperBound } = bootstrapConfidenceInterval(data);
|
||||||
|
let bestValue = Math.max(...data);
|
||||||
|
let errorMargin = (upperBound - lowerBound) / 2;
|
||||||
|
|
||||||
|
return { mean, errorMargin, bestValue };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
const {OSRM} = require(args[0]);
|
||||||
|
const path = args[1];
|
||||||
|
const algorithm = args[2].toUpperCase();
|
||||||
|
const method = args[3];
|
||||||
|
const gpsTracesFilePath = args[4];
|
||||||
|
const iterations = parseInt(args[5]);
|
||||||
|
|
||||||
|
const gpsData = new GPSData(gpsTracesFilePath);
|
||||||
|
const osrm = new OSRM({path, algorithm});
|
||||||
|
|
||||||
|
|
||||||
|
const functions = {
|
||||||
|
route: route,
|
||||||
|
table: table,
|
||||||
|
nearest: nearest,
|
||||||
|
match: match,
|
||||||
|
trip: trip
|
||||||
|
};
|
||||||
|
const func = functions[method];
|
||||||
|
if (!func) {
|
||||||
|
throw new Error('Unknown method');
|
||||||
|
}
|
||||||
|
const allTimes = [];
|
||||||
|
for (let i = 0; i < iterations; i++) {
|
||||||
|
RNG = seedrandom(42);
|
||||||
|
allTimes.push((await func(osrm, gpsData)).filter(t => t !== null));
|
||||||
|
}
|
||||||
|
|
||||||
|
const opsPerSec = allTimes.map(times => times.length / times.reduce((a, b) => a + b, 0));
|
||||||
|
const { mean, errorMargin, bestValue } = calculateConfidenceInterval(opsPerSec);
|
||||||
|
console.log(`Ops: ${mean.toFixed(1)} ± ${errorMargin.toFixed(1)} ops/s. Best: ${bestValue.toFixed(1)} ops/s`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -53,6 +53,7 @@ function run_benchmarks_for_folder {
|
|||||||
mkdir -p $RESULTS_FOLDER
|
mkdir -p $RESULTS_FOLDER
|
||||||
|
|
||||||
BENCHMARKS_FOLDER="$BINARIES_FOLDER/src/benchmarks"
|
BENCHMARKS_FOLDER="$BINARIES_FOLDER/src/benchmarks"
|
||||||
|
|
||||||
echo "Running match-bench MLD"
|
echo "Running match-bench MLD"
|
||||||
$BENCHMARKS_FOLDER/match-bench "$FOLDER/test/data/mld/monaco.osrm" mld > "$RESULTS_FOLDER/match_mld.bench"
|
$BENCHMARKS_FOLDER/match-bench "$FOLDER/test/data/mld/monaco.osrm" mld > "$RESULTS_FOLDER/match_mld.bench"
|
||||||
echo "Running match-bench CH"
|
echo "Running match-bench CH"
|
||||||
@@ -81,6 +82,18 @@ function run_benchmarks_for_folder {
|
|||||||
echo "Running osrm-contract"
|
echo "Running osrm-contract"
|
||||||
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-contract $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_contract.bench"
|
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-contract $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_contract.bench"
|
||||||
|
|
||||||
|
|
||||||
|
for ALGORITHM in ch mld; do
|
||||||
|
for BENCH in nearest table trip route match; do
|
||||||
|
echo "Running node $BENCH $ALGORITHM"
|
||||||
|
START=$(date +%s.%N)
|
||||||
|
node $SCRIPTS_FOLDER/scripts/ci/bench.js $FOLDER/lib/binding/node_osrm.node $FOLDER/data.osrm $ALGORITHM $BENCH $GPS_TRACES > "$RESULTS_FOLDER/node_${BENCH}_${ALGORITHM}.bench" 5
|
||||||
|
END=$(date +%s.%N)
|
||||||
|
DIFF=$(echo "$END - $START" | bc)
|
||||||
|
echo "Took: ${DIFF}s"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
for ALGORITHM in ch mld; do
|
for ALGORITHM in ch mld; do
|
||||||
for BENCH in nearest table trip route match; do
|
for BENCH in nearest table trip route match; do
|
||||||
echo "Running random $BENCH $ALGORITHM"
|
echo "Running random $BENCH $ALGORITHM"
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
#include "osrm/osrm.hpp"
|
#include "osrm/osrm.hpp"
|
||||||
#include "osrm/status.hpp"
|
#include "osrm/status.hpp"
|
||||||
|
|
||||||
|
#include "util/meminfo.hpp"
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
#include <boost/optional/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
@@ -655,6 +655,12 @@ try
|
|||||||
std::cerr << "Unknown benchmark: " << benchmarkToRun << std::endl;
|
std::cerr << "Unknown benchmark: " << benchmarkToRun << std::endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "Peak RAM: " << std::setprecision(3)
|
||||||
|
<< static_cast<double>(osrm::util::PeakRAMUsedInBytes()) /
|
||||||
|
static_cast<double>((1024 * 1024))
|
||||||
|
<< "MB" << std::endl;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
#include "util/pool_allocator.hpp"
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(pool_allocator)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::util;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_align_up)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(align_up(5, 4), 8);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(9, 8), 16);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(17, 16), 32);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(4, 4), 4);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(8, 8), 8);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(16, 16), 16);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(32, 16), 32);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(0, 4), 0);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(0, 8), 0);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(0, 16), 0);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(1000000, 256), 1000192);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(999999, 512), 1000448);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(123456789, 1024), 123457536);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(0, 1), 0);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(5, 1), 5);
|
||||||
|
BOOST_CHECK_EQUAL(align_up(123456, 1), 123456);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_get_next_power_of_two_exponent)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(1), 0);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(2), 1);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(4), 2);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(8), 3);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(16), 4);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(3), 2);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(5), 3);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(9), 4);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(15), 4);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(17), 5);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(1), 0);
|
||||||
|
BOOST_CHECK_EQUAL(get_next_power_of_two_exponent(SIZE_MAX), sizeof(size_t) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// in many of these tests we hope on address sanitizer to alert in the case if we are doing
|
||||||
|
// something wrong
|
||||||
|
BOOST_AUTO_TEST_CASE(smoke)
|
||||||
|
{
|
||||||
|
PoolAllocator<int> pool;
|
||||||
|
auto ptr = pool.allocate(1);
|
||||||
|
*ptr = 42;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool.deallocate(ptr, 1);
|
||||||
|
|
||||||
|
ptr = pool.allocate(2);
|
||||||
|
*ptr = 42;
|
||||||
|
*(ptr + 1) = 43;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool.deallocate(ptr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(a_lot_of_items)
|
||||||
|
{
|
||||||
|
PoolAllocator<int> pool;
|
||||||
|
auto ptr = pool.allocate(2048);
|
||||||
|
for (int i = 0; i < 2048; ++i)
|
||||||
|
{
|
||||||
|
ptr[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 2048; ++i)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(ptr[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.deallocate(ptr, 2048);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(copy)
|
||||||
|
{
|
||||||
|
PoolAllocator<int> pool;
|
||||||
|
auto ptr = pool.allocate(1);
|
||||||
|
*ptr = 42;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool.deallocate(ptr, 1);
|
||||||
|
|
||||||
|
PoolAllocator<int> pool2(pool);
|
||||||
|
ptr = pool2.allocate(1);
|
||||||
|
*ptr = 42;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool2.deallocate(ptr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(move)
|
||||||
|
{
|
||||||
|
PoolAllocator<int> pool;
|
||||||
|
auto ptr = pool.allocate(1);
|
||||||
|
*ptr = 42;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool.deallocate(ptr, 1);
|
||||||
|
|
||||||
|
PoolAllocator<int> pool2(std::move(pool));
|
||||||
|
ptr = pool2.allocate(1);
|
||||||
|
*ptr = 42;
|
||||||
|
BOOST_CHECK_NE(ptr, nullptr);
|
||||||
|
pool2.deallocate(ptr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(unordered_map)
|
||||||
|
{
|
||||||
|
std::unordered_map<int,
|
||||||
|
int,
|
||||||
|
std::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
PoolAllocator<std::pair<const int, int>>>
|
||||||
|
map;
|
||||||
|
map[1] = 42;
|
||||||
|
BOOST_CHECK_EQUAL(map[1], 42);
|
||||||
|
|
||||||
|
map.clear();
|
||||||
|
|
||||||
|
map[2] = 43;
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(map[2], 43);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(alignment)
|
||||||
|
{
|
||||||
|
PoolAllocator<char> pool_char;
|
||||||
|
PoolAllocator<double> pool_double;
|
||||||
|
|
||||||
|
auto ptr_char = pool_char.allocate(1);
|
||||||
|
auto ptr_double = pool_double.allocate(1);
|
||||||
|
|
||||||
|
BOOST_CHECK_NE(ptr_double, nullptr);
|
||||||
|
BOOST_CHECK_EQUAL(reinterpret_cast<uintptr_t>(ptr_double) % alignof(double), 0);
|
||||||
|
BOOST_CHECK_NE(ptr_char, nullptr);
|
||||||
|
BOOST_CHECK_EQUAL(reinterpret_cast<uintptr_t>(ptr_char) % alignof(char), 0);
|
||||||
|
|
||||||
|
pool_char.deallocate(ptr_char, 1);
|
||||||
|
pool_double.deallocate(ptr_double, 1);
|
||||||
|
|
||||||
|
ptr_char = pool_char.allocate(2);
|
||||||
|
ptr_double = pool_double.allocate(1);
|
||||||
|
|
||||||
|
BOOST_CHECK_NE(ptr_double, nullptr);
|
||||||
|
BOOST_CHECK_EQUAL(reinterpret_cast<uintptr_t>(ptr_double) % alignof(double), 0);
|
||||||
|
BOOST_CHECK_NE(ptr_char, nullptr);
|
||||||
|
BOOST_CHECK_EQUAL(reinterpret_cast<uintptr_t>(ptr_char) % alignof(char), 0);
|
||||||
|
|
||||||
|
pool_char.deallocate(ptr_char, 2);
|
||||||
|
pool_double.deallocate(ptr_double, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
Reference in New Issue
Block a user