1/* 2 * Copyright (c) 2017 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) 2006 The Regents of The University of Michigan 15 * Copyright (c) 2013 Advanced Micro Devices, Inc. 16 * Copyright (c) 2013 Mark D. Hill and David A. Wood 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions are 21 * met: redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer; 23 * redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution; 26 * neither the name of the copyright holders nor the names of its 27 * contributors may be used to endorse or promote products derived from 28 * this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 * 42 * Authors: Nathan Binkert 43 * Andreas Sandberg 44 */ 45 46#include "pybind11/pybind11.h" 47#include "pybind11/stl.h" 48
| 1/* 2 * Copyright (c) 2017 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) 2006 The Regents of The University of Michigan 15 * Copyright (c) 2013 Advanced Micro Devices, Inc. 16 * Copyright (c) 2013 Mark D. Hill and David A. Wood 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms, with or without 20 * modification, are permitted provided that the following conditions are 21 * met: redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer; 23 * redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution; 26 * neither the name of the copyright holders nor the names of its 27 * contributors may be used to endorse or promote products derived from 28 * this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 * 42 * Authors: Nathan Binkert 43 * Andreas Sandberg 44 */ 45 46#include "pybind11/pybind11.h" 47#include "pybind11/stl.h" 48
|
| 49#include "base/misc.hh"
|
49#include "sim/eventq.hh" 50#include "sim/sim_events.hh" 51#include "sim/sim_exit.hh" 52#include "sim/simulate.hh" 53 54namespace py = pybind11; 55
| 50#include "sim/eventq.hh" 51#include "sim/sim_events.hh" 52#include "sim/sim_exit.hh" 53#include "sim/simulate.hh" 54 55namespace py = pybind11; 56
|
| 57
|
56/** 57 * PyBind wrapper for Events 58 * 59 * We need to wrap the Event class with some Python glue code to 60 * enable method overrides in Python and memory management. Unlike its 61 * C++ cousin, PyEvents need to override __call__ instead of 62 * Event::process(). 63 *
| 58/** 59 * PyBind wrapper for Events 60 * 61 * We need to wrap the Event class with some Python glue code to 62 * enable method overrides in Python and memory management. Unlike its 63 * C++ cousin, PyEvents need to override __call__ instead of 64 * Event::process(). 65 *
|
64 * Memory management is mostly done using reference counting in 65 * Python. However, PyBind can't keep track of the reference the event 66 * queue holds to a scheduled event. We therefore need to inhibit 67 * deletion and hand over ownership to the event queue in case a 68 * scheduled event loses all of its Python references.
| 66 * Memory management is done using reference counting in Python.
|
69 */ 70class PyEvent : public Event 71{ 72 public:
| 67 */ 68class PyEvent : public Event 69{ 70 public:
|
73 struct Deleter { 74 void operator()(PyEvent *ev) { 75 assert(!ev->isAutoDelete()); 76 if (ev->scheduled()) { 77 // The event is scheduled, give ownership to the event 78 // queue. 79 ev->setFlags(Event::AutoDelete); 80 } else { 81 // The event isn't scheduled, hence Python owns it and 82 // we need to free it here. 83 delete ev; 84 } 85 } 86 }; 87
| |
88 PyEvent(Event::Priority priority)
| 71 PyEvent(Event::Priority priority)
|
89 : Event(priority) 90 { }
| 72 : Event(priority, Event::Managed) 73 { 74 }
|
91 92 void process() override {
| 75 76 void process() override {
|
93 if (isAutoDelete()) { 94 // Ownership of the event was handed over to the event queue 95 // because the last revference in Python land was GCed. We 96 // need to claim the object again since we're creating a new 97 // Python reference. 98 clearFlags(AutoDelete); 99 } 100
| |
101 // Call the Python implementation as __call__. This provides a 102 // slightly more Python-friendly interface. 103 PYBIND11_OVERLOAD_PURE_NAME(void, PyEvent, "__call__", process); 104 }
| 77 // Call the Python implementation as __call__. This provides a 78 // slightly more Python-friendly interface. 79 PYBIND11_OVERLOAD_PURE_NAME(void, PyEvent, "__call__", process); 80 }
|
| 81 82 protected: 83 void acquireImpl() override { 84 py::object obj = py::cast(this); 85 86 if (obj) { 87 obj.inc_ref(); 88 } else { 89 panic("Failed to get PyBind object to increase ref count\n"); 90 } 91 } 92 93 void releaseImpl() override { 94 py::object obj = py::cast(this); 95 96 if (obj) { 97 obj.dec_ref(); 98 } else { 99 panic("Failed to get PyBind object to decrease ref count\n"); 100 } 101 }
|
105}; 106 107void 108pybind_init_event(py::module &m_native) 109{ 110 py::module m = m_native.def_submodule("event"); 111 112 m.def("simulate", &simulate, 113 py::arg("ticks") = MaxTick); 114 m.def("exitSimLoop", &exitSimLoop); 115 m.def("getEventQueue", []() { return curEventQueue(); }, 116 py::return_value_policy::reference); 117 m.def("setEventQueue", [](EventQueue *q) { return curEventQueue(q); }); 118 m.def("getEventQueue", &getEventQueue, 119 py::return_value_policy::reference); 120 121 py::class_<EventQueue>(m, "EventQueue") 122 .def("name", [](EventQueue *eq) { return eq->name(); }) 123 .def("dump", &EventQueue::dump) 124 .def("schedule", [](EventQueue *eq, PyEvent *e, Tick t) { 125 eq->schedule(e, t); 126 }, py::arg("event"), py::arg("when"))
| 102}; 103 104void 105pybind_init_event(py::module &m_native) 106{ 107 py::module m = m_native.def_submodule("event"); 108 109 m.def("simulate", &simulate, 110 py::arg("ticks") = MaxTick); 111 m.def("exitSimLoop", &exitSimLoop); 112 m.def("getEventQueue", []() { return curEventQueue(); }, 113 py::return_value_policy::reference); 114 m.def("setEventQueue", [](EventQueue *q) { return curEventQueue(q); }); 115 m.def("getEventQueue", &getEventQueue, 116 py::return_value_policy::reference); 117 118 py::class_<EventQueue>(m, "EventQueue") 119 .def("name", [](EventQueue *eq) { return eq->name(); }) 120 .def("dump", &EventQueue::dump) 121 .def("schedule", [](EventQueue *eq, PyEvent *e, Tick t) { 122 eq->schedule(e, t); 123 }, py::arg("event"), py::arg("when"))
|
127 .def("deschedule", [](EventQueue *eq, PyEvent *e) { 128 eq->deschedule(e); 129 }, py::arg("event")) 130 .def("reschedule", [](EventQueue *eq, PyEvent *e, Tick t, bool alw) { 131 eq->reschedule(e, t, alw); 132 }, py::arg("event"), py::arg("tick"), py::arg("always") = false)
| 124 .def("deschedule", &EventQueue::deschedule, 125 py::arg("event")) 126 .def("reschedule", &EventQueue::reschedule, 127 py::arg("event"), py::arg("tick"), py::arg("always") = false)
|
133 ; 134 135 // TODO: Ownership of global exit events has always been a bit 136 // questionable. We currently assume they are owned by the C++
| 128 ; 129 130 // TODO: Ownership of global exit events has always been a bit 131 // questionable. We currently assume they are owned by the C++
|
137 // word. This is what the old SWIG code did, but that will result
| 132 // world. This is what the old SWIG code did, but that will result
|
138 // in memory leaks. 139 py::class_<GlobalSimLoopExitEvent, 140 std::unique_ptr<GlobalSimLoopExitEvent, py::nodelete>>( 141 m, "GlobalSimLoopExitEvent") 142 .def("getCause", &GlobalSimLoopExitEvent::getCause) 143 .def("getCode", &GlobalSimLoopExitEvent::getCode) 144 ; 145
| 133 // in memory leaks. 134 py::class_<GlobalSimLoopExitEvent, 135 std::unique_ptr<GlobalSimLoopExitEvent, py::nodelete>>( 136 m, "GlobalSimLoopExitEvent") 137 .def("getCause", &GlobalSimLoopExitEvent::getCause) 138 .def("getCode", &GlobalSimLoopExitEvent::getCode) 139 ; 140
|
146 // TODO: We currently export a wrapper class and not the Event 147 // base class. This wil be problematic if we ever return an event 148 // from C++. 149 py::class_<PyEvent, std::unique_ptr<PyEvent, PyEvent::Deleter>> 150 c_event(m, "Event");
| 141 // Event base class. These should never be returned directly to 142 // Python since they don't have a well-defined life cycle. Python 143 // events should be derived from PyEvent instead. 144 py::class_<Event> c_event( 145 m, "Event");
|
151 c_event
| 146 c_event
|
152 .def(py::init<Event::Priority>(), 153 py::arg("priority") = (int)Event::Default_Pri)
| |
154 .def("name", &Event::name) 155 .def("dump", &Event::dump) 156 .def("scheduled", &Event::scheduled) 157 .def("squash", &Event::squash) 158 .def("squashed", &Event::squashed) 159 .def("isExitEvent", &Event::isExitEvent)
| 147 .def("name", &Event::name) 148 .def("dump", &Event::dump) 149 .def("scheduled", &Event::scheduled) 150 .def("squash", &Event::squash) 151 .def("squashed", &Event::squashed) 152 .def("isExitEvent", &Event::isExitEvent)
|
160 .def("isAutoDelete", &Event::isAutoDelete)
| |
161 .def("when", &Event::when) 162 .def("priority", &Event::priority) 163 ; 164
| 153 .def("when", &Event::when) 154 .def("priority", &Event::priority) 155 ; 156
|
| 157 py::class_<PyEvent, Event>(m, "PyEvent") 158 .def(py::init<Event::Priority>(), 159 py::arg("priority") = (int)Event::Default_Pri) 160 ; 161
|
165#define PRIO(n) c_event.attr(# n) = py::cast((int)Event::n) 166 PRIO(Minimum_Pri); 167 PRIO(Minimum_Pri); 168 PRIO(Debug_Enable_Pri); 169 PRIO(Debug_Break_Pri); 170 PRIO(CPU_Switch_Pri); 171 PRIO(Delayed_Writeback_Pri); 172 PRIO(Default_Pri); 173 PRIO(DVFS_Update_Pri); 174 PRIO(Serialize_Pri); 175 PRIO(CPU_Tick_Pri); 176 PRIO(Stat_Event_Pri); 177 PRIO(Progress_Event_Pri); 178 PRIO(Sim_Exit_Pri); 179 PRIO(Maximum_Pri); 180}
| 162#define PRIO(n) c_event.attr(# n) = py::cast((int)Event::n) 163 PRIO(Minimum_Pri); 164 PRIO(Minimum_Pri); 165 PRIO(Debug_Enable_Pri); 166 PRIO(Debug_Break_Pri); 167 PRIO(CPU_Switch_Pri); 168 PRIO(Delayed_Writeback_Pri); 169 PRIO(Default_Pri); 170 PRIO(DVFS_Update_Pri); 171 PRIO(Serialize_Pri); 172 PRIO(CPU_Tick_Pri); 173 PRIO(Stat_Event_Pri); 174 PRIO(Progress_Event_Pri); 175 PRIO(Sim_Exit_Pri); 176 PRIO(Maximum_Pri); 177}
|