-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdef.hh
More file actions
344 lines (322 loc) · 10.6 KB
/
def.hh
File metadata and controls
344 lines (322 loc) · 10.6 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#pragma once
#ifndef XERXES_DEF_HH
#define XERXES_DEF_HH
#include "utils.hh"
#include <climits>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <map>
#include <string>
#include <unordered_map>
namespace xerxes {
typedef uint64_t Addr;
typedef int64_t TopoID;
typedef int64_t PktID;
typedef uint64_t Tick;
class Topology;
class System;
class Simulation;
typedef enum {
RD, /* Read (coherent) */
NT_RD, /* Non-temporal read */
WT, /* Write (coherent) */
NT_WT, /* Non-temporal write */
INV, /* Invalidate (to Host) */
CORUPT, /* Corrupted packet */
PKT_TYPE_NUM
} PacketType;
class TypeName {
public:
static std::string of(PacketType type) {
switch (type) {
case RD:
return std::string("Read");
case NT_RD:
return std::string("Non-temporal read");
case WT:
return std::string("Write");
case NT_WT:
return std::string("Non-temporal write");
case INV:
return std::string("Invalidate");
case CORUPT:
return std::string("*Corruptted*");
default:
return std::string("*unknown packet type*");
}
}
};
typedef enum {
BUS_QUEUE_DELAY,
BUS_TIME,
FRAMING_TIME,
SWITCH_QUEUE_DELAY,
SWITCH_TIME,
PACKAGING_DELAY,
WAIT_ALL_BURST,
SNOOP_EVICT_DELAY,
HOST_INV_DELAY,
DRAM_INTERFACE_QUEUING_DELAY,
DEVICE_PROCESS_TIME,
DRAM_TIME,
NUM_STATS
} NormalStatType;
class StatKeys {
public:
StatKeys() {}
static std::string key_name(NormalStatType type) {
switch (type) {
case BUS_QUEUE_DELAY:
return std::string("bus queue delay");
case SWITCH_QUEUE_DELAY:
return std::string("switch queue delay");
case BUS_TIME:
return std::string("bus time");
case FRAMING_TIME:
return std::string("framing time");
case SWITCH_TIME:
return std::string("switch time");
case PACKAGING_DELAY:
return std::string("packaging delay");
case WAIT_ALL_BURST:
return std::string("wait all burst");
case SNOOP_EVICT_DELAY:
return std::string("snoop evict delay");
case HOST_INV_DELAY:
return std::string("host inv delay");
case DRAM_INTERFACE_QUEUING_DELAY:
return std::string("dram interface queuing delay");
case DEVICE_PROCESS_TIME:
return std::string("device process time");
case DRAM_TIME:
return std::string("dram time");
default:
return std::string("unknown stat type");
}
}
};
/**
* @brief A global table to store packet statistics.
*/
class PktStatsTable {
private:
PktStatsTable() {}
typedef std::unordered_map<NormalStatType, double> Table;
typedef std::unordered_map<PktID, Table> Tables;
public:
static Tables &get() {
static Tables table = Tables{};
return table;
}
};
struct Packet {
PktID id; /* Packet ID */
PacketType type; /* Packet type */
Addr addr; /* Address */
size_t payload; /* Payload size (in bytes) */
size_t burst; /* Burst size */
Tick sent; /* Sent time */
Tick arrive; /* Arrive time */
TopoID from; /* From (on-trans) */
TopoID src; /* Source device */
TopoID dst; /* Destination device */
bool is_rsp; /* Is response */
bool
is_sub_pkt; /* Is sub-packet, uses 0 time in bus (packaged by former) */
Packet()
: id(-1), type(PKT_TYPE_NUM), addr(0), payload(0), burst(1), sent(0),
arrive(0), from(-1), src(-1), dst(-1), is_rsp(false),
is_sub_pkt(false) {}
Packet(PktID id, PacketType type, Addr addr, size_t size, size_t burst,
Tick sent, Tick arrive, TopoID from, TopoID src, TopoID dst,
bool is_rsp, bool is_sub_pkt)
: id(id), type(type), addr(addr), payload(size), burst(burst),
sent(sent), arrive(std::max(sent, arrive)), from(from), src(src),
dst(dst), is_rsp(is_rsp), is_sub_pkt(is_sub_pkt) {}
Packet(const Packet &pkt)
: id(pkt.id), type(pkt.type), addr(pkt.addr), payload(pkt.payload),
burst(pkt.burst), sent(pkt.sent), arrive(pkt.arrive), from(pkt.from),
src(pkt.src), dst(pkt.dst), is_rsp(pkt.is_rsp),
is_sub_pkt(pkt.is_sub_pkt) {}
bool valid() { return id != -1 && type != PKT_TYPE_NUM && type != CORUPT; }
/**
* @brief Check if the packet is a write request.
* @return true if the packet is a write request.
*/
bool is_write() { return type == WT || type == NT_WT; }
bool is_read() { return type == RD || type == NT_RD; }
/**
* @brief Check if the packet is a coherent request (RD/WT).
* @return true if the packet is a coherent request (RD/WT).
*/
bool is_coherent() { return type == RD || type == WT; }
bool has_stat(NormalStatType key) const {
auto &stats = PktStatsTable::get()[id];
return stats.find(key) != stats.end();
}
double get_stat(NormalStatType key) const {
if (!has_stat(key))
return 0;
auto &stats = PktStatsTable::get()[id];
return stats[key];
}
void set_stat(NormalStatType key, double value) {
auto &stats = PktStatsTable::get()[id];
stats.insert(std::make_pair(key, value));
}
/**
* @brief Add on or insert a value `v` to a statistic `s`. Do `s += v`.
* @param key The key of the statistic.
* @param value The value.
*/
void delta_stat(NormalStatType key, double value) {
auto &stats = PktStatsTable::get()[id];
XerxesLogger::debug() << "delta stat \"" << StatKeys::key_name(key)
<< "\" = " << value << std::endl;
if (has_stat(key))
stats[key] += value;
else
stats.insert(std::make_pair(key, value));
}
typedef std::function<void(const Packet &)> XerxesLoggerFunc;
static XerxesLoggerFunc &pkt_logger(
bool set = false, XerxesLoggerFunc logger = [](const Packet &) {}) {
static XerxesLoggerFunc f = [](const Packet &) {};
if (set)
f = logger;
return f;
}
void log_stat() { Packet::pkt_logger()(*this); }
};
class PktBuilder {
private:
PktID id_i;
PacketType type_i;
Addr addr_i;
size_t payload_i;
size_t burst_i;
Tick sent_i;
Tick arrive_i;
TopoID from_i;
TopoID src_i;
TopoID dst_i;
bool is_rsp_i;
bool is_sub_pkt_i;
public:
PktBuilder()
: type_i(PKT_TYPE_NUM), addr_i(0), payload_i(0), burst_i(1), sent_i(0),
arrive_i(0), from_i(-1), src_i(-1), dst_i(-1), is_rsp_i(false),
is_sub_pkt_i(false) {
// Automate the packet ID
static PktID id = 0;
id_i = id++;
PktStatsTable::get().insert(
std::make_pair(id_i, std::unordered_map<NormalStatType, double>{}));
}
PktBuilder &type(PacketType type) {
type_i = type;
return *this;
}
PktBuilder &addr(Addr addr) {
addr_i = addr;
return *this;
}
PktBuilder &payload(size_t payload) {
payload_i = payload;
return *this;
}
PktBuilder &burst(size_t burst) {
burst_i = burst;
return *this;
}
PktBuilder &sent(Tick sent) {
sent_i = sent;
arrive_i = std::max(sent_i, arrive_i);
return *this;
}
PktBuilder &arrive(Tick arrive) {
arrive_i = std::max(sent_i, arrive);
return *this;
}
PktBuilder &src(TopoID src) {
src_i = src;
from_i = src;
return *this;
}
PktBuilder &dst(TopoID dst) {
dst_i = dst;
return *this;
}
PktBuilder &is_rsp(bool is_rsp) {
is_rsp_i = is_rsp;
return *this;
}
PktBuilder &is_sub_pkt(bool is_sub_pkt) {
is_sub_pkt_i = is_sub_pkt;
return *this;
}
Packet build() {
return Packet(id_i, type_i, addr_i, payload_i, burst_i, sent_i,
arrive_i, from_i, src_i, dst_i, is_rsp_i, is_sub_pkt_i);
}
};
typedef std::function<void()> EventFunc;
// Schedule an event at a specific tick.
void xerxes_schedule(EventFunc f, Tick tick);
// Check if there are any events in the global event queue.
bool xerxes_events_empty();
class Device;
Device *find_dev(TopoID id);
// A helper for devices to manage the happening time of events.
// Useful when events may be processed not in time order.
// Devices can then decide the schedule time of their events.
class Timeline {
public:
struct Scope {
Tick start;
Tick end;
bool operator<(const Scope &rhs) const { return end < rhs.end; }
Tick len() { return end > start ? end - start : 0; }
};
// Stores free scopes in the timeline.
std::map<Tick, Scope> scopes;
Timeline() { scopes[LONG_LONG_MAX] = Scope{0, LONG_LONG_MAX}; }
// Find the first existing free scope that:
// 1. Ending after or at tick arrive + delay.
// 2. The length of the scope is at least delay.
// Returns the starting time of the actual transfer,
// i.e., max(arrive, found_scope.start).
Tick transfer_time(Tick arrive, Tick delay) {
XerxesLogger::debug() << "Timeline transfer time: " << arrive
<< ", delay " << delay << std::endl;
auto it = scopes.lower_bound(arrive);
while (it != scopes.end() &&
it->second.end - std::max(it->second.start, arrive) < delay) {
XerxesLogger::debug() << "Skip scope " << it->second.start << "-"
<< it->second.end << std::endl;
it++;
}
ASSERT(it != scopes.end(), "Cannot find scope");
XerxesLogger::debug() << "Use scope " << it->second.start << "-"
<< it->second.end << std::endl;
auto &scope = it->second;
auto left = Scope{scope.start, std::max(scope.start, arrive)};
auto right = Scope{std::max(scope.start, arrive) + delay, scope.end};
auto ret = std::max(scope.start, arrive);
scopes.erase(it);
if (left.len() > 0) {
XerxesLogger::debug() << "Insert new scope " << left.start << "-"
<< left.end << std::endl;
scopes[left.end] = left;
}
if (right.len() > 0) {
XerxesLogger::debug() << "Insert new scope " << right.start << "-"
<< right.end << std::endl;
scopes[right.end] = right;
}
return ret;
}
};
} // namespace xerxes
#endif // XERXES_DEF_HH