-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcounts_cache.hpp
147 lines (125 loc) · 4.25 KB
/
counts_cache.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#pragma once
#include "prelude.hpp"
#include "types.hpp"
#include "require.hpp"
#include "logging.hpp"
#include "cluster_vertex.hpp"
// A cache storing connection counts from a set of centers to all the
// others. Has a maximum size, and centers are evicted on an LRU basis
struct ConnectionCountsCacheElement {
ConnectionCountsCacheElement(): times_accessed(0), num_samples(0),
counts(std::vector<size_t>()) {
// It's here only to satisfy the compiler
throw std::logic_error("Never use this constructor");
}
ConnectionCountsCacheElement(size_t n): times_accessed(0), num_samples(0),
counts(std::vector<size_t>(n)) {}
size_t times_accessed;
size_t num_samples;
std::vector<size_t> counts;
};
class ConnectionCountsCache {
public:
ConnectionCountsCache(size_t max_size)
: m_max_size(max_size),
m_accesses(0),
m_hits(0),
m_cache(std::unordered_map<ugraph_vertex_t, ConnectionCountsCacheElement>()) {}
bool contains(ugraph_vertex_t v) const {
return m_cache.count(v) > 0;
}
ConnectionCountsCacheElement& get(ugraph_vertex_t v) {
REQUIRE(contains(v), "Cache does not contain the requested element");
m_cache[v].times_accessed++;
return m_cache[v];
}
void add_new(ugraph_vertex_t v, size_t n) {
REQUIRE(!contains(v), "Cache already contains the requested element");
LOG_DEBUG("Adding " << v << " to the cache");
m_cache.emplace(v, ConnectionCountsCacheElement(n));
cleanup_except(v);
}
ConnectionCountsCacheElement& get_or_new(ugraph_vertex_t v, size_t n) {
m_accesses++;
if (contains(v)) {
m_hits++;
return get(v);
} else {
add_new(v, n);
return get(v);
}
}
double perc_hits() const {
if (m_accesses == 0) {
return 0.0;
}
return 100.0 * m_hits / m_accesses;
}
size_t size() const {
return m_cache.size();
}
void set_accessed(ugraph_vertex_t v, size_t count) {
REQUIRE(contains(v), "Cannot set access count for missing node");
m_cache[v].times_accessed = count;
}
std::string str() const {
std::stringstream sstr;
sstr << "Cache size: " << m_cache.size() << " ::: ";
for (auto it=m_cache.begin(); it != m_cache.end(); it++) {
sstr << it->first << "(" << it->second.times_accessed << ") ";
}
return sstr.str();
}
int uncovered_node(const std::vector< ClusterVertex > & vinfo) {
size_t n = vinfo.size();
for (int i=0; i<n; i++) {
if (m_cache.count(i) > 0) {
if (!vinfo[i].is_covered()) {
return i;
} else if (vinfo[i].is_covered() && !vinfo[i].is_center()) {
// reset counter to mark for eviction for nodes that are
// covered but are not centers.
m_cache[i].times_accessed = 0;
}
}
}
return -1;
}
void cleanup() {
while (m_cache.size() > m_max_size) {
// remove the cache entry with the lowest times_accessed count
size_t min_accessed = std::numeric_limits<size_t>::max();
ugraph_vertex_t min_v = -1;
for (auto it=m_cache.begin(); it != m_cache.end(); it++) {
if (it->second.times_accessed < min_accessed) {
min_accessed = it->second.times_accessed;
min_v = it->first;
}
}
LOG_DEBUG("Removing from cache vertex " << min_v <<
" which was accessed " << min_accessed << " times");
m_cache.erase(min_v);
}
}
private:
size_t m_max_size;
size_t m_accesses;
size_t m_hits;
std::unordered_map<ugraph_vertex_t, ConnectionCountsCacheElement> m_cache;
void cleanup_except(ugraph_vertex_t u) {
while (m_cache.size() > m_max_size) {
// remove the cache entry with the lowest times_accessed count, if it's not the specified node
size_t min_accessed = std::numeric_limits<size_t>::max();
ugraph_vertex_t min_v = -1;
for (auto it=m_cache.begin(); it != m_cache.end(); it++) {
if (it->first != u && it->second.times_accessed < min_accessed) {
min_accessed = it->second.times_accessed;
min_v = it->first;
}
}
LOG_DEBUG("Removing from cache vertex " << min_v <<
" which was accessed " << min_accessed << " times");
m_cache.erase(min_v);
}
}
};