misc: merge branch 'release-staging-v19.0.0.0' into develop
[gem5.git] / src / sim / cxx_manager.cc
1 /*
2 * Copyright (c) 2014 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 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "sim/cxx_manager.hh"
39
40 #include <cstdlib>
41 #include <sstream>
42
43 #include "base/str.hh"
44 #include "base/trace.hh"
45 #include "debug/CxxConfig.hh"
46 #include "sim/serialize.hh"
47 #include "sim/sim_object.hh"
48
49 CxxConfigManager::CxxConfigManager(CxxConfigFileBase &configFile_) :
50 configFile(configFile_), flags(configFile_.getFlags()),
51 simObjectResolver(*this)
52 {
53 }
54
55 const CxxConfigDirectoryEntry &
56 CxxConfigManager::findObjectType(const std::string &object_name,
57 std::string &object_type)
58 {
59 if (!configFile.objectExists(object_name))
60 throw Exception(object_name, "Can't find sim object");
61
62 if (!configFile.getParam(object_name, "type", object_type))
63 throw Exception(object_name, "Sim object has no 'type' field");
64
65 if (cxx_config_directory.find(object_type) ==
66 cxx_config_directory.end())
67 {
68 throw Exception(object_name, csprintf(
69 "No sim object type %s is available", object_type));
70 }
71
72 const CxxConfigDirectoryEntry *entry = cxx_config_directory[object_type];
73
74 return *entry;
75 }
76
77 std::string
78 CxxConfigManager::rename(const std::string &from_name)
79 {
80 for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
81 const Renaming &renaming = *i;
82
83 if (from_name.find(renaming.fromPrefix) == 0) {
84 return renaming.toPrefix +
85 from_name.substr(renaming.fromPrefix.length());
86 }
87 }
88
89 return from_name;
90 }
91
92 std::string
93 CxxConfigManager::unRename(const std::string &to_name)
94 {
95 for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
96 const Renaming &renaming = *i;
97
98 if (to_name.find(renaming.toPrefix) == 0) {
99 return renaming.fromPrefix +
100 to_name.substr(renaming.toPrefix.length());
101 }
102 }
103
104 return to_name;
105 }
106
107 static
108 std::string formatParamList(const std::vector<std::string> &param_values)
109 {
110 std::ostringstream params;
111
112 auto i = param_values.begin();
113 auto end_i = param_values.end();
114
115 params << '[';
116 while (i != end_i) {
117 params << (*i);
118 ++i;
119
120 if (i != end_i)
121 params << ", ";
122 }
123 params << ']';
124
125 return params.str();
126 }
127
128 SimObject *
129 CxxConfigManager::findObject(const std::string &object_name,
130 bool visit_children)
131 {
132 std::string instance_name = rename(object_name);
133
134 if (object_name == "Null")
135 return NULL;
136
137 /* Already constructed */
138 if (objectsByName.find(instance_name) != objectsByName.end())
139 return objectsByName[instance_name];
140
141 if (inVisit.find(instance_name) != inVisit.end())
142 throw Exception(instance_name, "Cycle in configuration");
143
144 std::string object_type;
145 const CxxConfigDirectoryEntry &entry =
146 findObjectType(object_name, object_type);
147
148 SimObject *object = NULL;
149
150 CxxConfigParams *object_params = findObjectParams(object_name);
151
152 try {
153 DPRINTF(CxxConfig, "Configuring sim object references for: %s"
154 " (%s from object %s)\n", instance_name, object_type,
155 object_name);
156
157 /* Remember the path back to the top of the recursion to detect
158 * cycles */
159 inVisit.insert(instance_name);
160
161 /* Resolve pointed-to SimObjects by recursing into them */
162 for (auto i = entry.parameters.begin();
163 i != entry.parameters.end(); ++i)
164 {
165 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
166
167 if (param->isSimObject) {
168 if (param->isVector) {
169 std::vector<std::string> sub_object_names;
170
171 if (!configFile.getParamVector(object_name, param->name,
172 sub_object_names))
173 {
174 throw Exception(object_name, csprintf(
175 "Element not found: %s", param->name));
176 }
177
178 std::vector<SimObject *> sub_objects;
179
180 for (auto n = sub_object_names.begin();
181 n != sub_object_names.end(); ++n)
182 {
183 SimObject *sub_object = findObject(*n,
184 visit_children);
185
186 if (sub_object)
187 sub_objects.push_back(sub_object);
188 }
189
190 if (!object_params->setSimObjectVector(param->name,
191 sub_objects))
192 {
193 throw Exception(object_name, csprintf(
194 "Can't assign sim object element %s from \"%s\"",
195 param->name, formatParamList(sub_object_names)));
196 }
197
198 DPRINTF(CxxConfig, "Setting sim object(s): %s.%s=%s\n",
199 object_name, param->name,
200 formatParamList(sub_object_names));
201 } else {
202 std::string sub_object_name;
203
204 if (!configFile.getParam(object_name, param->name,
205 sub_object_name))
206 {
207 throw Exception(object_name, csprintf(
208 "Element not found: %s", param->name));
209 }
210
211 SimObject *sub_object = findObject(sub_object_name,
212 visit_children);
213
214 if (sub_object) {
215 if (!object_params->setSimObject(param->name,
216 sub_object))
217 {
218 throw Exception(object_name, csprintf(
219 "Can't assign sim object element %s from"
220 " \"%s\"", param->name, sub_object_name));
221 }
222 }
223
224 DPRINTF(CxxConfig, "Setting sim object(s):"
225 " %s.%s=%s\n", object_name, param->name,
226 sub_object_name);
227 }
228 }
229 }
230
231 DPRINTF(CxxConfig, "Creating SimObject: %s\n", instance_name);
232 object = object_params->simObjectCreate();
233
234 if (!object) {
235 throw Exception(object_name, csprintf("Couldn't create object of"
236 " type: %s", object_type));
237 }
238
239 objectsByName[instance_name] = object;
240 objectParamsByName[instance_name] = object_params;
241
242 if (visit_children) {
243 std::vector<std::string> children;
244 configFile.getObjectChildren(object_name, children, true);
245
246 /* Visit all your children */
247 for (auto i = children.begin(); i != children.end(); ++i)
248 findObject(*i, visit_children);
249 }
250 } catch (Exception &) {
251 delete object_params;
252 throw;
253 }
254
255 /* Mark that we've exited object
256 * construction and so 'find'ing this object again won't be a
257 * configuration loop */
258 inVisit.erase(object_name);
259 return object;
260 }
261
262 CxxConfigParams *
263 CxxConfigManager::findObjectParams(const std::string &object_name)
264 {
265 std::string instance_name = rename(object_name);
266
267 /* Already constructed */
268 if (objectParamsByName.find(instance_name) != objectParamsByName.end())
269 return objectParamsByName[instance_name];
270
271 std::string object_type;
272 const CxxConfigDirectoryEntry &entry =
273 findObjectType(object_name, object_type);
274
275 DPRINTF(CxxConfig, "Configuring parameters of object: %s (%s)\n",
276 instance_name, object_type);
277
278 CxxConfigParams *object_params = entry.makeParamsObject();
279
280 try {
281 /* Fill in the implicit parameters that don't necessarily
282 * appear in config files */
283 object_params->setName(instance_name);
284
285 /* Fill in parameters */
286 for (auto i = entry.parameters.begin();
287 i != entry.parameters.end(); ++i)
288 {
289 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
290
291 if (!param->isSimObject) {
292 /* Only handle non-SimObject parameters here (see below) */
293
294 if (param->isVector) {
295 std::vector<std::string> param_values;
296
297 if (!configFile.getParamVector(object_name, param->name,
298 param_values))
299 {
300 throw Exception(object_name, csprintf(
301 "Element not found for parameter: %s",
302 param->name));
303 }
304
305 if (!object_params->setParamVector(param->name,
306 param_values, flags))
307 {
308 throw Exception(instance_name, csprintf(
309 "Bad parameter value: .%s=X=\"%s\"",
310 param->name, formatParamList(param_values)));
311 }
312
313 DPRINTF(CxxConfig, "Setting parameter"
314 " %s.%s=%s\n", instance_name, param->name,
315 formatParamList(param_values));
316 } else {
317 std::string param_value;
318
319 if (!configFile.getParam(object_name, param->name,
320 param_value))
321 {
322 throw Exception(object_name, csprintf(
323 "Element not found for parameter: %s",
324 param->name));
325 }
326
327 if (!object_params->setParam(param->name, param_value,
328 flags))
329 {
330 throw Exception(instance_name, csprintf(
331 "Bad parameter value: .%s=X=\"%s\"",
332 param->name, param_value));
333 }
334
335 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
336 instance_name, param->name, param_value);
337 }
338 }
339 }
340
341 /* Find the number of ports that will need binding and set the
342 * appropriate port_..._connection_count parameters */
343 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
344 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
345 std::vector<std::string> peers;
346
347 if (!configFile.getPortPeers(object_name, port->name, peers)) {
348 DPRINTF(CxxConfig, "Port not found: %s.%s,"
349 " assuming there are no connections\n",
350 instance_name, port->name);
351 }
352
353 unsigned int peer_count = peers.size();
354
355 /* It would be more efficient to split the peer list and
356 * save the values for peer binding later but that would
357 * require another annoying intermediate structure to
358 * hold for little performance increase */
359
360 if (!object_params->setPortConnectionCount(port->name,
361 peer_count))
362 {
363 throw Exception(instance_name, csprintf(
364 "Unconnected port: %s", port->name));
365 }
366
367 DPRINTF(CxxConfig, "Setting port connection count"
368 " for: %s.%s to %d\n",
369 instance_name, port->name, peer_count);
370 }
371
372 /* Set pointed-to SimObjects to NULL */
373 for (auto i = entry.parameters.begin();
374 i != entry.parameters.end(); ++i)
375 {
376 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
377
378 if (param->isSimObject) {
379 bool ret;
380
381 DPRINTF(CxxConfig, "Nulling sim object reference: %s.%s\n",
382 instance_name, param->name);
383
384 if (param->isVector) {
385 /* Clear the reference list. */
386 std::vector<SimObject *> empty;
387 ret = object_params->setSimObjectVector(param->name,
388 empty);
389 } else {
390 ret = object_params->setSimObject(param->name, NULL);
391 }
392
393 if (!ret) {
394 throw Exception(instance_name, csprintf(
395 "Error nulling sim object reference(s): %s",
396 param->name));
397 }
398 }
399 }
400 } catch (Exception &) {
401 delete object_params;
402 throw;
403 }
404
405 objectParamsByName[instance_name] = object_params;
406
407 return object_params;
408 }
409
410 void
411 CxxConfigManager::findAllObjects()
412 {
413 std::vector<std::string> objects;
414 configFile.getAllObjectNames(objects);
415
416 /* Set the traversal order for further iterators */
417 objectsInOrder.clear();
418 findTraversalOrder("root");
419 }
420
421 void
422 CxxConfigManager::findTraversalOrder(const std::string &object_name)
423 {
424 SimObject *object = findObject(object_name);
425
426 if (object) {
427 objectsInOrder.push_back(object);
428
429 std::vector<std::string> children;
430 configFile.getObjectChildren(object_name, children, true);
431
432 /* Visit all your children */
433 for (auto i = children.begin(); i != children.end(); ++i)
434 findTraversalOrder(*i);
435 }
436 }
437
438 void
439 CxxConfigManager::bindAllPorts()
440 {
441 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
442 bindObjectPorts(*i);
443 }
444
445 void
446 CxxConfigManager::bindPort(
447 SimObject *master_object, const std::string &master_port_name,
448 PortID master_port_index,
449 SimObject *slave_object, const std::string &slave_port_name,
450 PortID slave_port_index)
451 {
452 /* FIXME, check slave_port_index against connection_count
453 * defined for port, need getPortConnectionCount and a
454 * getCxxConfigDirectoryEntry for each object. */
455
456 /* It would be nice to be able to catch the errors from these calls. */
457 Port &master_port = master_object->getPort(
458 master_port_name, master_port_index);
459 Port &slave_port = slave_object->getPort(
460 slave_port_name, slave_port_index);
461
462 if (master_port.isConnected()) {
463 throw Exception(master_object->name(), csprintf(
464 "Master port: %s[%d] is already connected\n", master_port_name,
465 master_port_index));
466 }
467
468 if (slave_port.isConnected()) {
469 throw Exception(slave_object->name(), csprintf(
470 "Slave port: %s[%d] is already connected\n", slave_port_name,
471 slave_port_index));
472 }
473
474 DPRINTF(CxxConfig, "Binding port %s.%s[%d]"
475 " to %s:%s[%d]\n",
476 master_object->name(), master_port_name, master_port_index,
477 slave_object->name(), slave_port_name, slave_port_index);
478
479 master_port.bind(slave_port);
480 }
481
482 void
483 CxxConfigManager::bindMasterPort(SimObject *object,
484 const CxxConfigDirectoryEntry::PortDesc &port,
485 const std::vector<std::string> &peers)
486 {
487 unsigned int master_port_index = 0;
488
489 for (auto peer_i = peers.begin(); peer_i != peers.end();
490 ++peer_i)
491 {
492 const std::string &peer = *peer_i;
493 std::string slave_object_name;
494 std::string slave_port_name;
495 unsigned int slave_port_index;
496
497 parsePort(peer, slave_object_name, slave_port_name,
498 slave_port_index);
499
500 std::string slave_instance_name = rename(slave_object_name);
501
502 if (objectsByName.find(slave_instance_name) == objectsByName.end()) {
503 throw Exception(object->name(), csprintf(
504 "Can't find slave port object: %s", slave_instance_name));
505 }
506
507 SimObject *slave_object = objectsByName[slave_instance_name];
508
509 bindPort(object, port.name, master_port_index,
510 slave_object, slave_port_name, slave_port_index);
511
512 master_port_index++;
513 }
514 }
515
516 void
517 CxxConfigManager::bindObjectPorts(SimObject *object)
518 {
519 /* We may want to separate object->name() from the name in configuration
520 * later to allow (for example) repetition of fragments of configs */
521 const std::string &instance_name = object->name();
522
523 std::string object_name = unRename(instance_name);
524
525 std::string object_type;
526 const CxxConfigDirectoryEntry &entry =
527 findObjectType(object_name, object_type);
528
529 DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n",
530 instance_name, object_type);
531
532 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
533 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
534
535 DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name,
536 port->name);
537
538 std::vector<std::string> peers;
539 configFile.getPortPeers(object_name, port->name, peers);
540
541 /* Only handle master ports as binding only needs to happen once
542 * for each observed pair of ports */
543 if (port->isMaster) {
544 if (!port->isVector && peers.size() > 1) {
545 throw Exception(instance_name, csprintf(
546 "Too many connections to non-vector port %s (%d)\n",
547 port->name, peers.size()));
548 }
549
550 bindMasterPort(object, *port, peers);
551 }
552 }
553 }
554
555 void
556 CxxConfigManager::parsePort(const std::string &inp,
557 std::string &path, std::string &port, unsigned int &index)
558 {
559 std::size_t dot_i = inp.rfind('.');
560 std::size_t open_square_i = inp.rfind('[');
561
562 if (dot_i == std::string::npos) {
563 DPRINTF(CxxConfig, "Bad port string: %s\n", inp);
564 path = "";
565 port = "";
566 index = 0;
567 } else {
568 path = std::string(inp, 0, dot_i);
569
570 if (open_square_i == std::string::npos) {
571 /* Singleton port */
572 port = std::string(inp, dot_i + 1, inp.length() - dot_i);
573 index = 0;
574 } else {
575 /* Vectored port elemnt */
576 port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i);
577 index = std::atoi(inp.c_str() + open_square_i + 1);
578 }
579 }
580 }
581
582 void
583 CxxConfigManager::forEachObject(void (SimObject::*mem_func)())
584 {
585 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
586 ((*i)->*mem_func)();
587 }
588
589 void
590 CxxConfigManager::instantiate(bool build_all)
591 {
592 if (build_all) {
593 findAllObjects();
594 bindAllPorts();
595 }
596
597 DPRINTF(CxxConfig, "Initialising all objects\n");
598 forEachObject(&SimObject::init);
599
600 DPRINTF(CxxConfig, "Registering stats\n");
601 forEachObject(&SimObject::regStats);
602
603 DPRINTF(CxxConfig, "Registering probe points\n");
604 forEachObject(&SimObject::regProbePoints);
605
606 DPRINTF(CxxConfig, "Connecting probe listeners\n");
607 forEachObject(&SimObject::regProbeListeners);
608 }
609
610 void
611 CxxConfigManager::initState()
612 {
613 DPRINTF(CxxConfig, "Calling initState on all objects\n");
614 forEachObject(&SimObject::initState);
615 }
616
617 void
618 CxxConfigManager::startup()
619 {
620 DPRINTF(CxxConfig, "Starting up all objects\n");
621 forEachObject(&SimObject::startup);
622 }
623
624 unsigned int
625 CxxConfigManager::drain()
626 {
627 return DrainManager::instance().tryDrain() ? 0 : 1;
628 }
629
630 void
631 CxxConfigManager::drainResume()
632 {
633 DrainManager::instance().resume();
634 }
635
636 void
637 CxxConfigManager::serialize(std::ostream &os)
638 {
639 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) {
640 // (*i)->nameOut(os); FIXME, change access spec. for nameOut
641 os << '[' << (*i)->name() << "]\n";
642 (*i)->serialize(os);
643 }
644 }
645
646 void
647 CxxConfigManager::loadState(CheckpointIn &checkpoint)
648 {
649 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
650 (*i)->loadState(checkpoint);
651 }
652
653 void
654 CxxConfigManager::deleteObjects()
655 {
656 for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) {
657 DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name());
658 delete *i;
659 }
660
661 for (auto i = objectParamsByName.rbegin();
662 i != objectParamsByName.rend(); ++i)
663 {
664 CxxConfigParams *params = (*i).second;
665
666 DPRINTF(CxxConfig, "Freeing sim object params: %s\n",
667 params->getName());
668 delete params;
669 }
670
671 objectsInOrder.clear();
672 objectsByName.clear();
673 }
674
675 void
676 CxxConfigManager::setParam(const std::string &object_name,
677 const std::string &param_name, const std::string &param_value)
678 {
679 CxxConfigParams *params = findObjectParams(object_name);
680
681 if (!params->setParam(param_name, param_value, flags)) {
682 throw Exception(object_name, csprintf("Bad parameter value:"
683 " .%s=X=\"%s\"", param_name, param_value));
684 } else {
685 std::string instance_name = rename(object_name);
686
687 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
688 instance_name, param_name, param_value);
689 }
690 }
691
692 void
693 CxxConfigManager::setParamVector(const std::string &object_name,
694 const std::string &param_name,
695 const std::vector<std::string> &param_values)
696 {
697 CxxConfigParams *params = findObjectParams(object_name);
698
699 if (!params->setParamVector(param_name, param_values, flags)) {
700 throw Exception(object_name, csprintf("Bad vector parameter value:"
701 " .%s=X=\"%s\"", param_name, formatParamList(param_values)));
702 } else {
703 std::string instance_name = rename(object_name);
704
705 DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n",
706 instance_name, param_name, formatParamList(param_values));
707 }
708 }
709
710 void CxxConfigManager::addRenaming(const Renaming &renaming)
711 {
712 renamings.push_back(renaming);
713 }