fixed notes

This commit is contained in:
Constantin Shalnev 2015-06-25 10:34:02 +03:00 committed by Alex Zolotarev
parent bf29963296
commit 503fab769f
5 changed files with 182 additions and 72 deletions

View file

@ -3,6 +3,23 @@
#include "base/macros.hpp"
#include "base/stl_add.hpp"
#include "std/bind.hpp"
namespace
{
class SimpleFunctor
{
public:
void operator() (char c)
{
m_v.push_back(c);
}
vector<char> m_v;
};
double constexpr kEpsilon = 1e-6;
} // namespace
UNIT_TEST(CacheSmoke)
{
char const s [] = "1123212434445";
@ -33,7 +50,7 @@ UNIT_TEST(CacheSmoke)
UNIT_TEST(CacheSmoke_0)
{
my::Cache<uint32_t, char> cache(3);
my::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
bool found = true;
cache.Find(0, found);
TEST(!found, ());
@ -41,3 +58,66 @@ UNIT_TEST(CacheSmoke_0)
cache.ForEachValue(MakeBackInsertFunctor(v));
TEST_EQUAL(v, vector<char>(8, 0), ());
}
UNIT_TEST(CacheSmoke_1)
{
my::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
SimpleFunctor f;
cache.ForEachValue(f); // f passed by reference
TEST_EQUAL(f.m_v, vector<char>(8, 0), ());
}
UNIT_TEST(CacheSmoke_2)
{
my::Cache<uint32_t, char> cache(3); // it contains 2^3=8 elements
SimpleFunctor f;
cache.ForEachValue(ref(f)); // f passed by reference
TEST_EQUAL(f.m_v, vector<char>(8, 0), ());
}
UNIT_TEST(CacheSmoke_3)
{
my::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
// 0 access, cache miss is 0
TEST(my::AlmostEqualAbs(0.0, cache.GetCacheMiss(), kEpsilon), ());
bool found = true;
cache.Find(1, found);
TEST(!found, ());
// 1 access, 1 miss, cache miss = 1/1 = 1
TEST(my::AlmostEqualAbs(1.0, cache.GetCacheMiss(), kEpsilon), ());
found = false;
cache.Find(1, found);
TEST(found, ());
// 2 access, 1 miss, cache miss = 1/2 = 0.5
TEST(my::AlmostEqualAbs(0.5, cache.GetCacheMiss(), kEpsilon), ());
found = false;
cache.Find(2, found);
TEST(!found, ());
// 3 access, 2 miss, cache miss = 2/3 = 0.6(6)
TEST(my::AlmostEqualAbs(2.0/3.0, cache.GetCacheMiss(), kEpsilon), ());
cache.Reset();
// 0 access, cache miss is 0
TEST(my::AlmostEqualAbs(0.0, cache.GetCacheMiss(), kEpsilon), ());
}
UNIT_TEST(CacheSmoke_4)
{
my::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
SimpleFunctor f;
cache.ForEachValue(f); // f passed by reference
TEST_EQUAL(f.m_v, vector<char>(8, 0), ());
}
UNIT_TEST(CacheSmoke_5)
{
my::CacheWithStat<uint32_t, char> cache(3); // it contains 2^3=8 elements
SimpleFunctor f;
cache.ForEachValue(ref(f)); // f passed by reference
TEST_EQUAL(f.m_v, vector<char>(8, 0), ());
}

View file

@ -6,7 +6,7 @@
namespace my
{
// Simple Cache that stores list of most recently used values.
// Simple cache that stores list of values.
template <typename KeyT, typename ValueT> class Cache
{
private:
@ -14,7 +14,7 @@ namespace my
Cache<KeyT, ValueT> & operator = (Cache<KeyT, ValueT> const &); // Not implemented.
public:
// Create cache with maximum size @maxCachedObjects.
// @logCacheSize is pow of two for number of elements in cache.
explicit Cache(uint32_t logCacheSize)
: m_Cache(new Data[1 << logCacheSize]), m_HashMask((1 << logCacheSize) - 1)
{
@ -59,7 +59,7 @@ namespace my
}
template <typename F>
void ForEachValue(F f)
void ForEachValue(F && f)
{
for (uint32_t i = 0; i <= m_HashMask; ++i)
f(m_Cache[i].m_Value);
@ -106,4 +106,53 @@ namespace my
Data * const m_Cache;
uint32_t const m_HashMask;
};
// Simple cache that stores list of values and provides cache missing statistics.
// CacheWithStat class has the same interface as Cache class
template <typename TKey, typename TValue>
class CacheWithStat
{
public:
// @logCacheSize is pow of two for number of elements in cache.
explicit CacheWithStat(uint32_t logCacheSize)
: m_cache(logCacheSize), m_miss(0), m_access(0)
{
}
double GetCacheMiss() const
{
if (m_access == 0)
return 0.0;
return (double)m_miss / (double)m_access;
}
uint32_t GetCacheSize() const { return m_cache.GetCacheSize(); }
TValue & Find(TKey const & key, bool & found)
{
++m_access;
TValue & res = m_cache.Find(key, found);
if (!found)
++m_miss;
return res;
}
template <typename F>
void ForEachValue(F && f)
{
m_cache.ForEachValue(std::forward<F>(f));
}
void Reset()
{
m_cache.Reset();
m_access = 0;
m_miss = 0;
}
private:
Cache<TKey, TValue> m_cache;
uint32_t m_miss;
uint32_t m_access;
};
}

View file

@ -16,17 +16,15 @@ namespace routing
namespace
{
uint32_t const FEATURE_CACHE_SIZE = 10;
double const READ_CROSS_EPSILON = 1.0E-4;
uint32_t constexpr kPowOfTwoForFeatureCacheSize = 10; // cache contains 2 ^ kPowOfTwoForFeatureCacheSize elements
double constexpr kReadCrossEpsilon = 1.0E-4;
} // namespace
FeaturesRoadGraph::FeaturesRoadGraph(IVehicleModel const & vehicleModel, Index const & index, MwmSet::MwmId const & mwmID)
: m_index(index),
m_mwmID(mwmID),
m_vehicleModel(vehicleModel),
m_cache(FEATURE_CACHE_SIZE),
m_cacheMiss(0),
m_cacheAccess(0)
m_cache(kPowOfTwoForFeatureCacheSize)
{
}
@ -56,8 +54,7 @@ public:
return;
// load feature from cache
IRoadGraph::RoadInfo const & ri = m_graph.GetCachedRoadInfo(fID.m_offset, true /*preload*/, ft, speedKMPH);
ASSERT_EQUAL(speedKMPH, ri.m_speedKMPH, ());
IRoadGraph::RoadInfo const & ri = m_graph.GetCachedRoadInfo(fID.m_offset, ft, speedKMPH);
m_edgesLoader(fID.m_offset, ri);
}
@ -67,26 +64,18 @@ private:
IRoadGraph::CrossEdgesLoader & m_edgesLoader;
};
void FeaturesRoadGraph::LoadFeature(uint32_t featureId, FeatureType & ft) const
{
Index::FeaturesLoaderGuard loader(m_index, m_mwmID);
loader.GetFeature(featureId, ft);
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, (featureId));
ASSERT_GREATER(ft.GetPointsCount(), 1, (featureId));
}
IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(uint32_t featureId) const
{
FeatureType ft;
return GetCachedRoadInfo(featureId, false /*preload*/, ft, 0.0 /*speedKMPH*/);
RoadInfo const & ri = GetCachedRoadInfo(featureId);
ASSERT_GREATER(ri.m_speedKMPH, 0.0, ());
return ri;
}
double FeaturesRoadGraph::GetSpeedKMPH(uint32_t featureId) const
{
FeatureType ft;
return GetCachedRoadInfo(featureId, false /*preload*/, ft, 0.0 /*speedKMPH*/).m_speedKMPH;
double const speedKMPH = GetCachedRoadInfo(featureId).m_speedKMPH;
ASSERT_GREATER(speedKMPH, 0.0, ());
return speedKMPH;
}
double FeaturesRoadGraph::GetMaxSpeedKMPH() const
@ -99,8 +88,8 @@ void FeaturesRoadGraph::ForEachFeatureClosestToCross(m2::PointD const & cross,
{
CrossFeaturesLoader featuresLoader(*this, edgesLoader);
m_index.ForEachInRect(featuresLoader,
m2::RectD(cross.x - READ_CROSS_EPSILON, cross.y - READ_CROSS_EPSILON,
cross.x + READ_CROSS_EPSILON, cross.y + READ_CROSS_EPSILON),
m2::RectD(cross.x - kReadCrossEpsilon, cross.y - kReadCrossEpsilon,
cross.x + kReadCrossEpsilon, cross.y + kReadCrossEpsilon),
scales::GetUpperScale());
}
@ -114,37 +103,46 @@ double FeaturesRoadGraph::GetSpeedKMPHFromFt(FeatureType const & ft) const
return m_vehicleModel.GetSpeed(ft);
}
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(uint32_t featureId) const
{
bool found = false;
RoadInfo & ri = m_cache.Find(featureId, found);
if (found)
return ri;
FeatureType ft;
Index::FeaturesLoaderGuard loader(m_index, m_mwmID);
loader.GetFeature(featureId, ft);
ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, (featureId));
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
ri.m_bidirectional = !IsOneWay(ft);
ri.m_speedKMPH = GetSpeedKMPHFromFt(ft);
ft.SwapPoints(ri.m_points);
return ri;
}
IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(uint32_t featureId,
bool preload,
FeatureType & ft,
double speedKMPH) const
{
bool found = false;
RoadInfo & ri = m_cache.Find(featureId, found);
if (!found)
{
if (preload)
{
// ft must be set
ASSERT(featureId == ft.GetID().m_offset, ());
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
}
else
{
LoadFeature(featureId, ft);
speedKMPH = GetSpeedKMPHFromFt(ft);
}
if (found)
return ri;
ri.m_bidirectional = !IsOneWay(ft);
ri.m_speedKMPH = speedKMPH;
ft.SwapPoints(ri.m_points);
// ft must be set
ASSERT_EQUAL(featureId, ft.GetID().m_offset, ());
m_cacheMiss++;
}
m_cacheAccess++;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
ASSERT_EQUAL(ri.m_speedKMPH, GetSpeedKMPHFromFt(ft), ());
ri.m_bidirectional = !IsOneWay(ft);
ri.m_speedKMPH = speedKMPH;
ft.SwapPoints(ri.m_points);
return ri;
}

