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
|
#include "cachesim.h"
#include <cstdlib>
#include <iostream>
#include <iomanip>
cache_sim_t::cache_sim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
: sets(_sets), ways(_ways), linesz(_linesz), name(_name)
{
init();
}
static void help()
{
std::cerr << "Cache configurations must be of the form" << std::endl;
std::cerr << " sets:ways:blocksize" << std::endl;
std::cerr << "where sets, ways, and blocksize are positive integers, with" << std::endl;
std::cerr << "sets and blocksize both powers of two and blocksize at least 8." << std::endl;
exit(1);
}
cache_sim_t::cache_sim_t(const char* config, const char* _name)
: name(_name)
{
const char* wp = strchr(config, ':');
if (!wp++) help();
const char* bp = strchr(wp, ':');
if (!bp++) help();
sets = atoi(std::string(config, wp).c_str());
ways = atoi(std::string(wp, bp).c_str());
linesz = atoi(bp);
init();
}
void cache_sim_t::init()
{
if(sets == 0 || (sets & (sets-1)))
help();
if(linesz < 8 || (linesz & (linesz-1)))
help();
idx_shift = 0;
for (size_t x = linesz; x; x >>= 1)
idx_shift++;
tags = new uint64_t[sets*ways]();
read_accesses = 0;
read_misses = 0;
bytes_read = 0;
write_accesses = 0;
write_misses = 0;
bytes_written = 0;
writebacks = 0;
miss_handler = NULL;
}
cache_sim_t::cache_sim_t(const cache_sim_t& rhs)
: sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
idx_shift(rhs.idx_shift), name(rhs.name)
{
tags = new uint64_t[sets*ways];
memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
}
cache_sim_t::~cache_sim_t()
{
print_stats();
delete [] tags;
}
void cache_sim_t::print_stats()
{
if(read_accesses + write_accesses == 0)
return;
float mr = 100.0f*(read_misses+write_misses)/(read_accesses+write_accesses);
std::cout << std::setprecision(3) << std::fixed;
std::cout << name << " ";
std::cout << "Bytes Read: " << bytes_read << std::endl;
std::cout << name << " ";
std::cout << "Bytes Written: " << bytes_written << std::endl;
std::cout << name << " ";
std::cout << "Read Accesses: " << read_accesses << std::endl;
std::cout << name << " ";
std::cout << "Write Accesses: " << write_accesses << std::endl;
std::cout << name << " ";
std::cout << "Read Misses: " << read_misses << std::endl;
std::cout << name << " ";
std::cout << "Write Misses: " << write_misses << std::endl;
std::cout << name << " ";
std::cout << "Writebacks: " << writebacks << std::endl;
std::cout << name << " ";
std::cout << "Miss Rate: " << mr << '%' << std::endl;
}
void cache_sim_t::access(uint64_t addr, size_t bytes, bool store)
{
store ? write_accesses++ : read_accesses++;
(store ? bytes_written : bytes_read) += bytes;
size_t idx = (addr >> idx_shift) & (sets-1);
size_t tag = (addr >> idx_shift) | VALID;
size_t* set_tags = &tags[idx*ways];
for(size_t i = 0; i < ways; i++)
{
if(tag == (set_tags[i] & ~DIRTY)) // hit
{
if(store)
set_tags[i] |= DIRTY;
return;
}
}
store ? write_misses++ : read_misses++;
size_t way = lfsr.next() % ways;
if((set_tags[way] & (VALID | DIRTY)) == (VALID | DIRTY))
{
uint64_t dirty_addr = (set_tags[way] & ~(VALID | DIRTY)) << idx_shift;
if (miss_handler) miss_handler->access(dirty_addr, linesz, true);
writebacks++;
}
if (miss_handler) miss_handler->access(addr & ~(linesz-1), linesz, false);
set_tags[way] = tag | (store ? DIRTY : 0);
}
|