diff options
author | Constantin Shalnev <c.shalnev@corp.mail.ru> | 2015-05-22 13:44:42 +0300 |
---|---|---|
committer | Alex Zolotarev <alex@maps.me> | 2015-09-23 02:48:33 +0300 |
commit | 3ac8580696edf59736c2a7fc693cf65a44ad43a9 (patch) | |
tree | 7f43ef61de6b3b242bd7e6f2b724c5d38b17a143 | |
parent | d9f4d6994d738c7ffff01696bdc229a7579e0810 (diff) |
Send statistics about pedestrian routing
-rw-r--r-- | map/framework.cpp | 28 | ||||
-rw-r--r-- | map/routing_session.cpp | 4 | ||||
-rw-r--r-- | map/routing_session.hpp | 8 | ||||
-rw-r--r-- | routing/async_router.cpp | 110 | ||||
-rw-r--r-- | routing/async_router.hpp | 28 | ||||
-rw-r--r-- | routing/osrm_online_router.cpp | 4 | ||||
-rw-r--r-- | routing/osrm_online_router.hpp | 4 | ||||
-rw-r--r-- | routing/road_graph_router.cpp | 11 |
8 files changed, 158 insertions, 39 deletions
diff --git a/map/framework.cpp b/map/framework.cpp index 8e4f857acf..cad0c3c5ac 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -2230,7 +2230,7 @@ void Framework::FollowRoute() void Framework::SetRouter(RouterType type) { #ifdef DEBUG - RoutingVisualizerFn const routingVisualizer = [this](m2::PointD const & pt) + RoutingVisualizerFn const routingVisualizerFn = [this](m2::PointD const & pt) { GetPlatform().RunOnGuiThread([this,pt]() { @@ -2239,25 +2239,33 @@ void Framework::SetRouter(RouterType type) }); }; #else - RoutingVisualizerFn const routingVisualizer = nullptr; + RoutingVisualizerFn const routingVisualizerFn = nullptr; #endif + auto const routingStatisticsFn = [](map<string, string> const & statistics) + { + alohalytics::LogEvent("Routing_CalculatingRoute", statistics); + }; + + unique_ptr<IRouter> router; if (type == RouterType::Pedestrian) { - m_routingSession.SetRouter( - unique_ptr<IRouter>(new AStarRouter([this](m2::PointD const & pt) - { - return GetSearchEngine()->GetCountryFile(pt) + DATA_FILE_EXTENSION; - }, - &m_model.GetIndex(), routingVisualizer))); + auto const countryFileFn = [this](m2::PointD const & pt) + { + return GetSearchEngine()->GetCountryFile(pt) + DATA_FILE_EXTENSION; + }; + router.reset(new AStarRouter(countryFileFn, &m_model.GetIndex(), routingVisualizerFn)); } else { - m_routingSession.SetRouter(unique_ptr<IRouter>(new OsrmRouter(&m_model.GetIndex(), [this] (m2::PointD const & pt) + auto const countryFileFn = [this](m2::PointD const & pt) { return GetSearchEngine()->GetCountryFile(pt); - }, routingVisualizer))); + }; + router.reset(new OsrmRouter(&m_model.GetIndex(), countryFileFn, routingVisualizerFn)); } + + m_routingSession.SetRouter(move(router), routingStatisticsFn); } void Framework::RemoveRoute() diff --git a/map/routing_session.cpp b/map/routing_session.cpp index 493673b5c8..75b56ed1de 100644 --- a/map/routing_session.cpp +++ b/map/routing_session.cpp @@ -206,9 +206,9 @@ void RoutingSession::AssignRoute(Route & route) m_route.Swap(route); } -void RoutingSession::SetRouter(unique_ptr<IRouter> && router) +void RoutingSession::SetRouter(unique_ptr<IRouter> && router, TRoutingStatisticsCallback const & routingStatisticsFn) { - m_router.reset(new AsyncRouter(move(router))); + m_router.reset(new AsyncRouter(move(router), routingStatisticsFn)); } void RoutingSession::DeleteIndexFile(string const & fileName) diff --git a/map/routing_session.hpp b/map/routing_session.hpp index 044f1bc1d1..2f900a0b9f 100644 --- a/map/routing_session.hpp +++ b/map/routing_session.hpp @@ -45,11 +45,15 @@ public: * RouteFinished -> RouteNotReady // start new route */ - RoutingSession(); - void SetRouter(unique_ptr<IRouter> && router); + typedef function<void(map<string, string> const &)> TRoutingStatisticsCallback; typedef function<void (Route const &, IRouter::ResultCode)> TReadyCallbackFn; + RoutingSession(); + + void SetRouter(unique_ptr<IRouter> && router, + TRoutingStatisticsCallback const & routingStatisticsFn); + /// @param[in] startPoint and endPoint in mercator void BuildRoute(m2::PointD const & startPoint, m2::PointD const & endPoint, TReadyCallbackFn const & callback); void RebuildRoute(m2::PointD const & startPoint, TReadyCallbackFn const & callback); diff --git a/routing/async_router.cpp b/routing/async_router.cpp index 7f3f037dff..6adddc6379 100644 --- a/routing/async_router.cpp +++ b/routing/async_router.cpp @@ -1,13 +1,67 @@ #include "routing/async_router.hpp" #include "platform/platform.hpp" -#include "base/macros.hpp" + #include "base/logging.hpp" +#include "base/macros.hpp" +#include "base/string_utils.hpp" +#include "base/timer.hpp" + +#include "indexer/mercator.hpp" namespace routing { -AsyncRouter::AsyncRouter(unique_ptr<IRouter> && router) : m_router(move(router)) +namespace +{ + +string ToString(IRouter::ResultCode code) +{ + switch (code) + { + case IRouter::NoError: return "NoError"; + case IRouter::Cancelled: return "Cancelled"; + case IRouter::NoCurrentPosition: return "NoCurrentPosition"; + case IRouter::InconsistentMWMandRoute: return "InconsistentMWMandRoute"; + case IRouter::RouteFileNotExist: return "RouteFileNotExist"; + case IRouter::StartPointNotFound: return "StartPointNotFound"; + case IRouter::EndPointNotFound: return "EndPointNotFound"; + case IRouter::PointsInDifferentMWM: return "PointsInDifferentMWM"; + case IRouter::RouteNotFound: return "RouteNotFound"; + case IRouter::InternalError: return "InternalError"; + default: + { + ASSERT(false, ("Unknown IRouter::ResultCode value ", code)); + ostringstream o; + o << "UnknownResultCode(" << static_cast<unsigned int>(code) << ")"; + return o.str(); + } + } +} + +map<string, string> PrepareStatisticsData(string const & routerName, + m2::PointD const & startPoint, m2::PointD const & startDirection, + m2::PointD const & finalPoint) +{ + // Coordinates precision in 5 digits after comma corresponds to metres (0,00001degree ~ 1meter), + // therefore we round coordinates up to 5 digits after comma. + int constexpr precision = 5; + + return {{"name", routerName}, + {"startLon", strings::to_string_dac(MercatorBounds::XToLon(startPoint.x), precision)}, + {"startLat", strings::to_string_dac(MercatorBounds::YToLat(startPoint.y), precision)}, + {"startDirectionX", strings::to_string_dac(startDirection.x, precision)}, + {"startDirectionY", strings::to_string_dac(startDirection.y, precision)}, + {"finalLon", strings::to_string_dac(MercatorBounds::XToLon(finalPoint.x), precision)}, + {"finalLat", strings::to_string_dac(MercatorBounds::YToLat(finalPoint.y), precision)}}; +} + +} // namespace + +AsyncRouter::AsyncRouter(unique_ptr<IRouter> && router, + TRoutingStatisticsCallback const & routingStatisticsFn) + : m_router(move(router)) + , m_routingStatisticsFn(routingStatisticsFn) { m_isReadyThread.clear(); } @@ -15,7 +69,7 @@ AsyncRouter::AsyncRouter(unique_ptr<IRouter> && router) : m_router(move(router)) AsyncRouter::~AsyncRouter() { ClearState(); } void AsyncRouter::CalculateRoute(m2::PointD const & startPoint, m2::PointD const & direction, - m2::PointD const & finalPoint, ReadyCallback const & callback) + m2::PointD const & finalPoint, TReadyCallback const & callback) { ASSERT(m_router, ()); { @@ -41,7 +95,7 @@ void AsyncRouter::ClearState() m_router->ClearState(); } -void AsyncRouter::CalculateRouteImpl(ReadyCallback const & callback) +void AsyncRouter::CalculateRouteImpl(TReadyCallback const & callback) { if (m_isReadyThread.test_and_set()) return; @@ -66,7 +120,15 @@ void AsyncRouter::CalculateRouteImpl(ReadyCallback const & callback) try { + LOG(LDEBUG, ("Calculating the route from", startPoint, "to", finalPoint, "startDirection", startDirection)); + + my::Timer timer; + timer.Reset(); + code = m_router->CalculateRoute(startPoint, startDirection, finalPoint, route); + + double const elapsedSec = timer.ElapsedSeconds(); + switch (code) { case IRouter::StartPointNotFound: @@ -82,21 +144,59 @@ void AsyncRouter::CalculateRouteImpl(ReadyCallback const & callback) LOG(LWARNING, ("Route not found")); break; case IRouter::RouteFileNotExist: - LOG(LWARNING, ("There are no routing file")); + LOG(LWARNING, ("There is no routing file")); + break; + case IRouter::Cancelled: + LOG(LINFO, ("Route calculation cancelled, elapsed seconds:", elapsedSec)); + break; + case IRouter::NoError: + LOG(LINFO, ("Route found, elapsed seconds:", elapsedSec)); break; default: break; } + + SendStatistics(startPoint, startDirection, finalPoint, code, elapsedSec); } catch (Reader::Exception const & e) { LOG(LERROR, ("Routing index is absent or incorrect. Error while loading routing index:", e.Msg())); code = IRouter::InternalError; + + SendStatistics(startPoint, startDirection, finalPoint, e.Msg()); } GetPlatform().RunOnGuiThread(bind(callback, route, code)); } +void AsyncRouter::SendStatistics(m2::PointD const & startPoint, m2::PointD const & startDirection, + m2::PointD const & finalPoint, + IRouter::ResultCode resultCode, + double elapsedSec) +{ + if (nullptr == m_routingStatisticsFn) + return; + + map<string, string> statistics = PrepareStatisticsData(m_router->GetName(), startPoint, startDirection, finalPoint); + statistics.emplace("result", ToString(resultCode)); + statistics.emplace("elapsed", strings::to_string(elapsedSec)); + + m_routingStatisticsFn(statistics); +} + +void AsyncRouter::SendStatistics(m2::PointD const & startPoint, m2::PointD const & startDirection, + m2::PointD const & finalPoint, + string const & exceptionMessage) +{ + if (nullptr == m_routingStatisticsFn) + return; + + map<string, string> statistics = PrepareStatisticsData(m_router->GetName(), startPoint, startDirection, finalPoint); + statistics.emplace("exception", exceptionMessage); + + m_routingStatisticsFn(statistics); +} + } // namespace routing diff --git a/routing/async_router.hpp b/routing/async_router.hpp index 6607621f9b..dc934ffb33 100644 --- a/routing/async_router.hpp +++ b/routing/async_router.hpp @@ -4,22 +4,28 @@ #include "routing/router.hpp" #include "std/atomic.hpp" +#include "std/map.hpp" #include "std/mutex.hpp" +#include "std/string.hpp" #include "std/unique_ptr.hpp" namespace routing { -/// Callback takes ownership of passed route. -typedef function<void(Route &, IRouter::ResultCode)> ReadyCallback; - class AsyncRouter { public: + /// Callback takes ownership of passed route. + typedef function<void(Route &, IRouter::ResultCode)> TReadyCallback; + + /// Callback on routing statistics + typedef function<void(map<string, string> const &)> TRoutingStatisticsCallback; + /// AsyncRouter is a wrapper class to run routing routines in the different thread /// @param router pointer to the router implementation. AsyncRouter will take ownership over /// router. - AsyncRouter(unique_ptr<IRouter> && router); + AsyncRouter(unique_ptr<IRouter> && router, + TRoutingStatisticsCallback const & routingStatisticsFn); virtual ~AsyncRouter(); @@ -31,14 +37,23 @@ public: /// @param finalPoint target point for route /// @param callback function to return routing result virtual void CalculateRoute(m2::PointD const & startPoint, m2::PointD const & direction, - m2::PointD const & finalPoint, ReadyCallback const & callback); + m2::PointD const & finalPoint, TReadyCallback const & callback); /// Interrupt routing and clear buffers virtual void ClearState(); private: /// This function is called in async mode - void CalculateRouteImpl(ReadyCallback const & callback); + void CalculateRouteImpl(TReadyCallback const & callback); + + /// These functions are called to send statistics about the routing + void SendStatistics(m2::PointD const & startPoint, m2::PointD const & startDirection, + m2::PointD const & finalPoint, + IRouter::ResultCode resultCode, + double elapsedSec); + void SendStatistics(m2::PointD const & startPoint, m2::PointD const & startDirection, + m2::PointD const & finalPoint, + string const & exceptionMessage); mutex m_paramsMutex; mutex m_routeMutex; @@ -49,6 +64,7 @@ private: m2::PointD m_startDirection; unique_ptr<IRouter> const m_router; + TRoutingStatisticsCallback const m_routingStatisticsFn; }; } // namespace routing diff --git a/routing/osrm_online_router.cpp b/routing/osrm_online_router.cpp index 0a79b90c1c..3222de3535 100644 --- a/routing/osrm_online_router.cpp +++ b/routing/osrm_online_router.cpp @@ -25,7 +25,7 @@ string OsrmOnlineRouter::GetName() const } void OsrmOnlineRouter::CalculateRoute(m2::PointD const & startPoint, m2::PointD const & /* direction */, - m2::PointD const & /* finalPoint */, ReadyCallback const & callback) + m2::PointD const & /* finalPoint */, TReadyCallback const & callback) { // Construct OSRM url request to get the route string url = OSRM_CAR_ROUTING_URL; @@ -37,7 +37,7 @@ void OsrmOnlineRouter::CalculateRoute(m2::PointD const & startPoint, m2::PointD downloader::HttpRequest::Get(url, bind(&OsrmOnlineRouter::OnRouteReceived, this, _1, callback)); } -void OsrmOnlineRouter::OnRouteReceived(downloader::HttpRequest & request, ReadyCallback callback) +void OsrmOnlineRouter::OnRouteReceived(downloader::HttpRequest & request, TReadyCallback callback) { if (request.Status() == downloader::HttpRequest::ECompleted) { diff --git a/routing/osrm_online_router.hpp b/routing/osrm_online_router.hpp index 9e5143e8d7..3bd928e78d 100644 --- a/routing/osrm_online_router.hpp +++ b/routing/osrm_online_router.hpp @@ -14,13 +14,13 @@ class OsrmOnlineRouter : public AsyncRouter m2::PointD m_finalPt; /// Http callback from the server - void OnRouteReceived(downloader::HttpRequest & request, ReadyCallback callback); + void OnRouteReceived(downloader::HttpRequest & request, TReadyCallback callback); public: virtual string GetName() const; // AsyncRouter overrides: void CalculateRoute(m2::PointD const & startPoint, m2::PointD const & /* direction */, - m2::PointD const & /* finalPoint */, ReadyCallback const & callback) override; + m2::PointD const & /* finalPoint */, TReadyCallback const & callback) override; }; } // namespace routing diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp index 1971a1e19b..de9345ddbb 100644 --- a/routing/road_graph_router.cpp +++ b/routing/road_graph_router.cpp @@ -11,8 +11,6 @@ #include "geometry/distance.hpp" #include "base/assert.hpp" -#include "base/timer.hpp" -#include "base/logging.hpp" namespace routing { @@ -70,8 +68,6 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin // we still need to check that startPoint and finalPoint are in the same MWM // and probably reset the graph. So the checks stay here. - LOG(LDEBUG, ("Calculate route from", startPoint, "to", finalPoint)); - string const mwmName = m_countryFileFn(finalPoint); if (m_countryFileFn(startPoint) != mwmName) return PointsInDifferentMWM; @@ -96,9 +92,6 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin if (startVicinity.empty()) return StartPointNotFound; - my::Timer timer; - timer.Reset(); - Junction const startPos(startPoint); Junction const finalPos(finalPoint); @@ -107,12 +100,10 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin m_roadGraph->AddFakeEdges(finalPos, finalVicinity); vector<Junction> routePos; - IRouter::ResultCode const resultCode = CalculateRoute(startPos, finalPos, routePos); + ResultCode const resultCode = CalculateRoute(startPos, finalPos, routePos); m_roadGraph->ResetFakes(); - LOG(LINFO, ("Route calculation time:", timer.ElapsedSeconds(), "result code:", resultCode)); - if (IRouter::NoError == resultCode) { ASSERT(routePos.back() == finalPos, ()); |