View file

@ -27,12 +27,7 @@ public:
inline MwmSet::MwmId const & GetMwmID() const { return m_mwmID; }
double GetCacheMiss() const
{
if (m_cacheAccess == 0)
return 0.0;
return (double)m_cacheMiss / (double)m_cacheAccess;
}
double GetCacheMiss() const { return m_cache.GetCacheMiss(); }
protected:
// IRoadGraph overrides:
@ -47,13 +42,9 @@ private:
bool IsOneWay(FeatureType const & ft) const;
double GetSpeedKMPHFromFt(FeatureType const & ft) const;
void LoadFeature(uint32_t featureId, FeatureType & ft) const;
// Optimization:
// If preload is set to true then feature ft is set and speedKMPH contains valid value,
// otherwise feature is not set and must be load and speed is not valid.
RoadInfo const & GetCachedRoadInfo(uint32_t featureId) const;
RoadInfo const & GetCachedRoadInfo(uint32_t featureId,
bool preload,
FeatureType & ft,
double speedKMPH) const;
@ -61,9 +52,7 @@ private:
MwmSet::MwmId const m_mwmID;
IVehicleModel const & m_vehicleModel;
mutable my::Cache<uint32_t, RoadInfo> m_cache;
mutable uint32_t m_cacheMiss;
mutable uint32_t m_cacheAccess;
mutable my::CacheWithStat<uint32_t, RoadInfo> m_cache;
};
} // namespace routing

View file

@ -56,13 +56,10 @@ public:
for (auto const & e : edges)
{
double const speedKMPH = m_roadGraph.GetSpeedKMPH(e);
if (speedKMPH <= 0.0)
continue;
ASSERT_EQUAL(v, e.GetStartJunction(), ());
adj.emplace_back(e.GetEndJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedKMPH * KMPH2MPS));
double const speedMPS = m_roadGraph.GetSpeedKMPH(e) * KMPH2MPS;
adj.emplace_back(e.GetEndJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedMPS));
}
}
@ -76,13 +73,10 @@ public:
for (auto const & e : edges)
{
double const speedKMPH = m_roadGraph.GetSpeedKMPH(e);
if (speedKMPH <= 0.0)
continue;
ASSERT_EQUAL(v, e.GetEndJunction(), ());
adj.emplace_back(e.GetStartJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedKMPH * KMPH2MPS));
double const speedMPS = m_roadGraph.GetSpeedKMPH(e) * KMPH2MPS;
adj.emplace_back(e.GetStartJunction(), TimeBetweenSec(e.GetStartJunction(), e.GetEndJunction(), speedMPS));
}
}