00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <ReuseDistance.hpp>
00022
00023 using namespace std;
00024
00025 #define REUSE_DEBUG
00026 #ifdef REUSE_DEBUG
00027 #define debug_assert(...) assert(__VA_ARGS__)
00028 #else
00029 #define debug_assert(...)
00030 #endif
00031
00032 inline uint64_t uint64abs(uint64_t a){
00033 if (a < 0x8000000000000000L){
00034 return a;
00035 } else {
00036 return 0 - a;
00037 }
00038 }
00039
00040 void ReuseDistance::Init(uint64_t w, uint64_t b){
00041 capacity = w;
00042 binindividual = b;
00043 maxtracking = capacity;
00044
00045 current = 0;
00046 sequence = 1;
00047
00048 window = newtree234();
00049 assert(window);
00050
00051 mwindow.clear();
00052
00053 assert(ReuseDistance::Infinity == NULL && "NULL is non-zero!?");
00054 }
00055
00056 ReuseDistance::ReuseDistance(uint64_t w, uint64_t b){
00057 ReuseDistance::Init(w, b);
00058 }
00059
00060 ReuseDistance::ReuseDistance(uint64_t w){
00061 ReuseDistance::Init(w, DefaultBinIndividual);
00062 }
00063
00064 ReuseDistance::~ReuseDistance(){
00065 for (reuse_map_type<uint64_t, ReuseStats*>::const_iterator it = stats.begin(); it != stats.end(); it++){
00066 uint64_t id = it->first;
00067 delete stats[id];
00068 }
00069
00070 debug_assert(current == count234(window));
00071 while (current){
00072 delete (ReuseEntry*)delpos234(window, 0);
00073 current--;
00074 }
00075 freetree234(window);
00076 }
00077
00078 uint64_t ReuseStats::GetMissCount(){
00079 return distcounts[invalid];
00080 }
00081
00082 void ReuseDistance::GetIndices(std::vector<uint64_t>& ids){
00083 assert(ids.size() == 0);
00084 for (reuse_map_type<uint64_t, ReuseStats*>::const_iterator it = stats.begin(); it != stats.end(); it++){
00085 uint64_t id = it->first;
00086 ids.push_back(id);
00087 }
00088 }
00089
00090 void ReuseDistance::GetActiveAddresses(std::vector<uint64_t>& addrs){
00091 assert(addrs.size() == 0);
00092 debug_assert(current == count234(window));
00093
00094 for (int i = 0; i < current; i++){
00095 ReuseEntry* r = index234(window, i);
00096 addrs.push_back(r->address);
00097 }
00098 }
00099
00100 void ReuseDistance::Print(bool annotate){
00101 Print(cout, annotate);
00102 }
00103
00104 void ReuseDistance::Process(ReuseEntry* rs, uint64_t count){
00105 for (uint32_t i = 0; i < count; i++){
00106 Process(rs[i]);
00107 }
00108 }
00109
00110 void ReuseDistance::Process(vector<ReuseEntry> rs){
00111 for (vector<ReuseEntry>::const_iterator it = rs.begin(); it != rs.end(); it++){
00112 ReuseEntry r = *it;
00113 Process(r);
00114 }
00115 }
00116
00117 void ReuseDistance::Process(vector<ReuseEntry*> rs){
00118 for (vector<ReuseEntry*>::const_iterator it = rs.begin(); it != rs.end(); it++){
00119 ReuseEntry* r = *it;
00120 Process((*r));
00121 }
00122 }
00123
00124 void ReuseDistance::SkipAddresses(uint64_t amount){
00125 sequence += amount;
00126
00127
00128 while (current){
00129 delete delpos234(window, 0);
00130 current--;
00131 }
00132 mwindow.clear();
00133
00134 assert(mwindow.size() == 0);
00135 assert(count234(window) == 0);
00136 }
00137
00138 void ReuseDistance::Process(ReuseEntry& r){
00139 uint64_t addr = r.address;
00140 uint64_t id = r.id;
00141 uint64_t mres = mwindow.count(addr);
00142
00143 ReuseStats* stats = GetStats(id, true);
00144
00145 int dist = 0;
00146 ReuseEntry* result;
00147 if (mres){
00148 mres = mwindow[addr];
00149 ReuseEntry key;
00150 key.address = addr;
00151 key.__seq = mres;
00152
00153 result = findrelpos234(window, &key, &dist);
00154 debug_assert(result);
00155
00156 if (capacity != ReuseDistance::Infinity){
00157 debug_assert(current - dist <= capacity);
00158 }
00159 stats->Update(current - dist);
00160 } else {
00161 stats->Update(ReuseDistance::Infinity);
00162 }
00163
00164
00165 ReuseEntry* slot = NULL;
00166 if (mres || (capacity != ReuseDistance::Infinity && current >= capacity)){
00167 slot = (ReuseEntry*)delpos234(window, dist);
00168 debug_assert(mwindow[slot->address]);
00169 mwindow.erase(slot->address);
00170 debug_assert(count234(window) == mwindow.size());
00171 } else {
00172 slot = new ReuseEntry();
00173 current++;
00174 }
00175
00176 mwindow[addr] = sequence;
00177
00178 slot->__seq = sequence;
00179 slot->address = addr;
00180 add234(window, slot);
00181
00182 debug_assert(count234(window) == mwindow.size());
00183 debug_assert(mwindow.size() <= current);
00184
00185 sequence++;
00186 }
00187
00188 void ReuseDistance::PrintFormat(ostream& f){
00189 f << "# "
00190 << Describe() << "STATS"
00191 << TAB << "<window_size>"
00192 << TAB << "<bin_indiv>"
00193 << TAB << "<max_track>"
00194 << TAB << "<id_count>"
00195 << TAB << "<tot_access>"
00196 << TAB << "<tot_miss>"
00197 << ENDL;
00198
00199 f << "# "
00200 << TAB << Describe() << "ID"
00201 << TAB << "<id>"
00202 << TAB << "<id_access>"
00203 << TAB << "<id_miss>"
00204 << ENDL;
00205 }
00206
00207 void ReuseStats::PrintFormat(ostream& f){
00208 f << "# "
00209 << TAB
00210 << TAB << "<bin_lower_bound>"
00211 << TAB << "<bin_upper_bound>"
00212 << TAB << "<bin_count>"
00213 << ENDL;
00214 }
00215
00216 void ReuseDistance::Print(ostream& f, bool annotate){
00217 vector<uint64_t> keys;
00218 for (reuse_map_type<uint64_t, ReuseStats*>::const_iterator it = stats.begin(); it != stats.end(); it++){
00219 keys.push_back(it->first);
00220 }
00221 sort(keys.begin(), keys.end());
00222
00223 uint64_t tot = 0, mis = 0;
00224 for (vector<uint64_t>::const_iterator it = keys.begin(); it != keys.end(); it++){
00225 uint64_t id = (*it);
00226 ReuseStats* r = (ReuseStats*)stats[id];
00227 tot += r->GetAccessCount();
00228 mis += r->GetMissCount();
00229 }
00230
00231 if (annotate){
00232 ReuseDistance::PrintFormat(f);
00233 ReuseStats::PrintFormat(f);
00234 }
00235
00236 f << Describe() << "STATS"
00237 << TAB << dec << capacity
00238 << TAB << binindividual
00239 << TAB << maxtracking
00240 << TAB << keys.size()
00241 << TAB << tot
00242 << TAB << mis
00243 << ENDL;
00244
00245 for (vector<uint64_t>::const_iterator it = keys.begin(); it != keys.end(); it++){
00246 uint64_t id = (*it);
00247 ReuseStats* r = (ReuseStats*)stats[id];
00248
00249 f << TAB << Describe() << "ID"
00250 << TAB << dec << id
00251 << TAB << r->GetAccessCount()
00252 << TAB << r->GetMissCount()
00253 << ENDL;
00254
00255 r->Print(f);
00256 }
00257 }
00258
00259 ReuseStats* ReuseDistance::GetStats(uint64_t id, bool gen){
00260 ReuseStats* s = stats[id];
00261 if (s == NULL && gen){
00262 s = new ReuseStats(id, binindividual, capacity, ReuseDistance::Infinity);
00263 stats[id] = s;
00264 }
00265 return s;
00266 }
00267
00268
00269 static const uint64_t b[] = {0x2L, 0xCL, 0xF0L, 0xFF00L, 0xFFFF0000L, 0xFFFFFFFF00000000L};
00270 static const uint32_t S[] = {1, 2, 4, 8, 16, 32};
00271 inline uint64_t ShaveBitsPwr2(uint64_t val){
00272 val -= 1;
00273 register uint64_t r = 0;
00274 for (int32_t i = 5; i >= 0; i--){
00275 if (val & b[i]){
00276 val = val >> S[i];
00277 r |= S[i];
00278 }
00279 }
00280 return (2 << r);
00281 }
00282
00283 uint64_t ReuseStats::GetBin(uint64_t value){
00284
00285 if (value == invalid){
00286 return invalid;
00287 }
00288
00289 else if (maxtracking != ReuseDistance::Infinity && value > maxtracking){
00290 return invalid;
00291 }
00292
00293 else if (binindividual != ReuseDistance::Infinity && value > binindividual){
00294 return ShaveBitsPwr2(value);
00295 }
00296
00297 return value;
00298 }
00299
00300 ReuseStats* ReuseDistance::GetStats(uint64_t id){
00301 return GetStats(id, false);
00302 }
00303
00304 uint64_t ReuseStats::GetAccessCount(){
00305 return accesses;
00306 }
00307
00308 uint64_t ReuseStats::GetMaximumDistance(){
00309 uint64_t max = 0;
00310 for (reuse_map_type<uint64_t, uint64_t>::const_iterator it = distcounts.begin(); it != distcounts.end(); it++){
00311 uint64_t d = it->first;
00312 if (d > max){
00313 max = d;
00314 }
00315 }
00316 return max;
00317 }
00318
00319 void ReuseStats::Update(uint64_t dist){
00320 distcounts[GetBin(dist)] += 1;
00321 accesses++;
00322 }
00323
00324 uint64_t ReuseStats::CountDistance(uint64_t d){
00325 if (distcounts.count(d) == 0){
00326 return 0;
00327 }
00328 return distcounts[d];
00329 }
00330
00331 void ReuseStats::GetSortedDistances(vector<uint64_t>& dkeys){
00332 assert(dkeys.size() == 0 && "dkeys must be an empty vector");
00333 for (reuse_map_type<uint64_t, uint64_t>::const_iterator it = distcounts.begin(); it != distcounts.end(); it++){
00334 uint64_t d = it->first;
00335 dkeys.push_back(d);
00336 }
00337 sort(dkeys.begin(), dkeys.end());
00338 }
00339
00340 void ReuseStats::Print(ostream& f, bool annotate){
00341 vector<uint64_t> keys;
00342 GetSortedDistances(keys);
00343
00344 if (annotate){
00345 ReuseStats::PrintFormat(f);
00346 }
00347
00348 for (vector<uint64_t>::const_iterator it = keys.begin(); it != keys.end(); it++){
00349 uint64_t d = *it;
00350 if (d == invalid) continue;
00351
00352 debug_assert(distcounts.count(d) > 0);
00353 uint32_t cnt = distcounts[d];
00354
00355 debug_assert(cnt > 0);
00356 if (cnt > 0){
00357 uint64_t p = d / 2 + 1;
00358 if (binindividual == ReuseDistance::Infinity || d <= binindividual){
00359 p = d;
00360 }
00361 f << TAB
00362 << TAB << dec << p
00363 << TAB << d
00364 << TAB << cnt
00365 << ENDL;
00366 }
00367 }
00368 }
00369
00370 void SpatialLocality::Init(uint64_t size, uint64_t bin, uint64_t max){
00371 sequence = 1;
00372 capacity = size;
00373 binindividual = bin;
00374 maxtracking = max;
00375
00376 assert(capacity > 0 && capacity != ReuseDistance::Infinity && "window size must be a finite, positive value");
00377 assert((maxtracking == INFINITY_REUSE || maxtracking >= binindividual) && "max tracking must be at least as large as individual binning");
00378 }
00379
00380 ReuseStats* SpatialLocality::GetStats(uint64_t id, bool gen){
00381 ReuseStats* s = stats[id];
00382 if (s == NULL && gen){
00383 s = new ReuseStats(id, binindividual, maxtracking, SpatialLocality::Invalid);
00384 stats[id] = s;
00385 }
00386 return s;
00387 }
00388
00389 void SpatialLocality::Process(ReuseEntry& r){
00390 uint64_t addr = r.address;
00391 uint64_t id = r.id;
00392 ReuseStats* stats = GetStats(id, true);
00393 debug_assert(stats);
00394
00395
00396 uint64_t bestdiff = SpatialLocality::Invalid;
00397
00398 if (awindow.size() > 0){
00399
00400 map<uint64_t, uint64_t>::const_iterator it = awindow.upper_bound(addr);
00401 if (it == awindow.end()){
00402 it--;
00403 }
00404
00405
00406 for (uint32_t i = 0; i < 3; i++, it--){
00407 uint64_t cur = it->first;
00408 uint64_t seq = it->second;
00409 uint64_t diff = uint64abs(cur - addr);
00410
00411 if (diff < bestdiff){
00412 bestdiff = diff;
00413 }
00414
00415 if (it == awindow.begin()){
00416 break;
00417 }
00418 }
00419 }
00420
00421 stats->Update(bestdiff);
00422
00423
00424 if (swindow.size() > capacity){
00425 uint64_t a = swindow.front();
00426 swindow.pop_front();
00427
00428 uint64_t v = awindow[a];
00429 if (v > 1){
00430 awindow[a] = v - 1;
00431 } else {
00432 awindow.erase(a);
00433 }
00434 }
00435
00436
00437 awindow[addr]++;
00438 swindow.push_back(addr);
00439 }
00440
00441 void SpatialLocality::SkipAddresses(uint64_t amount){
00442
00443
00444 while (swindow.size()){
00445 uint64_t a = swindow.front();
00446 swindow.pop_front();
00447
00448 uint64_t v = awindow[a];
00449 if (v > 1){
00450 awindow[a] = v - 1;
00451 } else {
00452 awindow.erase(a);
00453 }
00454 }
00455
00456 assert(awindow.size() == 0);
00457 assert(swindow.size() == 0);
00458 }
00459
00460 void SpatialLocality::GetActiveAddresses(std::vector<uint64_t>& addrs){
00461 assert(addrs.size() == 0);
00462
00463 for (map<uint64_t, uint64_t>::const_iterator it = awindow.begin(); it != awindow.end(); it++){
00464 uint64_t addr = it->first;
00465 addrs.push_back(addr);
00466 }
00467 }
00468