arch,cpu,sim: Eliminate the now empty kernel statistics classes.
[gem5.git] / src / sim / system.cc
1 /*
2 * Copyright (c) 2011-2014,2017-2019 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2006 The Regents of The University of Michigan
15 * Copyright (c) 2011 Regents of the University of California
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42 #include "sim/system.hh"
43
44 #include <algorithm>
45
46 #include "arch/remote_gdb.hh"
47 #include "arch/utility.hh"
48 #include "base/loader/object_file.hh"
49 #include "base/loader/symtab.hh"
50 #include "base/str.hh"
51 #include "base/trace.hh"
52 #include "config/use_kvm.hh"
53 #if USE_KVM
54 #include "cpu/kvm/base.hh"
55 #include "cpu/kvm/vm.hh"
56 #endif
57 #include "cpu/base.hh"
58 #include "cpu/thread_context.hh"
59 #include "debug/Loader.hh"
60 #include "debug/Quiesce.hh"
61 #include "debug/WorkItems.hh"
62 #include "mem/abstract_mem.hh"
63 #include "mem/physical.hh"
64 #include "params/System.hh"
65 #include "sim/byteswap.hh"
66 #include "sim/debug.hh"
67 #include "sim/full_system.hh"
68 #include "sim/redirect_path.hh"
69
70 using namespace std;
71 using namespace TheISA;
72
73 vector<System *> System::systemList;
74
75 ContextID
76 System::Threads::insert(ThreadContext *tc, ContextID id)
77 {
78 if (id == InvalidContextID) {
79 for (id = 0; id < size(); id++) {
80 if (!threads[id].context)
81 break;
82 }
83 }
84
85 if (id >= size())
86 threads.resize(id + 1);
87
88 fatal_if(threads[id].context,
89 "Cannot have two thread contexts with the same id (%d).", id);
90
91 auto &t = thread(id);
92 t.context = tc;
93 # if THE_ISA != NULL_ISA
94 int port = getRemoteGDBPort();
95 if (port) {
96 t.gdb = new RemoteGDB(tc->getSystemPtr(), tc, port + id);
97 t.gdb->listen();
98 }
99 # endif
100
101 return id;
102 }
103
104 void
105 System::Threads::replace(ThreadContext *tc, ContextID id)
106 {
107 auto &t = thread(id);
108 t.context = tc;
109 if (t.gdb)
110 t.gdb->replaceThreadContext(tc);
111 }
112
113 ThreadContext *
114 System::Threads::findFree()
115 {
116 for (auto &thread: threads) {
117 if (thread.context->status() == ThreadContext::Halted)
118 return thread.context;
119 }
120 return nullptr;
121 }
122
123 int
124 System::Threads::numRunning() const
125 {
126 int count = 0;
127 for (auto &thread: threads) {
128 auto status = thread.context->status();
129 if (status != ThreadContext::Halted &&
130 status != ThreadContext::Halting) {
131 count++;
132 }
133 }
134 return count;
135 }
136
137 int System::numSystemsRunning = 0;
138
139 System::System(Params *p)
140 : SimObject(p), _systemPort("system_port", this),
141 multiThread(p->multi_thread),
142 pagePtr(0),
143 init_param(p->init_param),
144 physProxy(_systemPort, p->cache_line_size),
145 workload(p->workload),
146 #if USE_KVM
147 kvmVM(p->kvm_vm),
148 #else
149 kvmVM(nullptr),
150 #endif
151 physmem(name() + ".physmem", p->memories, p->mmap_using_noreserve),
152 memoryMode(p->mem_mode),
153 _cacheLineSize(p->cache_line_size),
154 workItemsBegin(0),
155 workItemsEnd(0),
156 numWorkIds(p->num_work_ids),
157 thermalModel(p->thermal_model),
158 _params(p),
159 _m5opRange(p->m5ops_base ?
160 RangeSize(p->m5ops_base, 0x10000) :
161 AddrRange(1, 0)), // Create an empty range if disabled
162 totalNumInsts(0),
163 redirectPaths(p->redirect_paths)
164 {
165 if (workload)
166 workload->system = this;
167
168 // add self to global system list
169 systemList.push_back(this);
170
171 #if USE_KVM
172 if (kvmVM) {
173 kvmVM->setSystem(this);
174 }
175 #endif
176
177 // check if the cache line size is a value known to work
178 if (!(_cacheLineSize == 16 || _cacheLineSize == 32 ||
179 _cacheLineSize == 64 || _cacheLineSize == 128))
180 warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n");
181
182 // Get the generic system master IDs
183 MasterID tmp_id M5_VAR_USED;
184 tmp_id = getMasterId(this, "writebacks");
185 assert(tmp_id == Request::wbMasterId);
186 tmp_id = getMasterId(this, "functional");
187 assert(tmp_id == Request::funcMasterId);
188 tmp_id = getMasterId(this, "interrupt");
189 assert(tmp_id == Request::intMasterId);
190
191 // increment the number of running systems
192 numSystemsRunning++;
193
194 // Set back pointers to the system in all memories
195 for (int x = 0; x < params()->memories.size(); x++)
196 params()->memories[x]->system(this);
197 }
198
199 System::~System()
200 {
201 for (uint32_t j = 0; j < numWorkIds; j++)
202 delete workItemStats[j];
203 }
204
205 void
206 System::init()
207 {
208 // check that the system port is connected
209 if (!_systemPort.isConnected())
210 panic("System port on %s is not connected.\n", name());
211 }
212
213 void
214 System::startup()
215 {
216 SimObject::startup();
217
218 // Now that we're about to start simulation, wait for GDB connections if
219 // requested.
220 #if THE_ISA != NULL_ISA
221 for (int i = 0; i < threads.size(); i++) {
222 auto *gdb = threads.thread(i).gdb;
223 auto *cpu = threads[i]->getCpuPtr();
224 if (gdb && cpu->waitForRemoteGDB()) {
225 inform("%s: Waiting for a remote GDB connection on port %d.",
226 cpu->name(), gdb->port());
227 gdb->connect();
228 }
229 }
230 #endif
231 }
232
233 Port &
234 System::getPort(const std::string &if_name, PortID idx)
235 {
236 // no need to distinguish at the moment (besides checking)
237 return _systemPort;
238 }
239
240 void
241 System::setMemoryMode(Enums::MemoryMode mode)
242 {
243 assert(drainState() == DrainState::Drained);
244 memoryMode = mode;
245 }
246
247 bool System::breakpoint()
248 {
249 if (!threads.size())
250 return false;
251 auto *gdb = threads.thread(0).gdb;
252 if (!gdb)
253 return false;
254 return gdb->breakpoint();
255 }
256
257 ContextID
258 System::registerThreadContext(ThreadContext *tc, ContextID assigned)
259 {
260 ContextID id = threads.insert(tc, assigned);
261
262 for (auto *e: liveEvents)
263 tc->schedule(e);
264
265 return id;
266 }
267
268 bool
269 System::schedule(PCEvent *event)
270 {
271 bool all = true;
272 liveEvents.push_back(event);
273 for (auto *tc: threads)
274 all = tc->schedule(event) && all;
275 return all;
276 }
277
278 bool
279 System::remove(PCEvent *event)
280 {
281 bool all = true;
282 liveEvents.remove(event);
283 for (auto *tc: threads)
284 all = tc->remove(event) && all;
285 return all;
286 }
287
288 void
289 System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
290 {
291 auto *otc = threads[context_id];
292 threads.replace(tc, context_id);
293
294 for (auto *e: liveEvents) {
295 otc->remove(e);
296 tc->schedule(e);
297 }
298 }
299
300 bool
301 System::validKvmEnvironment() const
302 {
303 #if USE_KVM
304 if (threads.empty())
305 return false;
306
307 for (auto *tc: threads) {
308 if (!dynamic_cast<BaseKvmCPU *>(tc->getCpuPtr()))
309 return false;
310 }
311
312 return true;
313 #else
314 return false;
315 #endif
316 }
317
318 Addr
319 System::allocPhysPages(int npages)
320 {
321 Addr return_addr = pagePtr << PageShift;
322 pagePtr += npages;
323
324 Addr next_return_addr = pagePtr << PageShift;
325
326 if (_m5opRange.contains(next_return_addr)) {
327 warn("Reached m5ops MMIO region\n");
328 return_addr = 0xffffffff;
329 pagePtr = 0xffffffff >> PageShift;
330 }
331
332 if ((pagePtr << PageShift) > physmem.totalSize())
333 fatal("Out of memory, please increase size of physical memory.");
334 return return_addr;
335 }
336
337 Addr
338 System::memSize() const
339 {
340 return physmem.totalSize();
341 }
342
343 Addr
344 System::freeMemSize() const
345 {
346 return physmem.totalSize() - (pagePtr << PageShift);
347 }
348
349 bool
350 System::isMemAddr(Addr addr) const
351 {
352 return physmem.isMemAddr(addr);
353 }
354
355 void
356 System::drainResume()
357 {
358 totalNumInsts = 0;
359 }
360
361 void
362 System::serialize(CheckpointOut &cp) const
363 {
364 SERIALIZE_SCALAR(pagePtr);
365
366 // also serialize the memories in the system
367 physmem.serializeSection(cp, "physmem");
368 }
369
370
371 void
372 System::unserialize(CheckpointIn &cp)
373 {
374 UNSERIALIZE_SCALAR(pagePtr);
375
376 // also unserialize the memories in the system
377 physmem.unserializeSection(cp, "physmem");
378 }
379
380 void
381 System::regStats()
382 {
383 SimObject::regStats();
384
385 for (uint32_t j = 0; j < numWorkIds ; j++) {
386 workItemStats[j] = new Stats::Histogram();
387 stringstream namestr;
388 ccprintf(namestr, "work_item_type%d", j);
389 workItemStats[j]->init(20)
390 .name(name() + "." + namestr.str())
391 .desc("Run time stat for" + namestr.str())
392 .prereq(*workItemStats[j]);
393 }
394 }
395
396 void
397 System::workItemEnd(uint32_t tid, uint32_t workid)
398 {
399 std::pair<uint32_t,uint32_t> p(tid, workid);
400 if (!lastWorkItemStarted.count(p))
401 return;
402
403 Tick samp = curTick() - lastWorkItemStarted[p];
404 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
405
406 if (workid >= numWorkIds)
407 fatal("Got workid greater than specified in system configuration\n");
408
409 workItemStats[workid]->sample(samp);
410 lastWorkItemStarted.erase(p);
411 }
412
413 void
414 System::printSystems()
415 {
416 ios::fmtflags flags(cerr.flags());
417
418 vector<System *>::iterator i = systemList.begin();
419 vector<System *>::iterator end = systemList.end();
420 for (; i != end; ++i) {
421 System *sys = *i;
422 cerr << "System " << sys->name() << ": " << hex << sys << endl;
423 }
424
425 cerr.flags(flags);
426 }
427
428 void
429 printSystems()
430 {
431 System::printSystems();
432 }
433
434 std::string
435 System::stripSystemName(const std::string& master_name) const
436 {
437 if (startswith(master_name, name())) {
438 return master_name.substr(name().size());
439 } else {
440 return master_name;
441 }
442 }
443
444 MasterID
445 System::lookupMasterId(const SimObject* obj) const
446 {
447 MasterID id = Request::invldMasterId;
448
449 // number of occurrences of the SimObject pointer
450 // in the master list.
451 auto obj_number = 0;
452
453 for (int i = 0; i < masters.size(); i++) {
454 if (masters[i].obj == obj) {
455 id = i;
456 obj_number++;
457 }
458 }
459
460 fatal_if(obj_number > 1,
461 "Cannot lookup MasterID by SimObject pointer: "
462 "More than one master is sharing the same SimObject\n");
463
464 return id;
465 }
466
467 MasterID
468 System::lookupMasterId(const std::string& master_name) const
469 {
470 std::string name = stripSystemName(master_name);
471
472 for (int i = 0; i < masters.size(); i++) {
473 if (masters[i].masterName == name) {
474 return i;
475 }
476 }
477
478 return Request::invldMasterId;
479 }
480
481 MasterID
482 System::getGlobalMasterId(const std::string& master_name)
483 {
484 return _getMasterId(nullptr, master_name);
485 }
486
487 MasterID
488 System::getMasterId(const SimObject* master, std::string submaster)
489 {
490 auto master_name = leafMasterName(master, submaster);
491 return _getMasterId(master, master_name);
492 }
493
494 MasterID
495 System::_getMasterId(const SimObject* master, const std::string& master_name)
496 {
497 std::string name = stripSystemName(master_name);
498
499 // CPUs in switch_cpus ask for ids again after switching
500 for (int i = 0; i < masters.size(); i++) {
501 if (masters[i].masterName == name) {
502 return i;
503 }
504 }
505
506 // Verify that the statistics haven't been enabled yet
507 // Otherwise objects will have sized their stat buckets and
508 // they will be too small
509
510 if (Stats::enabled()) {
511 fatal("Can't request a masterId after regStats(). "
512 "You must do so in init().\n");
513 }
514
515 // Generate a new MasterID incrementally
516 MasterID master_id = masters.size();
517
518 // Append the new Master metadata to the group of system Masters.
519 masters.emplace_back(master, name, master_id);
520
521 return masters.back().masterId;
522 }
523
524 std::string
525 System::leafMasterName(const SimObject* master, const std::string& submaster)
526 {
527 if (submaster.empty()) {
528 return master->name();
529 } else {
530 // Get the full master name by appending the submaster name to
531 // the root SimObject master name
532 return master->name() + "." + submaster;
533 }
534 }
535
536 std::string
537 System::getMasterName(MasterID master_id)
538 {
539 if (master_id >= masters.size())
540 fatal("Invalid master_id passed to getMasterName()\n");
541
542 const auto& master_info = masters[master_id];
543 return master_info.masterName;
544 }
545
546 System *
547 SystemParams::create()
548 {
549 return new System(this);
550 }