Merge branch 'master' into replace_boost_filesystem
This commit is contained in:
commit
a1d34196cd
16
.github/workflows/osrm-backend.yml
vendored
16
.github/workflows/osrm-backend.yml
vendored
@ -645,8 +645,10 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
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
|
||||
@ -678,10 +680,18 @@ jobs:
|
||||
sudo apt-get update -y && sudo apt-get install ccache
|
||||
- name: Prepare data
|
||||
run: |
|
||||
if [ ! -f "~/data.osm.pbf" ]; then
|
||||
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf
|
||||
if [ "$RUN_BIG_BENCHMARK" = "true" ]; then
|
||||
rm -rf ~/data.osm.pbf
|
||||
wget http://download.geofabrik.de/europe/poland-latest.osm.pbf -O ~/data.osm.pbf --quiet
|
||||
gunzip -c ./pr/test/data/poland_gps_traces.csv.gz > ~/gps_traces.csv
|
||||
else
|
||||
if [ ! -f "~/data.osm.pbf" ]; then
|
||||
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf
|
||||
else
|
||||
echo "Using cached data.osm.pbf"
|
||||
fi
|
||||
gunzip -c ./pr/test/data/berlin_gps_traces.csv.gz > ~/gps_traces.csv
|
||||
fi
|
||||
gunzip -c ./pr/test/data/berlin_gps_traces.csv.gz > ~/gps_traces.csv
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
echo "CCACHE_DIR=$HOME/.ccache" >> $GITHUB_ENV
|
||||
|
@ -24,6 +24,13 @@
|
||||
- NodeJS:
|
||||
- CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452)
|
||||
- Misc:
|
||||
- CHANGED: Apply micro-optimisation for Table & Trip APIs. [#6949](https://github.com/Project-OSRM/osrm-backend/pull/6949)
|
||||
- CHANGED: Apply micro-optimisation for Route API. [#6948](https://github.com/Project-OSRM/osrm-backend/pull/6948)
|
||||
- CHANGED: Apply micro-optimisation for Match API. [#6945](https://github.com/Project-OSRM/osrm-backend/pull/6945)
|
||||
- CHANGED: Apply micro-optimisation for Nearest API. [#6944](https://github.com/Project-OSRM/osrm-backend/pull/6944)
|
||||
- CHANGED: Avoid copy of intersection in totalTurnAngle. [#6938](https://github.com/Project-OSRM/osrm-backend/pull/6938)
|
||||
- CHANGED: Use std::unordered_map::emplace instead of operator[] when producing JSONs. [#6936](https://github.com/Project-OSRM/osrm-backend/pull/6936)
|
||||
- CHANGED: Avoid copy of vectors in MakeRoute function. [#6939](https://github.com/Project-OSRM/osrm-backend/pull/6939)
|
||||
- FIXED: Fix bugprone-unused-return-value clang-tidy warning. [#6934](https://github.com/Project-OSRM/osrm-backend/pull/6934)
|
||||
- FIXED: Fix performance-noexcept-move-constructor clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6933)
|
||||
- FIXED: Fix performance-noexcept-swap clang-tidy warning. [#6931](https://github.com/Project-OSRM/osrm-backend/pull/6931)
|
||||
|
@ -330,20 +330,12 @@ if(ENABLE_CONAN)
|
||||
|
||||
set(CONAN_BOOST_VERSION "1.85.0@#14265ec82b25d91305bbb3b30d3357f8")
|
||||
set(CONAN_BZIP2_VERSION "1.0.8@#d1b2d5816f25865acf978501dff1f897")
|
||||
set(CONAN_EXPAT_VERSION "2.2.10@#916908d4a570ad839edd25322c3268cd")
|
||||
set(CONAN_LUA_VERSION "5.4.4@#3ec62efc37cd0a5d80b9e5cb35277360")
|
||||
set(CONAN_TBB_VERSION "2021.3.0@#507ec17cbd51a84167e143b20d170eea")
|
||||
set(CONAN_EXPAT_VERSION "2.6.2@#2d385d0d50eb5561006a7ff9e356656b")
|
||||
set(CONAN_LUA_VERSION "5.4.6@#658d6089093cf01992c2737ab2e96763")
|
||||
set(CONAN_TBB_VERSION "2021.12.0@#e56e5b44be8d690530585dd3634c0106")
|
||||
|
||||
set(CONAN_SYSTEM_INCLUDES ON)
|
||||
|
||||
# TODO:
|
||||
# if we link TBB dynamically osrm-extract.exe finishes on the first access to any TBB symbol
|
||||
# with exit code = -1073741515, which means that program cannot load required DLL.
|
||||
if (MSVC)
|
||||
set(TBB_SHARED False)
|
||||
else()
|
||||
set(TBB_SHARED True)
|
||||
endif()
|
||||
|
||||
set(CONAN_ARGS
|
||||
REQUIRES
|
||||
@ -357,7 +349,6 @@ if(ENABLE_CONAN)
|
||||
KEEP_RPATHS
|
||||
NO_OUTPUT_DIRS
|
||||
OPTIONS boost:filesystem_version=3 # https://stackoverflow.com/questions/73392648/error-with-boost-filesystem-version-in-cmake
|
||||
onetbb:shared=${TBB_SHARED}
|
||||
boost:without_stacktrace=True # Apple Silicon cross-compilation fails without it
|
||||
BUILD missing
|
||||
)
|
||||
|
64
docker/Dockerfile-alpine
Normal file
64
docker/Dockerfile-alpine
Normal file
@ -0,0 +1,64 @@
|
||||
FROM alpine:3.20.0 as alpine-mimalloc
|
||||
|
||||
RUN apk add --no-cache mimalloc
|
||||
|
||||
ENV LD_PRELOAD=/usr/lib/libmimalloc.so.2
|
||||
ENV MIMALLOC_LARGE_OS_PAGES=1
|
||||
|
||||
|
||||
FROM alpine-mimalloc as builder
|
||||
ARG DOCKER_TAG
|
||||
ARG BUILD_CONCURRENCY
|
||||
RUN mkdir -p /src && mkdir -p /opt
|
||||
|
||||
RUN apk add --no-cache \
|
||||
cmake make git clang libbz2 libxml2 \
|
||||
boost-dev boost-program_options boost-filesystem boost-iostreams boost-thread \
|
||||
lua5.4-dev onetbb-dev expat-dev
|
||||
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN NPROC=${BUILD_CONCURRENCY:-$(nproc)} && \
|
||||
echo "Building OSRM ${DOCKER_TAG}" && \
|
||||
git show --format="%H" | head -n1 > /opt/OSRM_GITSHA && \
|
||||
echo "Building OSRM gitsha $(cat /opt/OSRM_GITSHA)" && \
|
||||
mkdir -p build && \
|
||||
cd build && \
|
||||
BUILD_TYPE="Release" && \
|
||||
ENABLE_ASSERTIONS="Off" && \
|
||||
BUILD_TOOLS="Off" && \
|
||||
case ${DOCKER_TAG} in *"-debug"*) BUILD_TYPE="Debug";; esac && \
|
||||
case ${DOCKER_TAG} in *"-assertions"*) BUILD_TYPE="RelWithDebInfo" && ENABLE_ASSERTIONS="On" && BUILD_TOOLS="On";; esac && \
|
||||
echo "Building ${BUILD_TYPE} with ENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} BUILD_TOOLS=${BUILD_TOOLS}" && \
|
||||
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DENABLE_ASSERTIONS=${ENABLE_ASSERTIONS} -DBUILD_TOOLS=${BUILD_TOOLS} -DENABLE_LTO=On && \
|
||||
make -j${NPROC} install && \
|
||||
cd ../profiles && \
|
||||
cp -r * /opt && \
|
||||
strip /usr/local/bin/* && \
|
||||
rm -rf /src
|
||||
|
||||
|
||||
# Multistage build to reduce image size - https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds
|
||||
# Only the content below ends up in the image, this helps remove /src from the image (which is large)
|
||||
FROM alpine-mimalloc as runstage
|
||||
|
||||
COPY --from=builder /usr/local /usr/local
|
||||
COPY --from=builder /opt /opt
|
||||
|
||||
RUN apk add --no-cache \
|
||||
boost-program_options boost-regex \
|
||||
boost-date_time boost-chrono boost-filesystem \
|
||||
boost-iostreams boost-system boost-thread \
|
||||
expat lua5.4 onetbb && \
|
||||
ldconfig /usr/local/lib
|
||||
|
||||
RUN /usr/local/bin/osrm-extract --help && \
|
||||
/usr/local/bin/osrm-routed --help && \
|
||||
/usr/local/bin/osrm-contract --help && \
|
||||
/usr/local/bin/osrm-partition --help && \
|
||||
/usr/local/bin/osrm-customize --help
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
EXPOSE 5000
|
6
docker/hooks/build
Normal file → Executable file
6
docker/hooks/build
Normal file → Executable file
@ -6,4 +6,8 @@
|
||||
# ensure that "COPY . /src" is referring to the repo root, not the directory
|
||||
# that contains the Dockerfile.
|
||||
# This script gets executed with a pwd of wherever the Dockerfile is.
|
||||
docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY:-1} --build-arg DOCKER_TAG=${DOCKER_TAG} -t $IMAGE_NAME -f Dockerfile ..
|
||||
|
||||
DOCKER_BUILD="docker build --build-arg BUILD_CONCURRENCY=${CONCURRENCY} --build-arg DOCKER_TAG=${DOCKER_TAG:?unset} -t ${IMAGE_NAME:?unset} -f"
|
||||
|
||||
$DOCKER_BUILD Dockerfile ..
|
||||
$DOCKER_BUILD Dockerfile-alpine ..
|
||||
|
@ -77,19 +77,19 @@ class MatchAPI final : public RouteAPI
|
||||
sub_routes[index].unpacked_path_segments,
|
||||
sub_routes[index].source_traversed_in_reverse,
|
||||
sub_routes[index].target_traversed_in_reverse);
|
||||
route.values["confidence"] = sub_matchings[index].confidence;
|
||||
routes.values.push_back(std::move(route));
|
||||
route.values.emplace("confidence", sub_matchings[index].confidence);
|
||||
routes.values.emplace_back(std::move(route));
|
||||
}
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["tracepoints"] = MakeTracepoints(sub_matchings);
|
||||
response.values.emplace("tracepoints", MakeTracepoints(sub_matchings));
|
||||
}
|
||||
response.values["matchings"] = std::move(routes);
|
||||
response.values["code"] = "Ok";
|
||||
response.values.emplace("matchings", std::move(routes));
|
||||
response.values.emplace("code", "Ok");
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
response.values.emplace("data_version", data_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,13 +132,13 @@ class MatchAPI final : public RouteAPI
|
||||
|
||||
if (tidy_result.can_be_removed[trace_index])
|
||||
{
|
||||
waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish());
|
||||
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
|
||||
continue;
|
||||
}
|
||||
auto matching_index = trace_idx_to_matching_idx[trace_index];
|
||||
if (matching_index.NotMatched())
|
||||
{
|
||||
waypoints.push_back(fbresult::WaypointBuilder(fb_result).Finish());
|
||||
waypoints.emplace_back(fbresult::WaypointBuilder(fb_result).Finish());
|
||||
continue;
|
||||
}
|
||||
const auto &phantom =
|
||||
@ -165,7 +165,7 @@ class MatchAPI final : public RouteAPI
|
||||
{
|
||||
waypoint->add_waypoint_index(matching_index.point_index);
|
||||
}
|
||||
waypoints.push_back(waypoint->Finish());
|
||||
waypoints.emplace_back(waypoint->Finish());
|
||||
}
|
||||
|
||||
return fb_result.CreateVector(waypoints);
|
||||
@ -186,23 +186,23 @@ class MatchAPI final : public RouteAPI
|
||||
{
|
||||
if (tidy_result.can_be_removed[trace_index])
|
||||
{
|
||||
waypoints.values.push_back(util::json::Null());
|
||||
waypoints.values.emplace_back(util::json::Null());
|
||||
continue;
|
||||
}
|
||||
auto matching_index = trace_idx_to_matching_idx[trace_index];
|
||||
if (matching_index.NotMatched())
|
||||
{
|
||||
waypoints.values.push_back(util::json::Null());
|
||||
waypoints.values.emplace_back(util::json::Null());
|
||||
continue;
|
||||
}
|
||||
const auto &phantom =
|
||||
sub_matchings[matching_index.sub_matching_index].nodes[matching_index.point_index];
|
||||
auto waypoint = BaseAPI::MakeWaypoint({phantom});
|
||||
waypoint.values["matchings_index"] = matching_index.sub_matching_index;
|
||||
waypoint.values["waypoint_index"] = matching_index.point_index;
|
||||
waypoint.values["alternatives_count"] =
|
||||
sub_matchings[matching_index.sub_matching_index]
|
||||
.alternatives_count[matching_index.point_index];
|
||||
waypoint.values.emplace("matchings_index", matching_index.sub_matching_index);
|
||||
waypoint.values.emplace("waypoint_index", matching_index.point_index);
|
||||
waypoint.values.emplace("alternatives_count",
|
||||
sub_matchings[matching_index.sub_matching_index]
|
||||
.alternatives_count[matching_index.point_index]);
|
||||
// waypoint indices need to be adjusted if route legs were collapsed
|
||||
// waypoint parameter assumes there is only one match object
|
||||
if (!parameters.waypoints.empty())
|
||||
@ -217,7 +217,7 @@ class MatchAPI final : public RouteAPI
|
||||
waypoint.values["waypoint_index"] = util::json::Null();
|
||||
}
|
||||
}
|
||||
waypoints.values.push_back(std::move(waypoint));
|
||||
waypoints.values.emplace_back(std::move(waypoint));
|
||||
}
|
||||
|
||||
return waypoints;
|
||||
|
@ -100,23 +100,23 @@ class NearestAPI final : public BaseAPI
|
||||
auto waypoint = MakeWaypoint({phantom_node});
|
||||
|
||||
util::json::Array nodes;
|
||||
nodes.values.reserve(2);
|
||||
|
||||
auto node_values = MakeNodes(phantom_node);
|
||||
|
||||
nodes.values.push_back(node_values.first);
|
||||
nodes.values.push_back(node_values.second);
|
||||
waypoint.values["nodes"] = std::move(nodes);
|
||||
|
||||
nodes.values.emplace_back(node_values.first);
|
||||
nodes.values.emplace_back(node_values.second);
|
||||
waypoint.values.emplace("nodes", std::move(nodes));
|
||||
return waypoint;
|
||||
});
|
||||
response.values["waypoints"] = std::move(waypoints);
|
||||
response.values.emplace("waypoints", std::move(waypoints));
|
||||
}
|
||||
|
||||
response.values["code"] = "Ok";
|
||||
response.values.emplace("code", "Ok");
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
response.values.emplace("data_version", data_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,14 +110,14 @@ class RouteAPI : public BaseAPI
|
||||
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["waypoints"] = BaseAPI::MakeWaypoints(waypoint_candidates);
|
||||
response.values.emplace("waypoints", BaseAPI::MakeWaypoints(waypoint_candidates));
|
||||
}
|
||||
response.values["routes"] = std::move(jsRoutes);
|
||||
response.values["code"] = "Ok";
|
||||
response.values.emplace("routes", std::move(jsRoutes));
|
||||
response.values.emplace("code", "Ok");
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
response.values.emplace("data_version", data_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,8 +340,8 @@ class RouteAPI : public BaseAPI
|
||||
unpacked_path_segments,
|
||||
source_traversed_in_reverse,
|
||||
target_traversed_in_reverse);
|
||||
std::vector<guidance::RouteLeg> legs = legs_info.first;
|
||||
std::vector<guidance::LegGeometry> leg_geometries = legs_info.second;
|
||||
std::vector<guidance::RouteLeg> &legs = legs_info.first;
|
||||
std::vector<guidance::LegGeometry> &leg_geometries = legs_info.second;
|
||||
auto route = guidance::assembleRoute(legs);
|
||||
|
||||
// Fill legs
|
||||
@ -716,8 +716,8 @@ class RouteAPI : public BaseAPI
|
||||
unpacked_path_segments,
|
||||
source_traversed_in_reverse,
|
||||
target_traversed_in_reverse);
|
||||
std::vector<guidance::RouteLeg> legs = legs_info.first;
|
||||
std::vector<guidance::LegGeometry> leg_geometries = legs_info.second;
|
||||
std::vector<guidance::RouteLeg> &legs = legs_info.first;
|
||||
std::vector<guidance::LegGeometry> &leg_geometries = legs_info.second;
|
||||
|
||||
auto route = guidance::assembleRoute(legs);
|
||||
boost::optional<util::json::Value> json_overview =
|
||||
@ -784,49 +784,57 @@ class RouteAPI : public BaseAPI
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Speed)
|
||||
{
|
||||
double prev_speed = 0;
|
||||
annotation.values["speed"] = GetAnnotations(
|
||||
leg_geometry,
|
||||
[&prev_speed](const guidance::LegGeometry::Annotation &anno)
|
||||
{
|
||||
if (anno.duration < std::numeric_limits<double>::min())
|
||||
{
|
||||
return prev_speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto speed = std::round(anno.distance / anno.duration * 10.) / 10.;
|
||||
prev_speed = speed;
|
||||
return util::json::clamp_float(speed);
|
||||
}
|
||||
});
|
||||
annotation.values.emplace(
|
||||
"speed",
|
||||
GetAnnotations(leg_geometry,
|
||||
[&prev_speed](const guidance::LegGeometry::Annotation &anno)
|
||||
{
|
||||
if (anno.duration < std::numeric_limits<double>::min())
|
||||
{
|
||||
return prev_speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto speed =
|
||||
std::round(anno.distance / anno.duration * 10.) /
|
||||
10.;
|
||||
prev_speed = speed;
|
||||
return util::json::clamp_float(speed);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Duration)
|
||||
{
|
||||
annotation.values["duration"] =
|
||||
annotation.values.emplace(
|
||||
"duration",
|
||||
GetAnnotations(leg_geometry,
|
||||
[](const guidance::LegGeometry::Annotation &anno)
|
||||
{ return anno.duration; });
|
||||
{ return anno.duration; }));
|
||||
}
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Distance)
|
||||
{
|
||||
annotation.values["distance"] =
|
||||
annotation.values.emplace(
|
||||
"distance",
|
||||
GetAnnotations(leg_geometry,
|
||||
[](const guidance::LegGeometry::Annotation &anno)
|
||||
{ return anno.distance; });
|
||||
{ return anno.distance; }));
|
||||
}
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Weight)
|
||||
{
|
||||
annotation.values["weight"] = GetAnnotations(
|
||||
leg_geometry,
|
||||
[](const guidance::LegGeometry::Annotation &anno) { return anno.weight; });
|
||||
annotation.values.emplace(
|
||||
"weight",
|
||||
GetAnnotations(leg_geometry,
|
||||
[](const guidance::LegGeometry::Annotation &anno)
|
||||
{ return anno.weight; }));
|
||||
}
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Datasources)
|
||||
{
|
||||
annotation.values["datasources"] =
|
||||
annotation.values.emplace(
|
||||
"datasources",
|
||||
GetAnnotations(leg_geometry,
|
||||
[](const guidance::LegGeometry::Annotation &anno)
|
||||
{ return anno.datasource; });
|
||||
{ return anno.datasource; }));
|
||||
}
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
|
||||
{
|
||||
@ -837,7 +845,7 @@ class RouteAPI : public BaseAPI
|
||||
nodes.values.push_back(
|
||||
static_cast<std::uint64_t>(facade.GetOSMNodeIDOfNode(node_id)));
|
||||
}
|
||||
annotation.values["nodes"] = std::move(nodes);
|
||||
annotation.values.emplace("nodes", std::move(nodes));
|
||||
}
|
||||
// Add any supporting metadata, if needed
|
||||
if (requested_annotations & RouteParameters::AnnotationsType::Datasources)
|
||||
@ -853,8 +861,8 @@ class RouteAPI : public BaseAPI
|
||||
break;
|
||||
datasource_names.values.push_back(std::string(facade.GetDatasourceName(i)));
|
||||
}
|
||||
metadata.values["datasource_names"] = datasource_names;
|
||||
annotation.values["metadata"] = metadata;
|
||||
metadata.values.emplace("datasource_names", datasource_names);
|
||||
annotation.values.emplace("metadata", metadata);
|
||||
}
|
||||
|
||||
annotations.push_back(std::move(annotation));
|
||||
|
@ -179,7 +179,7 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["sources"] = MakeWaypoints(candidates);
|
||||
response.values.emplace("sources", MakeWaypoints(candidates));
|
||||
}
|
||||
number_of_sources = candidates.size();
|
||||
}
|
||||
@ -187,7 +187,7 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["sources"] = MakeWaypoints(candidates, parameters.sources);
|
||||
response.values.emplace("sources", MakeWaypoints(candidates, parameters.sources));
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["destinations"] = MakeWaypoints(candidates);
|
||||
response.values.emplace("destinations", MakeWaypoints(candidates));
|
||||
}
|
||||
number_of_destinations = candidates.size();
|
||||
}
|
||||
@ -203,34 +203,37 @@ class TableAPI final : public BaseAPI
|
||||
{
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["destinations"] =
|
||||
MakeWaypoints(candidates, parameters.destinations);
|
||||
response.values.emplace("destinations",
|
||||
MakeWaypoints(candidates, parameters.destinations));
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.annotations & TableParameters::AnnotationsType::Duration)
|
||||
{
|
||||
response.values["durations"] =
|
||||
MakeDurationTable(tables.first, number_of_sources, number_of_destinations);
|
||||
response.values.emplace(
|
||||
"durations",
|
||||
MakeDurationTable(tables.first, number_of_sources, number_of_destinations));
|
||||
}
|
||||
|
||||
if (parameters.annotations & TableParameters::AnnotationsType::Distance)
|
||||
{
|
||||
response.values["distances"] =
|
||||
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations);
|
||||
response.values.emplace(
|
||||
"distances",
|
||||
MakeDistanceTable(tables.second, number_of_sources, number_of_destinations));
|
||||
}
|
||||
|
||||
if (parameters.fallback_speed != from_alias<double>(INVALID_FALLBACK_SPEED) &&
|
||||
parameters.fallback_speed > 0)
|
||||
{
|
||||
response.values["fallback_speed_cells"] = MakeEstimatesTable(fallback_speed_cells);
|
||||
response.values.emplace("fallback_speed_cells",
|
||||
MakeEstimatesTable(fallback_speed_cells));
|
||||
}
|
||||
|
||||
response.values["code"] = "Ok";
|
||||
response.values.emplace("code", "Ok");
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
response.values.emplace("data_version", data_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,14 +79,14 @@ class TripAPI final : public RouteAPI
|
||||
}
|
||||
if (!parameters.skip_waypoints)
|
||||
{
|
||||
response.values["waypoints"] = MakeWaypoints(sub_trips, candidates);
|
||||
response.values.emplace("waypoints", MakeWaypoints(sub_trips, candidates));
|
||||
}
|
||||
response.values["trips"] = std::move(routes);
|
||||
response.values["code"] = "Ok";
|
||||
response.values.emplace("trips", std::move(routes));
|
||||
response.values.emplace("code", "Ok");
|
||||
auto data_timestamp = facade.GetTimestamp();
|
||||
if (!data_timestamp.empty())
|
||||
{
|
||||
response.values["data_version"] = data_timestamp;
|
||||
response.values.emplace("data_version", data_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,8 +151,8 @@ class TripAPI final : public RouteAPI
|
||||
BOOST_ASSERT(!trip_index.NotUsed());
|
||||
|
||||
auto waypoint = BaseAPI::MakeWaypoint(candidates[input_index]);
|
||||
waypoint.values["trips_index"] = trip_index.sub_trip_index;
|
||||
waypoint.values["waypoint_index"] = trip_index.point_index;
|
||||
waypoint.values.emplace("trips_index", trip_index.sub_trip_index);
|
||||
waypoint.values.emplace("waypoint_index", trip_index.point_index);
|
||||
waypoints.values.push_back(std::move(waypoint));
|
||||
}
|
||||
|
||||
|
@ -202,8 +202,8 @@ inline double totalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_
|
||||
if (entry_step.geometry_begin > exit_step.geometry_begin)
|
||||
return totalTurnAngle(exit_step, entry_step);
|
||||
|
||||
const auto exit_intersection = exit_step.intersections.front();
|
||||
const auto entry_intersection = entry_step.intersections.front();
|
||||
const auto &exit_intersection = exit_step.intersections.front();
|
||||
const auto &entry_intersection = entry_step.intersections.front();
|
||||
if ((exit_intersection.out >= exit_intersection.bearings.size()) ||
|
||||
(entry_intersection.in >= entry_intersection.bearings.size()))
|
||||
return entry_intersection.bearings[entry_intersection.out];
|
||||
|
@ -4,41 +4,43 @@ import csv
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
def get_osm_gps_traces(min_lon, min_lat, max_lon, max_lat):
|
||||
def get_osm_gps_traces(bboxes):
|
||||
url = 'https://api.openstreetmap.org/api/0.6/trackpoints'
|
||||
traces = []
|
||||
|
||||
lon_step = 0.25
|
||||
lat_step = 0.25
|
||||
|
||||
current_min_lon = min_lon
|
||||
|
||||
while current_min_lon < max_lon:
|
||||
current_max_lon = min(current_min_lon + lon_step, max_lon)
|
||||
for bbox in bboxes:
|
||||
min_lon, min_lat, max_lon, max_lat = map(float, bbox.split(','))
|
||||
|
||||
current_min_lat = min_lat
|
||||
while current_min_lat < max_lat:
|
||||
current_max_lat = min(current_min_lat + lat_step, max_lat)
|
||||
current_min_lon = min_lon
|
||||
while current_min_lon < max_lon:
|
||||
current_max_lon = min(current_min_lon + lon_step, max_lon)
|
||||
|
||||
bbox = f'{current_min_lon},{current_min_lat},{current_max_lon},{current_max_lat}'
|
||||
print(f"Requesting bbox: {bbox}", file=sys.stderr)
|
||||
|
||||
params = {
|
||||
'bbox': bbox,
|
||||
'page': 0
|
||||
}
|
||||
headers = {
|
||||
'Accept': 'application/xml'
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
if response.status_code == 200:
|
||||
traces.append(response.content)
|
||||
else:
|
||||
print(f"Error fetching data for bbox {bbox}: {response.status_code} {response.text}", file=sys.stderr)
|
||||
|
||||
current_min_lat += lat_step
|
||||
current_min_lon += lon_step
|
||||
current_min_lat = min_lat
|
||||
while current_min_lat < max_lat:
|
||||
current_max_lat = min(current_min_lat + lat_step, max_lat)
|
||||
|
||||
bbox_str = f'{current_min_lon},{current_min_lat},{current_max_lon},{current_max_lat}'
|
||||
print(f"Requesting bbox: {bbox_str}", file=sys.stderr)
|
||||
|
||||
params = {
|
||||
'bbox': bbox_str,
|
||||
'page': 0
|
||||
}
|
||||
headers = {
|
||||
'Accept': 'application/xml'
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
if response.status_code == 200:
|
||||
traces.append(response.content)
|
||||
else:
|
||||
print(f"Error fetching data for bbox {bbox_str}: {response.status_code} {response.text}", file=sys.stderr)
|
||||
|
||||
current_min_lat += lat_step
|
||||
current_min_lon += lon_step
|
||||
|
||||
return traces
|
||||
|
||||
@ -68,15 +70,12 @@ def save_to_csv(data, file):
|
||||
writer.writerows(data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Fetch and output OSM GPS traces for a given bounding box.')
|
||||
parser.add_argument('min_lon', type=float, help='Minimum longitude of the bounding box')
|
||||
parser.add_argument('min_lat', type=float, help='Minimum latitude of the bounding box')
|
||||
parser.add_argument('max_lon', type=float, help='Maximum longitude of the bounding box')
|
||||
parser.add_argument('max_lat', type=float, help='Maximum latitude of the bounding box')
|
||||
parser = argparse.ArgumentParser(description='Fetch and output OSM GPS traces for given bounding boxes.')
|
||||
parser.add_argument('bboxes', nargs='+', help='Bounding boxes in the format min_lon,min_lat,max_lon,max_lat')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
gpx_data_traces = get_osm_gps_traces(args.min_lon, args.min_lat, args.max_lon, args.max_lat)
|
||||
gpx_data_traces = get_osm_gps_traces(args.bboxes)
|
||||
print(f"Collected {len(gpx_data_traces)} trace segments", file=sys.stderr)
|
||||
|
||||
all_data = []
|
||||
|
@ -42,6 +42,12 @@ function run_benchmarks_for_folder {
|
||||
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-customize $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_customize.bench"
|
||||
measure_peak_ram_and_time "$BINARIES_FOLDER/osrm-contract $FOLDER/data.osrm" "$RESULTS_FOLDER/osrm_contract.bench"
|
||||
|
||||
for BENCH in nearest table trip route match; do
|
||||
./$BENCHMARKS_FOLDER/bench "$FOLDER/data.osrm" mld ~/gps_traces.csv ${BENCH} > "$RESULTS_FOLDER/random_${BENCH}_mld.bench" || true
|
||||
./$BENCHMARKS_FOLDER/bench "$FOLDER/data.osrm" ch ~/gps_traces.csv ${BENCH} > "$RESULTS_FOLDER/random_${BENCH}_ch.bench" || true
|
||||
done
|
||||
|
||||
|
||||
for ALGORITHM in ch mld; do
|
||||
$BINARIES_FOLDER/osrm-routed --algorithm $ALGORITHM $FOLDER/data.osrm &
|
||||
OSRM_ROUTED_PID=$!
|
||||
@ -59,8 +65,6 @@ function run_benchmarks_for_folder {
|
||||
|
||||
kill -9 $OSRM_ROUTED_PID
|
||||
done
|
||||
|
||||
|
||||
}
|
||||
|
||||
run_benchmarks_for_folder $1 "${1}_results" $2
|
||||
|
@ -18,6 +18,7 @@ target_link_libraries(rtree-bench
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_SHAPEFILE})
|
||||
|
||||
|
||||
add_executable(match-bench
|
||||
EXCLUDE_FROM_ALL
|
||||
${MatchBenchmarkSources}
|
||||
@ -35,6 +36,7 @@ add_executable(route-bench
|
||||
route.cpp
|
||||
$<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
|
||||
target_link_libraries(route-bench
|
||||
osrm
|
||||
${BOOST_BASE_LIBRARIES}
|
||||
@ -42,6 +44,18 @@ target_link_libraries(route-bench
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_SHAPEFILE})
|
||||
|
||||
add_executable(bench
|
||||
EXCLUDE_FROM_ALL
|
||||
bench.cpp
|
||||
$<TARGET_OBJECTS:UTIL>)
|
||||
|
||||
target_link_libraries(bench
|
||||
osrm
|
||||
${BOOST_BASE_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${TBB_LIBRARIES}
|
||||
${MAYBE_SHAPEFILE})
|
||||
|
||||
add_executable(json-render-bench
|
||||
EXCLUDE_FROM_ALL
|
||||
json_render.cpp
|
||||
@ -85,5 +99,6 @@ add_custom_target(benchmarks
|
||||
packedvector-bench
|
||||
match-bench
|
||||
route-bench
|
||||
bench
|
||||
json-render-bench
|
||||
alias-bench)
|
||||
|
573
src/benchmarks/bench.cpp
Normal file
573
src/benchmarks/bench.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
#include "osrm/match_parameters.hpp"
|
||||
#include "osrm/nearest_parameters.hpp"
|
||||
#include "osrm/table_parameters.hpp"
|
||||
#include "osrm/trip_parameters.hpp"
|
||||
|
||||
#include "engine/engine_config.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
#include "osrm/route_parameters.hpp"
|
||||
|
||||
#include "osrm/coordinate.hpp"
|
||||
#include "osrm/engine_config.hpp"
|
||||
#include "osrm/json_container.hpp"
|
||||
|
||||
#include "osrm/osrm.hpp"
|
||||
#include "osrm/status.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace osrm;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class GPSTraces
|
||||
{
|
||||
private:
|
||||
std::set<int> trackIDs;
|
||||
std::unordered_map<int /* track id */, std::vector<osrm::util::Coordinate>> traces;
|
||||
std::vector<osrm::util::Coordinate> coordinates;
|
||||
mutable std::mt19937 gen;
|
||||
|
||||
public:
|
||||
GPSTraces(int seed) : gen(std::random_device{}()) { gen.seed(seed); }
|
||||
|
||||
bool readCSV(const std::string &filename)
|
||||
{
|
||||
std::ifstream file(filename);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << "Error opening file: " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::getline(file, line);
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
std::istringstream ss(line);
|
||||
std::string token;
|
||||
|
||||
int trackID;
|
||||
double latitude, longitude;
|
||||
std::string time;
|
||||
|
||||
std::getline(ss, token, ',');
|
||||
trackID = std::stoi(token);
|
||||
|
||||
std::getline(ss, token, ',');
|
||||
latitude = std::stod(token);
|
||||
|
||||
std::getline(ss, token, ',');
|
||||
longitude = std::stod(token);
|
||||
|
||||
// handle empty fields
|
||||
if (std::getline(ss, token, ','))
|
||||
{
|
||||
time = token;
|
||||
}
|
||||
|
||||
trackIDs.insert(trackID);
|
||||
traces[trackID].emplace_back(osrm::util::Coordinate{
|
||||
osrm::util::FloatLongitude{longitude}, osrm::util::FloatLatitude{latitude}});
|
||||
coordinates.emplace_back(osrm::util::Coordinate{osrm::util::FloatLongitude{longitude},
|
||||
osrm::util::FloatLatitude{latitude}});
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
const osrm::util::Coordinate &getRandomCoordinate() const
|
||||
{
|
||||
std::uniform_int_distribution<> dis(0, coordinates.size() - 1);
|
||||
return coordinates[dis(gen)];
|
||||
}
|
||||
|
||||
const std::vector<osrm::util::Coordinate> &getRandomTrace() const
|
||||
{
|
||||
std::uniform_int_distribution<> dis(0, trackIDs.size() - 1);
|
||||
auto it = trackIDs.begin();
|
||||
std::advance(it, dis(gen));
|
||||
return traces.at(*it);
|
||||
}
|
||||
};
|
||||
|
||||
class Statistics
|
||||
{
|
||||
public:
|
||||
void push(double timeMs)
|
||||
{
|
||||
times.push_back(timeMs);
|
||||
sorted = false;
|
||||
}
|
||||
|
||||
double mean() { return sum() / times.size(); }
|
||||
|
||||
double sum()
|
||||
{
|
||||
double sum = 0;
|
||||
for (auto time : times)
|
||||
{
|
||||
sum += time;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
double min() { return *std::min_element(times.begin(), times.end()); }
|
||||
|
||||
double max() { return *std::max_element(times.begin(), times.end()); }
|
||||
|
||||
double percentile(double p)
|
||||
{
|
||||
const auto × = getTimes();
|
||||
return times[static_cast<size_t>(p * times.size())];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<double> getTimes()
|
||||
{
|
||||
if (!sorted)
|
||||
{
|
||||
std::sort(times.begin(), times.end());
|
||||
sorted = true;
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
std::vector<double> times;
|
||||
|
||||
bool sorted = false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, Statistics &statistics)
|
||||
{
|
||||
os << std::fixed << std::setprecision(2);
|
||||
os << "total: " << statistics.sum() << "ms" << std::endl;
|
||||
os << "avg: " << statistics.mean() << "ms" << std::endl;
|
||||
os << "min: " << statistics.min() << "ms" << std::endl;
|
||||
os << "max: " << statistics.max() << "ms" << std::endl;
|
||||
os << "p99: " << statistics.percentile(0.99) << "ms" << std::endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
void runRouteBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
|
||||
{
|
||||
struct Benchmark
|
||||
{
|
||||
std::string name;
|
||||
size_t coordinates;
|
||||
RouteParameters::OverviewType overview;
|
||||
bool steps = false;
|
||||
std::optional<size_t> alternatives = std::nullopt;
|
||||
std::optional<double> radius = std::nullopt;
|
||||
};
|
||||
|
||||
auto run_benchmark = [&](const Benchmark &benchmark)
|
||||
{
|
||||
Statistics statistics;
|
||||
|
||||
auto NUM = 10000;
|
||||
for (int i = 0; i < NUM; ++i)
|
||||
{
|
||||
RouteParameters params;
|
||||
params.overview = benchmark.overview;
|
||||
params.steps = benchmark.steps;
|
||||
|
||||
for (size_t i = 0; i < benchmark.coordinates; ++i)
|
||||
{
|
||||
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
|
||||
}
|
||||
|
||||
if (benchmark.alternatives)
|
||||
{
|
||||
params.alternatives = *benchmark.alternatives;
|
||||
}
|
||||
|
||||
if (benchmark.radius)
|
||||
{
|
||||
params.radiuses = std::vector<boost::optional<double>>(
|
||||
params.coordinates.size(), boost::make_optional(*benchmark.radius));
|
||||
}
|
||||
|
||||
engine::api::ResultT result = json::Object();
|
||||
TIMER_START(routes);
|
||||
const auto rc = osrm.Route(params, result);
|
||||
TIMER_STOP(routes);
|
||||
|
||||
statistics.push(TIMER_MSEC(routes));
|
||||
|
||||
auto &json_result = std::get<json::Object>(result);
|
||||
if (rc != Status::Ok || json_result.values.find("routes") == json_result.values.end())
|
||||
{
|
||||
auto code = std::get<json::String>(json_result.values["code"]).value;
|
||||
if (code != "NoSegment" && code != "NoRoute")
|
||||
{
|
||||
throw std::runtime_error{"Couldn't route: " + code};
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << benchmark.name << std::endl;
|
||||
std::cout << statistics << std::endl;
|
||||
};
|
||||
|
||||
std::vector<Benchmark> benchmarks = {
|
||||
{"10000 routes, 3 coordinates, no alternatives, overview=full, steps=true",
|
||||
3,
|
||||
RouteParameters::OverviewType::Full,
|
||||
true,
|
||||
std::nullopt},
|
||||
{"10000 routes, 2 coordinates, no alternatives, overview=full, steps=true",
|
||||
2,
|
||||
RouteParameters::OverviewType::Full,
|
||||
true,
|
||||
std::nullopt},
|
||||
{"10000 routes, 2 coordinates, 3 alternatives, overview=full, steps=true",
|
||||
2,
|
||||
RouteParameters::OverviewType::Full,
|
||||
true,
|
||||
3},
|
||||
{"10000 routes, 3 coordinates, no alternatives, overview=false, steps=false",
|
||||
3,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
std::nullopt},
|
||||
{"10000 routes, 2 coordinates, no alternatives, overview=false, steps=false",
|
||||
2,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
std::nullopt},
|
||||
{"10000 routes, 2 coordinates, 3 alternatives, overview=false, steps=false",
|
||||
2,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
3},
|
||||
{"10000 routes, 3 coordinates, no alternatives, overview=false, steps=false, radius=750",
|
||||
3,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
std::nullopt,
|
||||
750},
|
||||
{"10000 routes, 2 coordinates, no alternatives, overview=false, steps=false, radius=750",
|
||||
2,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
std::nullopt,
|
||||
750},
|
||||
{"10000 routes, 2 coordinates, 3 alternatives, overview=false, steps=false, radius=750",
|
||||
2,
|
||||
RouteParameters::OverviewType::False,
|
||||
false,
|
||||
3,
|
||||
750}
|
||||
|
||||
};
|
||||
|
||||
for (const auto &benchmark : benchmarks)
|
||||
{
|
||||
run_benchmark(benchmark);
|
||||
}
|
||||
}
|
||||
|
||||
void runMatchBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
|
||||
{
|
||||
struct Benchmark
|
||||
{
|
||||
std::string name;
|
||||
std::optional<size_t> radius = std::nullopt;
|
||||
};
|
||||
|
||||
auto run_benchmark = [&](const Benchmark &benchmark)
|
||||
{
|
||||
Statistics statistics;
|
||||
|
||||
auto NUM = 1000;
|
||||
for (int i = 0; i < NUM; ++i)
|
||||
{
|
||||
engine::api::ResultT result = json::Object();
|
||||
|
||||
engine::api::MatchParameters params;
|
||||
params.coordinates = gpsTraces.getRandomTrace();
|
||||
params.radiuses = {};
|
||||
if (benchmark.radius)
|
||||
{
|
||||
for (size_t index = 0; index < params.coordinates.size(); ++index)
|
||||
{
|
||||
params.radiuses.emplace_back(*benchmark.radius);
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_START(match);
|
||||
const auto rc = osrm.Match(params, result);
|
||||
TIMER_STOP(match);
|
||||
|
||||
statistics.push(TIMER_MSEC(match));
|
||||
|
||||
auto &json_result = std::get<json::Object>(result);
|
||||
if (rc != Status::Ok ||
|
||||
json_result.values.find("matchings") == json_result.values.end())
|
||||
{
|
||||
auto code = std::get<json::String>(json_result.values["code"]).value;
|
||||
if (code != "NoSegment" && code != "NoMatch")
|
||||
{
|
||||
throw std::runtime_error{"Couldn't route: " + code};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << benchmark.name << std::endl;
|
||||
std::cout << statistics << std::endl;
|
||||
};
|
||||
|
||||
std::vector<Benchmark> benchmarks = {{"1000 matches, default radius"},
|
||||
{"1000 matches, radius=10", 10},
|
||||
{"1000 matches, radius=20", 20}};
|
||||
|
||||
for (const auto &benchmark : benchmarks)
|
||||
{
|
||||
run_benchmark(benchmark);
|
||||
}
|
||||
}
|
||||
|
||||
void runNearestBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
|
||||
{
|
||||
struct Benchmark
|
||||
{
|
||||
std::string name;
|
||||
std::optional<size_t> number_of_results = std::nullopt;
|
||||
};
|
||||
|
||||
auto run_benchmark = [&](const Benchmark &benchmark)
|
||||
{
|
||||
Statistics statistics;
|
||||
auto NUM = 10000;
|
||||
for (int i = 0; i < NUM; ++i)
|
||||
{
|
||||
engine::api::ResultT result = json::Object();
|
||||
NearestParameters params;
|
||||
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
|
||||
|
||||
if (benchmark.number_of_results)
|
||||
{
|
||||
params.number_of_results = *benchmark.number_of_results;
|
||||
}
|
||||
|
||||
TIMER_START(nearest);
|
||||
const auto rc = osrm.Nearest(params, result);
|
||||
TIMER_STOP(nearest);
|
||||
|
||||
statistics.push(TIMER_MSEC(nearest));
|
||||
|
||||
auto &json_result = std::get<json::Object>(result);
|
||||
if (rc != Status::Ok ||
|
||||
json_result.values.find("waypoints") == json_result.values.end())
|
||||
{
|
||||
auto code = std::get<json::String>(json_result.values["code"]).value;
|
||||
if (code != "NoSegment")
|
||||
{
|
||||
throw std::runtime_error{"Couldn't find nearest point"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << benchmark.name << std::endl;
|
||||
std::cout << statistics << std::endl;
|
||||
};
|
||||
|
||||
std::vector<Benchmark> benchmarks = {{"10000 nearest, number_of_results=1", 1},
|
||||
{"10000 nearest, number_of_results=5", 5},
|
||||
{"10000 nearest, number_of_results=10", 10}};
|
||||
|
||||
for (const auto &benchmark : benchmarks)
|
||||
{
|
||||
run_benchmark(benchmark);
|
||||
}
|
||||
}
|
||||
|
||||
void runTripBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
|
||||
{
|
||||
struct Benchmark
|
||||
{
|
||||
std::string name;
|
||||
size_t coordinates;
|
||||
};
|
||||
|
||||
auto run_benchmark = [&](const Benchmark &benchmark)
|
||||
{
|
||||
Statistics statistics;
|
||||
auto NUM = 1000;
|
||||
for (int i = 0; i < NUM; ++i)
|
||||
{
|
||||
engine::api::ResultT result = json::Object();
|
||||
TripParameters params;
|
||||
params.roundtrip = true;
|
||||
|
||||
for (size_t i = 0; i < benchmark.coordinates; ++i)
|
||||
{
|
||||
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
|
||||
}
|
||||
|
||||
TIMER_START(trip);
|
||||
const auto rc = osrm.Trip(params, result);
|
||||
TIMER_STOP(trip);
|
||||
|
||||
statistics.push(TIMER_MSEC(trip));
|
||||
|
||||
auto &json_result = std::get<json::Object>(result);
|
||||
if (rc != Status::Ok || json_result.values.find("trips") == json_result.values.end())
|
||||
{
|
||||
auto code = std::get<json::String>(json_result.values["code"]).value;
|
||||
if (code != "NoSegment")
|
||||
{
|
||||
throw std::runtime_error{"Couldn't find trip"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << benchmark.name << std::endl;
|
||||
std::cout << statistics << std::endl;
|
||||
};
|
||||
|
||||
std::vector<Benchmark> benchmarks = {
|
||||
{"1000 trips, 3 coordinates", 3},
|
||||
{"1000 trips, 4 coordinates", 4},
|
||||
{"1000 trips, 5 coordinates", 5},
|
||||
};
|
||||
|
||||
for (const auto &benchmark : benchmarks)
|
||||
{
|
||||
run_benchmark(benchmark);
|
||||
}
|
||||
}
|
||||
void runTableBenchmark(const OSRM &osrm, const GPSTraces &gpsTraces)
|
||||
{
|
||||
struct Benchmark
|
||||
{
|
||||
std::string name;
|
||||
size_t coordinates;
|
||||
};
|
||||
|
||||
auto run_benchmark = [&](const Benchmark &benchmark)
|
||||
{
|
||||
Statistics statistics;
|
||||
auto NUM = 250;
|
||||
for (int i = 0; i < NUM; ++i)
|
||||
{
|
||||
engine::api::ResultT result = json::Object();
|
||||
TableParameters params;
|
||||
|
||||
for (size_t i = 0; i < benchmark.coordinates; ++i)
|
||||
{
|
||||
params.coordinates.push_back(gpsTraces.getRandomCoordinate());
|
||||
}
|
||||
|
||||
TIMER_START(table);
|
||||
const auto rc = osrm.Table(params, result);
|
||||
TIMER_STOP(table);
|
||||
|
||||
statistics.push(TIMER_MSEC(table));
|
||||
|
||||
auto &json_result = std::get<json::Object>(result);
|
||||
if (rc != Status::Ok ||
|
||||
json_result.values.find("durations") == json_result.values.end())
|
||||
{
|
||||
auto code = std::get<json::String>(json_result.values["code"]).value;
|
||||
if (code != "NoSegment")
|
||||
{
|
||||
throw std::runtime_error{"Couldn't compute table"};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << benchmark.name << std::endl;
|
||||
std::cout << statistics << std::endl;
|
||||
};
|
||||
|
||||
std::vector<Benchmark> benchmarks = {{"250 tables, 3 coordinates", 3},
|
||||
{"250 tables, 25 coordinates", 25},
|
||||
{"250 tables, 50 coordinates", 50},
|
||||
{"250 tables, 100 coordinates", 100}};
|
||||
|
||||
for (const auto &benchmark : benchmarks)
|
||||
{
|
||||
run_benchmark(benchmark);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
try
|
||||
{
|
||||
if (argc < 5)
|
||||
{
|
||||
std::cerr
|
||||
<< "Usage: " << argv[0]
|
||||
<< " data.osrm <mld|ch> <path to GPS traces.csv> <route|match|trip|table|nearest>\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Configure based on a .osrm base path, and no datasets in shared mem from osrm-datastore
|
||||
EngineConfig config;
|
||||
config.storage_config = {argv[1]};
|
||||
config.algorithm =
|
||||
std::string{argv[2]} == "mld" ? EngineConfig::Algorithm::MLD : EngineConfig::Algorithm::CH;
|
||||
config.use_shared_memory = false;
|
||||
|
||||
// Routing machine with several services (such as Route, Table, Nearest, Trip, Match)
|
||||
OSRM osrm{config};
|
||||
|
||||
GPSTraces gpsTraces{42};
|
||||
gpsTraces.readCSV(argv[3]);
|
||||
|
||||
const auto benchmarkToRun = std::string{argv[4]};
|
||||
|
||||
if (benchmarkToRun == "route")
|
||||
{
|
||||
runRouteBenchmark(osrm, gpsTraces);
|
||||
}
|
||||
else if (benchmarkToRun == "match")
|
||||
{
|
||||
runMatchBenchmark(osrm, gpsTraces);
|
||||
}
|
||||
else if (benchmarkToRun == "nearest")
|
||||
{
|
||||
runNearestBenchmark(osrm, gpsTraces);
|
||||
}
|
||||
else if (benchmarkToRun == "trip")
|
||||
{
|
||||
runTripBenchmark(osrm, gpsTraces);
|
||||
}
|
||||
else if (benchmarkToRun == "table")
|
||||
{
|
||||
runTableBenchmark(osrm, gpsTraces);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown benchmark: " << benchmarkToRun << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
@ -44,21 +44,22 @@ util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection
|
||||
{
|
||||
BOOST_ASSERT(intersection.lanes.lanes_in_turn >= 1);
|
||||
util::json::Array result;
|
||||
result.values.reserve(intersection.lane_description.size());
|
||||
LaneID lane_id = intersection.lane_description.size();
|
||||
|
||||
for (const auto &lane_desc : intersection.lane_description)
|
||||
{
|
||||
--lane_id;
|
||||
util::json::Object lane;
|
||||
lane.values["indications"] = toJSON(lane_desc);
|
||||
lane.values.emplace("indications", toJSON(lane_desc));
|
||||
if (lane_id >= intersection.lanes.first_lane_from_the_right &&
|
||||
lane_id <
|
||||
intersection.lanes.first_lane_from_the_right + intersection.lanes.lanes_in_turn)
|
||||
lane.values["valid"] = util::json::True();
|
||||
lane.values.emplace("valid", util::json::True());
|
||||
else
|
||||
lane.values["valid"] = util::json::False();
|
||||
lane.values.emplace("valid", util::json::False());
|
||||
|
||||
result.values.push_back(lane);
|
||||
result.values.emplace_back(std::move(lane));
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -77,6 +78,7 @@ std::string waypointTypeToString(const guidance::WaypointType waypoint_type)
|
||||
util::json::Value coordinateToLonLat(const util::Coordinate &coordinate)
|
||||
{
|
||||
util::json::Array array;
|
||||
array.values.reserve(2);
|
||||
array.values.push_back(static_cast<double>(util::toFloating(coordinate.lon)));
|
||||
array.values.push_back(static_cast<double>(util::toFloating(coordinate.lat)));
|
||||
return util::json::Value{std::move(array)};
|
||||
@ -98,17 +100,20 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
|
||||
// These invalid responses should never happen: log if they do happen
|
||||
BOOST_ASSERT_MSG(maneuver_type != "invalid", "unexpected invalid maneuver type");
|
||||
|
||||
step_maneuver.values["type"] = std::move(maneuver_type);
|
||||
step_maneuver.values.emplace("type", std::move(maneuver_type));
|
||||
|
||||
if (detail::isValidModifier(maneuver))
|
||||
step_maneuver.values["modifier"] =
|
||||
osrm::guidance::instructionModifierToString(maneuver.instruction.direction_modifier);
|
||||
step_maneuver.values.emplace(
|
||||
"modifier",
|
||||
osrm::guidance::instructionModifierToString(maneuver.instruction.direction_modifier));
|
||||
|
||||
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
|
||||
step_maneuver.values["bearing_before"] = detail::roundAndClampBearing(maneuver.bearing_before);
|
||||
step_maneuver.values["bearing_after"] = detail::roundAndClampBearing(maneuver.bearing_after);
|
||||
step_maneuver.values.emplace("location", detail::coordinateToLonLat(maneuver.location));
|
||||
step_maneuver.values.emplace("bearing_before",
|
||||
detail::roundAndClampBearing(maneuver.bearing_before));
|
||||
step_maneuver.values.emplace("bearing_after",
|
||||
detail::roundAndClampBearing(maneuver.bearing_after));
|
||||
if (maneuver.exit != 0)
|
||||
step_maneuver.values["exit"] = maneuver.exit;
|
||||
step_maneuver.values.emplace("exit", maneuver.exit);
|
||||
|
||||
return step_maneuver;
|
||||
}
|
||||
@ -137,16 +142,16 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
|
||||
return util::json::False();
|
||||
});
|
||||
|
||||
result.values["location"] = detail::coordinateToLonLat(intersection.location);
|
||||
result.values["bearings"] = bearings;
|
||||
result.values["entry"] = entry;
|
||||
result.values.emplace("location", detail::coordinateToLonLat(intersection.location));
|
||||
result.values.emplace("bearings", bearings);
|
||||
result.values.emplace("entry", entry);
|
||||
if (intersection.in != guidance::IntermediateIntersection::NO_INDEX)
|
||||
result.values["in"] = intersection.in;
|
||||
result.values.emplace("in", intersection.in);
|
||||
if (intersection.out != guidance::IntermediateIntersection::NO_INDEX)
|
||||
result.values["out"] = intersection.out;
|
||||
result.values.emplace("out", intersection.out);
|
||||
|
||||
if (detail::hasValidLanes(intersection))
|
||||
result.values["lanes"] = detail::lanesFromIntersection(intersection);
|
||||
result.values.emplace("lanes", detail::lanesFromIntersection(intersection));
|
||||
|
||||
if (!intersection.classes.empty())
|
||||
{
|
||||
@ -157,7 +162,7 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
|
||||
std::back_inserter(classes.values),
|
||||
[](const std::string &class_name)
|
||||
{ return util::json::String{class_name}; });
|
||||
result.values["classes"] = std::move(classes);
|
||||
result.values.emplace("classes", std::move(classes));
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -166,39 +171,44 @@ util::json::Object makeIntersection(const guidance::IntermediateIntersection &in
|
||||
util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geometry)
|
||||
{
|
||||
util::json::Object route_step;
|
||||
route_step.values["distance"] = std::round(step.distance * 10) / 10.;
|
||||
route_step.values["duration"] = step.duration;
|
||||
route_step.values["weight"] = step.weight;
|
||||
route_step.values["name"] = std::move(step.name);
|
||||
route_step.values.reserve(15);
|
||||
|
||||
route_step.values.emplace("distance", std::round(step.distance * 10) / 10.);
|
||||
route_step.values.emplace("duration", step.duration);
|
||||
route_step.values.emplace("weight", step.weight);
|
||||
route_step.values.emplace("name", step.name);
|
||||
|
||||
if (!step.ref.empty())
|
||||
route_step.values["ref"] = std::move(step.ref);
|
||||
route_step.values.emplace("ref", step.ref);
|
||||
if (!step.pronunciation.empty())
|
||||
route_step.values["pronunciation"] = std::move(step.pronunciation);
|
||||
route_step.values.emplace("pronunciation", step.pronunciation);
|
||||
if (!step.destinations.empty())
|
||||
route_step.values["destinations"] = std::move(step.destinations);
|
||||
route_step.values.emplace("destinations", step.destinations);
|
||||
if (!step.exits.empty())
|
||||
route_step.values["exits"] = std::move(step.exits);
|
||||
route_step.values.emplace("exits", step.exits);
|
||||
if (!step.rotary_name.empty())
|
||||
{
|
||||
route_step.values["rotary_name"] = std::move(step.rotary_name);
|
||||
route_step.values.emplace("rotary_name", step.rotary_name);
|
||||
if (!step.rotary_pronunciation.empty())
|
||||
{
|
||||
route_step.values["rotary_pronunciation"] = std::move(step.rotary_pronunciation);
|
||||
route_step.values.emplace("rotary_pronunciation", step.rotary_pronunciation);
|
||||
}
|
||||
}
|
||||
|
||||
route_step.values["mode"] = extractor::travelModeToString(step.mode);
|
||||
route_step.values["maneuver"] = makeStepManeuver(step.maneuver);
|
||||
route_step.values["geometry"] = std::move(geometry);
|
||||
route_step.values["driving_side"] = step.is_left_hand_driving ? "left" : "right";
|
||||
route_step.values.emplace("mode", extractor::travelModeToString(step.mode));
|
||||
route_step.values.emplace("maneuver", makeStepManeuver(step.maneuver));
|
||||
route_step.values.emplace("geometry", std::move(geometry));
|
||||
route_step.values.emplace("driving_side", step.is_left_hand_driving ? "left" : "right");
|
||||
|
||||
util::json::Array intersections;
|
||||
intersections.values.reserve(step.intersections.size());
|
||||
|
||||
std::transform(step.intersections.begin(),
|
||||
step.intersections.end(),
|
||||
std::back_inserter(intersections.values),
|
||||
makeIntersection);
|
||||
route_step.values["intersections"] = std::move(intersections);
|
||||
|
||||
route_step.values.emplace("intersections", std::move(intersections));
|
||||
|
||||
return route_step;
|
||||
}
|
||||
@ -209,14 +219,16 @@ util::json::Object makeRoute(const guidance::Route &route,
|
||||
const char *weight_name)
|
||||
{
|
||||
util::json::Object json_route;
|
||||
json_route.values["distance"] = route.distance;
|
||||
json_route.values["duration"] = route.duration;
|
||||
json_route.values["weight"] = route.weight;
|
||||
json_route.values["weight_name"] = weight_name;
|
||||
json_route.values["legs"] = std::move(legs);
|
||||
json_route.values.reserve(6);
|
||||
|
||||
json_route.values.emplace("distance", route.distance);
|
||||
json_route.values.emplace("duration", route.duration);
|
||||
json_route.values.emplace("weight", route.weight);
|
||||
json_route.values.emplace("weight_name", weight_name);
|
||||
json_route.values.emplace("legs", std::move(legs));
|
||||
if (geometry)
|
||||
{
|
||||
json_route.values["geometry"] = *std::move(geometry);
|
||||
json_route.values.emplace("geometry", *std::move(geometry));
|
||||
}
|
||||
return json_route;
|
||||
}
|
||||
@ -225,9 +237,11 @@ util::json::Object
|
||||
makeWaypoint(const util::Coordinate &location, const double &distance, std::string name)
|
||||
{
|
||||
util::json::Object waypoint;
|
||||
waypoint.values["location"] = detail::coordinateToLonLat(location);
|
||||
waypoint.values["name"] = std::move(name);
|
||||
waypoint.values["distance"] = distance;
|
||||
waypoint.values.reserve(3);
|
||||
|
||||
waypoint.values.emplace("location", detail::coordinateToLonLat(location));
|
||||
waypoint.values.emplace("name", std::move(name));
|
||||
waypoint.values.emplace("distance", distance);
|
||||
return waypoint;
|
||||
}
|
||||
|
||||
@ -237,26 +251,29 @@ util::json::Object makeWaypoint(const util::Coordinate &location,
|
||||
const Hint &location_hints)
|
||||
{
|
||||
auto waypoint = makeWaypoint(location, distance, std::move(name));
|
||||
waypoint.values["hint"] = location_hints.ToBase64();
|
||||
waypoint.values.reserve(1);
|
||||
waypoint.values.emplace("hint", location_hints.ToBase64());
|
||||
return waypoint;
|
||||
}
|
||||
|
||||
util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps)
|
||||
{
|
||||
util::json::Object route_leg;
|
||||
route_leg.values["distance"] = leg.distance;
|
||||
route_leg.values["duration"] = leg.duration;
|
||||
route_leg.values["weight"] = leg.weight;
|
||||
route_leg.values["summary"] = std::move(leg.summary);
|
||||
route_leg.values["steps"] = std::move(steps);
|
||||
route_leg.values.reserve(5);
|
||||
|
||||
route_leg.values.emplace("distance", leg.distance);
|
||||
route_leg.values.emplace("duration", leg.duration);
|
||||
route_leg.values.emplace("weight", leg.weight);
|
||||
route_leg.values.emplace("summary", std::move(leg.summary));
|
||||
route_leg.values.emplace("steps", std::move(steps));
|
||||
return route_leg;
|
||||
}
|
||||
|
||||
util::json::Object
|
||||
makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps, util::json::Object annotation)
|
||||
{
|
||||
util::json::Object route_leg = makeRouteLeg(std::move(leg), std::move(steps));
|
||||
route_leg.values["annotation"] = std::move(annotation);
|
||||
route_leg.values.reserve(1);
|
||||
route_leg.values.emplace("annotation", std::move(annotation));
|
||||
return route_leg;
|
||||
}
|
||||
|
||||
|
BIN
test/data/poland_gps_traces.csv.gz
Normal file
BIN
test/data/poland_gps_traces.csv.gz
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user