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:
|
||||
if: github.event_name == 'pull_request'
|
||||
needs: [format-taginfo-docs]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: self-hosted
|
||||
env:
|
||||
CCOMPILER: clang-16
|
||||
CXXCOMPILER: clang++-16
|
||||
@@ -664,37 +664,17 @@ jobs:
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
RUN_BIG_BENCHMARK: ${{ contains(github.event.pull_request.labels.*.name, 'Performance') }}
|
||||
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
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
path: pr
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m pip install "conan<2.0.0" "requests==2.31.0" "numpy==1.26.4" --break-system-packages
|
||||
sudo apt-get update -y && sudo apt-get install ccache
|
||||
- name: Activate virtualenv
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
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
|
||||
run: |
|
||||
if [ "$RUN_BIG_BENCHMARK" = "true" ]; then
|
||||
@@ -722,50 +702,67 @@ jobs:
|
||||
path: base
|
||||
- name: Build Base Branch
|
||||
run: |
|
||||
cd base
|
||||
npm ci --ignore-scripts
|
||||
cd ..
|
||||
mkdir 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) benchmarks
|
||||
cd ..
|
||||
make -C test/data
|
||||
- name: Build PR Branch
|
||||
run: |
|
||||
cd pr
|
||||
npm ci --ignore-scripts
|
||||
cd ..
|
||||
mkdir -p 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) benchmarks
|
||||
cd ..
|
||||
make -C test/data
|
||||
# we run benchmarks in tmpfs to avoid impact of disk IO
|
||||
- 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
|
||||
run: |
|
||||
sudo mount -t tmpfs -o size=4g none /opt/benchmarks
|
||||
cp -rf pr/build /opt/benchmarks/build
|
||||
mkdir -p /opt/benchmarks/test
|
||||
cp -rf pr/test/data /opt/benchmarks/test/data
|
||||
cp -rf pr/profiles /opt/benchmarks/profiles
|
||||
sudo cset shield -c 2-3 -k on
|
||||
sudo mount -t tmpfs -o size=4g none ~/benchmarks
|
||||
cp -rf pr/build ~/benchmarks/build
|
||||
cp -rf pr/lib ~/benchmarks/lib
|
||||
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 umount /opt/benchmarks
|
||||
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 ~/benchmarks
|
||||
sudo cset shield --reset
|
||||
- name: Run Base Benchmarks
|
||||
run: |
|
||||
sudo mount -t tmpfs -o size=4g none /opt/benchmarks
|
||||
cp -rf base/build /opt/benchmarks/build
|
||||
mkdir -p /opt/benchmarks/test
|
||||
cp -rf base/test/data /opt/benchmarks/test/data
|
||||
cp -rf base/profiles /opt/benchmarks/profiles
|
||||
sudo cset shield -c 2-3 -k on
|
||||
sudo mount -t tmpfs -o size=4g none ~/benchmarks
|
||||
cp -rf base/build ~/benchmarks/build
|
||||
cp -rf base/lib ~/benchmarks/lib
|
||||
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
|
||||
if [ ! -f /opt/benchmarks/test/data/portugal_to_korea.json ]; then
|
||||
cp base/src/benchmarks/portugal_to_korea.json /opt/benchmarks/test/data/portugal_to_korea.json
|
||||
if [ ! -f ~/benchmarks/test/data/portugal_to_korea.json ]; then
|
||||
cp base/src/benchmarks/portugal_to_korea.json ~/benchmarks/test/data/portugal_to_korea.json
|
||||
fi
|
||||
# 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 umount /opt/benchmarks
|
||||
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 ~/benchmarks
|
||||
sudo cset shield --reset
|
||||
- name: Post Benchmark Results
|
||||
run: |
|
||||
python3 pr/scripts/ci/post_benchmark_results.py base_results pr_results
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Unreleased
|
||||
- Changes from 5.27.1
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
@@ -26,7 +26,15 @@ Feature: Foot - Access tags on ways
|
||||
| motorway | no | | |
|
||||
| motorway | no | yes | x |
|
||||
| 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
|
||||
Then routability should be
|
||||
|
||||
@@ -116,8 +116,8 @@ class CellCustomizer
|
||||
const std::vector<bool> &allowed_nodes,
|
||||
CellMetric &metric) const
|
||||
{
|
||||
Heap heap_exemplar(graph.GetNumberOfNodes());
|
||||
HeapPtr heaps(heap_exemplar);
|
||||
const auto number_of_nodes = graph.GetNumberOfNodes();
|
||||
HeapPtr heaps([number_of_nodes] { return Heap{number_of_nodes}; });
|
||||
|
||||
for (std::size_t level = 1; level < partition.GetNumberOfLevels(); ++level)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MEMINFO_HPP
|
||||
|
||||
#include "util/log.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
@@ -10,22 +11,31 @@
|
||||
namespace osrm::util
|
||||
{
|
||||
|
||||
inline void DumpMemoryStats()
|
||||
inline size_t PeakRAMUsedInBytes()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
rusage usage;
|
||||
getrusage(RUSAGE_SELF, &usage);
|
||||
#ifdef __linux__
|
||||
// Under linux, ru.maxrss is in kb
|
||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss * 1024;
|
||||
return usage.ru_maxrss * 1024;
|
||||
#else // __linux__
|
||||
// Under BSD systems (OSX), it's in bytes
|
||||
util::Log() << "RAM: peak bytes used: " << usage.ru_maxrss;
|
||||
return usage.ru_maxrss;
|
||||
#endif // __linux__
|
||||
#else // _WIN32
|
||||
return 0;
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
inline void DumpMemoryStats()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
util::Log() << "RAM: peak bytes used: " << PeakRAMUsedInBytes();
|
||||
#else // _WIN32
|
||||
util::Log() << "RAM: peak bytes used: <not implemented on Windows>";
|
||||
#endif // _WIN32
|
||||
}
|
||||
} // 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
|
||||
#define OSRM_UTIL_QUERY_HEAP_HPP
|
||||
|
||||
#include "util/pool_allocator.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/heap/d_ary_heap.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm::util
|
||||
{
|
||||
|
||||
@@ -56,7 +55,11 @@ template <typename NodeID, typename Key> class UnorderedMapStorage
|
||||
void Clear() { nodes.clear(); }
|
||||
|
||||
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,
|
||||
@@ -142,10 +145,12 @@ class QueryHeap
|
||||
return weight > other.weight;
|
||||
}
|
||||
};
|
||||
|
||||
using HeapContainer = boost::heap::d_ary_heap<HeapData,
|
||||
boost::heap::arity<4>,
|
||||
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;
|
||||
|
||||
public:
|
||||
@@ -160,6 +165,9 @@ class QueryHeap
|
||||
Data data;
|
||||
};
|
||||
|
||||
QueryHeap(const QueryHeap &other) = delete;
|
||||
QueryHeap(QueryHeap &&other) = delete;
|
||||
|
||||
template <typename... StorageArgs> explicit QueryHeap(StorageArgs... args) : node_index(args...)
|
||||
{
|
||||
Clear();
|
||||
|
||||
Generated
+12
-1
@@ -10,7 +10,8 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.11"
|
||||
"@mapbox/node-pre-gyp": "^1.0.11",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.18.10",
|
||||
@@ -14652,6 +14653,11 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"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": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
@@ -30296,6 +30302,11 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"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": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
|
||||
+7
-4
@@ -4,7 +4,8 @@
|
||||
"private": false,
|
||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++ designed to run on OpenStreetMap data.",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.11"
|
||||
"@mapbox/node-pre-gyp": "^1.0.11",
|
||||
"seedrandom": "^3.0.5"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
@@ -57,6 +58,7 @@
|
||||
"jsonpath": "^1.1.1",
|
||||
"mkdirp": "^0.5.6",
|
||||
"node-addon-api": "^5.0.0",
|
||||
"node-cmake": "^2.5.1",
|
||||
"node-timeout": "0.0.4",
|
||||
"polyline": "^0.2.0",
|
||||
"request": "^2.88.2",
|
||||
@@ -64,12 +66,13 @@
|
||||
"tape": "^4.16.0",
|
||||
"turf": "^3.0.14",
|
||||
"uglify-js": "^3.17.0",
|
||||
"xmlbuilder": "^4.2.1",
|
||||
"node-cmake": "^2.5.1"
|
||||
"xmlbuilder": "^4.2.1"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"binary": {
|
||||
"napi_versions": [8],
|
||||
"napi_versions": [
|
||||
8
|
||||
],
|
||||
"module_name": "node_osrm",
|
||||
"module_path": "./lib/binding_napi_v{napi_build_version}/",
|
||||
"host": "https://github.com",
|
||||
|
||||
@@ -90,6 +90,7 @@ function setup()
|
||||
path = walking_speed,
|
||||
steps = walking_speed,
|
||||
pedestrian = walking_speed,
|
||||
platform = walking_speed,
|
||||
footway = 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
|
||||
|
||||
BENCHMARKS_FOLDER="$BINARIES_FOLDER/src/benchmarks"
|
||||
|
||||
echo "Running match-bench MLD"
|
||||
$BENCHMARKS_FOLDER/match-bench "$FOLDER/test/data/mld/monaco.osrm" mld > "$RESULTS_FOLDER/match_mld.bench"
|
||||
echo "Running match-bench CH"
|
||||
@@ -81,6 +82,18 @@ function run_benchmarks_for_folder {
|
||||
echo "Running osrm-contract"
|
||||
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 BENCH in nearest table trip route match; do
|
||||
echo "Running random $BENCH $ALGORITHM"
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "osrm/osrm.hpp"
|
||||
#include "osrm/status.hpp"
|
||||
|
||||
#include "util/meminfo.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
@@ -655,6 +655,12 @@ try
|
||||
std::cerr << "Unknown benchmark: " << benchmarkToRun << std::endl;
|
||||
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;
|
||||
}
|
||||
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