-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimpoint.cpp
More file actions
293 lines (260 loc) · 8.74 KB
/
simpoint.cpp
File metadata and controls
293 lines (260 loc) · 8.74 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
#include "ref.h"
#include <cstdint>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <zlib.h>
namespace {
constexpr uint32_t CKPT_MAGIC = 0x006d6552u; // "Rem\0" (little-endian)
constexpr uint32_t CKPT_VERSION = 2u;
constexpr uint32_t BOOT_IO_BASE = 0x00000000u;
constexpr uint32_t BOOT_IO_SIZE = 0x00002000u;
constexpr uint32_t LEGACY_TIMER_MMIO_SIZE = 0x8u;
struct CkptHeader {
uint32_t magic;
uint32_t version;
uint32_t ram_size;
uint32_t io_range_count;
};
struct CkptIoRange {
uint32_t base;
uint32_t size;
};
std::vector<CkptIoRange> expected_io_layout() {
return {
{BOOT_IO_BASE, BOOT_IO_SIZE},
{UART_BASE, UART_MMIO_SIZE},
{PLIC_BASE, PLIC_MMIO_SIZE},
{TIMER_BASE, LEGACY_TIMER_MMIO_SIZE},
};
}
template <typename T> void gz_write_pod(gzFile file, const T &data) {
if (gzwrite(file, &data, sizeof(T)) != sizeof(T)) {
std::cerr << "Error writing checkpoint data." << std::endl;
exit(1);
}
}
template <typename T> void gz_read_pod(gzFile file, T &data) {
if (gzread(file, &data, sizeof(T)) != sizeof(T)) {
std::cerr << "Error reading checkpoint data." << std::endl;
exit(1);
}
}
void gz_write_bytes(gzFile file, const void *buf, size_t len) {
if (len == 0) {
return;
}
if (gzwrite(file, buf, static_cast<unsigned int>(len)) != static_cast<int>(len)) {
std::cerr << "Error writing checkpoint payload." << std::endl;
exit(1);
}
}
void gz_read_bytes(gzFile file, void *buf, size_t len) {
if (len == 0) {
return;
}
if (gzread(file, buf, static_cast<unsigned int>(len)) != static_cast<int>(len)) {
std::cerr << "Error reading checkpoint payload." << std::endl;
exit(1);
}
}
} // namespace
void Ref_cpu::bbv_init_file(const char *filename) {
bbv_file.open(filename, std::ios::out | std::ios::trunc);
if (!bbv_file.is_open()) {
std::cerr << "Error: Could not open BBV output file!" << std::endl;
}
bbv_counts.resize(65536, 0);
}
void Ref_cpu::bbv_commit() {
// [ID 映射]:将 PC 转换为 SimPoint ID
uint32_t bb_id = 0;
auto it = global_pc_to_id.find(current_bb_head_pc);
if (it != global_pc_to_id.end()) {
bb_id = it->second; // 以前见过,用老 ID
} else {
bb_id = next_bb_id++; // 没见过,分配新 ID
global_pc_to_id[current_bb_head_pc] = bb_id;
}
if (bb_id >= bbv_counts.size()) {
// 策略:指数级扩容 (Geometric Growth)
// 比如每次扩大 2 倍,避免每次只加 1 导致频繁申请内存
// 如果 id 突然变得很大,至少要扩容到 id + 1
size_t new_size = bbv_counts.size() * 2;
if (new_size <= bb_id)
new_size = bb_id + 1024;
// resize 会自动把新增加的部分初始化为 0
bbv_counts.resize(new_size, 0);
}
// 3. [统计]:当前切片计数
bbv_counts[bb_id] += current_bb_len;
}
void Ref_cpu::dump_bbv() {
static int count = 0;
bbv_file << "T";
// 遍历 vector,只要非零的都输出
for (size_t id = 1; id < bbv_counts.size(); ++id) {
if (bbv_counts[id] > 0) {
bbv_file << " :" << id << ":" << bbv_counts[id];
bbv_counts[id] = 0; // 输出完清零,为下一轮做准备
}
}
bbv_file << "\n";
std::cout << "bbv dump:" << count++ << std::endl;
}
void Ref_cpu::save_checkpoint(const std::string &filename) {
std::string final_name = filename;
if (final_name.size() < 3 ||
final_name.substr(final_name.size() - 3) != ".gz") {
final_name += ".gz";
}
gzFile file = gzopen(final_name.c_str(), "wb1"); // wb1 速度最快
if (!file) {
std::cerr << "Error: Could not open file: " << final_name << std::endl;
exit(1);
}
const auto io_layout = expected_io_layout();
CkptHeader header = {
CKPT_MAGIC,
CKPT_VERSION,
ram_size,
static_cast<uint32_t>(io_layout.size()),
};
gz_write_pod(file, header);
// 1. 保存 CPU 状态
gz_write_pod(file, state);
gz_write_pod(file, interval_inst_count);
// 2. 保存 RAM
if (ram_size == 0 || memory == nullptr) {
std::cerr << "Error: Invalid RAM buffer when saving checkpoint." << std::endl;
exit(1);
}
std::cout << "Saving Memory: " << (ram_size / sizeof(uint32_t)) << " words ("
<< (ram_size / 1024 / 1024) << " MB)..." << std::endl;
gz_write_bytes(file, reinterpret_cast<const uint8_t *>(memory), ram_size);
// 3. 保存 IO 布局(base + size)
for (const auto &r : io_layout) {
gz_write_pod(file, r);
std::vector<uint8_t> io_bytes(r.size, 0);
for (const auto &kv : io_words) {
if (kv.first < r.base) {
continue;
}
const uint64_t off = static_cast<uint64_t>(kv.first) - r.base;
if (off + sizeof(uint32_t) > r.size) {
continue;
}
io_bytes[off + 0] = static_cast<uint8_t>(kv.second & 0xFF);
io_bytes[off + 1] = static_cast<uint8_t>((kv.second >> 8) & 0xFF);
io_bytes[off + 2] = static_cast<uint8_t>((kv.second >> 16) & 0xFF);
io_bytes[off + 3] = static_cast<uint8_t>((kv.second >> 24) & 0xFF);
}
gz_write_bytes(file, io_bytes.data(), io_bytes.size());
}
gzclose(file);
std::cout << "Checkpoint saved to " << final_name << std::endl;
}
void Ref_cpu::restore_checkpoint(const std::string &filename) {
std::string final_name = filename;
gzFile file = gzopen(final_name.c_str(), "rb");
if (!file && final_name.find(".gz") == std::string::npos) {
final_name += ".gz";
file = gzopen(final_name.c_str(), "rb");
}
if (!file) {
std::cerr << "Error: Could not open file: " << filename << std::endl;
exit(1);
}
CkptHeader header = {};
gz_read_pod(file, header);
if (header.magic != CKPT_MAGIC) {
std::cerr << "Error: Invalid checkpoint magic." << std::endl;
exit(1);
}
if (header.version != CKPT_VERSION) {
std::cerr << "Error: Unsupported checkpoint version: " << header.version
<< std::endl;
exit(1);
}
if (header.ram_size != ram_size) {
std::cerr << "Error: Checkpoint RAM size mismatch. file=0x" << std::hex
<< header.ram_size << " sim=0x" << ram_size << std::dec
<< std::endl;
exit(1);
}
// 1. 恢复 CPU 状态
gz_read_pod(file, state);
gz_read_pod(file, interval_inst_count);
// 2. 恢复 RAM
if (memory == nullptr) {
std::cerr << "Error: Memory not allocated." << std::endl;
exit(1);
}
std::cout << "Restoring Memory..." << std::endl;
gz_read_bytes(file, reinterpret_cast<uint8_t *>(memory), ram_size);
// 3. 恢复并校验 IO 布局(base + size)
const auto io_layout = expected_io_layout();
if (header.io_range_count != io_layout.size()) {
std::cerr << "Error: IO layout count mismatch. file="
<< header.io_range_count << " sim=" << io_layout.size()
<< std::endl;
exit(1);
}
io_words.clear();
for (uint32_t i = 0; i < header.io_range_count; ++i) {
CkptIoRange r = {};
gz_read_pod(file, r);
if (r.base != io_layout[i].base || r.size != io_layout[i].size) {
std::cerr << "Error: IO layout mismatch at index " << i << ". file=[0x"
<< std::hex << r.base << ", 0x" << r.size << "] sim=[0x"
<< io_layout[i].base << ", 0x" << io_layout[i].size << "]"
<< std::dec << std::endl;
exit(1);
}
std::vector<uint8_t> io_bytes(r.size, 0);
gz_read_bytes(file, io_bytes.data(), io_bytes.size());
for (uint32_t off = 0; off + 4 <= r.size; off += 4) {
uint32_t word = static_cast<uint32_t>(io_bytes[off + 0]) |
(static_cast<uint32_t>(io_bytes[off + 1]) << 8) |
(static_cast<uint32_t>(io_bytes[off + 2]) << 16) |
(static_cast<uint32_t>(io_bytes[off + 3]) << 24);
if (word != 0) {
io_words[r.base + off] = word;
}
}
}
gzclose(file);
std::cout << "Checkpoint restored from " << final_name << std::endl;
}
// 辅助结构:记录 SimPoint ID 和 对应的 Interval ID
struct PointInfo {
uint32_t sp_id; // SimPoint ID (例如 0, 1, 2...)
uint32_t interval_id; // 对应的 Interval 编号 (例如 105, 2000...)
};
std::map<uint32_t, uint32_t> load_simpoints(const std::string &filename) {
std::map<uint32_t, uint32_t> targets;
std::ifstream in(filename);
if (!in) {
std::cerr << "Error: Could not open points file: " << filename << std::endl;
exit(1);
}
std::string line;
while (std::getline(in, line)) {
// 跳过空行和注释
if (line.empty() || line[0] == '#')
continue;
std::stringstream ss(line);
uint32_t interval_id, sp_id;
// data format: <Interval_ID> <SimPoint_ID>
// Example: 1824 0
if (ss >> interval_id >> sp_id) {
targets[interval_id] = sp_id;
// 调试输出,确保读入正确
std::cout << "Target: Interval " << interval_id << " -> SP " << sp_id
<< std::endl;
}
}
return targets;
}