diff options
Diffstat (limited to 'src/sim/power/thermal_model.cc')
-rw-r--r-- | src/sim/power/thermal_model.cc | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/src/sim/power/thermal_model.cc b/src/sim/power/thermal_model.cc new file mode 100644 index 000000000..13242f666 --- /dev/null +++ b/src/sim/power/thermal_model.cc @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: David Guillen Fandos + */ + +#include "sim/power/thermal_model.hh" + +#include "base/statistics.hh" +#include "params/ThermalCapacitor.hh" +#include "params/ThermalNode.hh" +#include "params/ThermalReference.hh" +#include "params/ThermalResistor.hh" +#include "sim/clocked_object.hh" +#include "sim/linear_solver.hh" +#include "sim/power/thermal_domain.hh" +#include "sim/sim_object.hh" + +/** + * ThermalNode + */ +ThermalNode::ThermalNode(const Params *p) + : SimObject(p), id(-1), isref(false), temp(0.0f) +{ +} + +ThermalNode * +ThermalNodeParams::create() +{ + return new ThermalNode(this); +} + +/** + * ThermalReference + */ +ThermalReference::ThermalReference(const Params *p) + : SimObject(p), _temperature(p->temperature), node(NULL) +{ +} + +ThermalReference * +ThermalReferenceParams::create() +{ + return new ThermalReference(this); +} + +void +ThermalReference::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_temperature); +} + +void +ThermalReference::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_temperature); +} + +LinearEquation +ThermalReference::getEquation(ThermalNode * n, unsigned nnodes, + double step) const { + // Just return an empty equation + return LinearEquation(nnodes); +} + +/** + * ThermalResistor + */ +ThermalResistor::ThermalResistor(const Params *p) + : SimObject(p), _resistance(p->resistance), node1(NULL), node2(NULL) +{ +} + +ThermalResistor * +ThermalResistorParams::create() +{ + return new ThermalResistor(this); +} + +void +ThermalResistor::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_resistance); +} + +void +ThermalResistor::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_resistance); +} + +LinearEquation +ThermalResistor::getEquation(ThermalNode * n, unsigned nnodes, + double step) const +{ + // i[n] = (Vn2 - Vn1)/R + LinearEquation eq(nnodes); + + if (n != node1 && n != node2) + return eq; + + if (node1->isref) + eq[eq.cnt()] += -node1->temp / _resistance; + else + eq[node1->id] += -1.0f / _resistance; + + if (node2->isref) + eq[eq.cnt()] += node2->temp / _resistance; + else + eq[node2->id] += 1.0f / _resistance; + + // We've assumed n was node1, reverse if necessary + if (n == node2) + eq *= -1.0f; + + return eq; +} + +/** + * ThermalCapacitor + */ +ThermalCapacitor::ThermalCapacitor(const Params *p) + : SimObject(p), _capacitance(p->capacitance), node1(NULL), node2(NULL) +{ +} + +ThermalCapacitor * +ThermalCapacitorParams::create() +{ + return new ThermalCapacitor(this); +} + +void +ThermalCapacitor::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_capacitance); +} + +void +ThermalCapacitor::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_capacitance); +} + +LinearEquation +ThermalCapacitor::getEquation(ThermalNode * n, unsigned nnodes, + double step) const +{ + // i(t) = C * d(Vn2 - Vn1)/dt + // i[n] = C/step * (Vn2 - Vn1 - Vn2[n-1] + Vn1[n-1]) + LinearEquation eq(nnodes); + + if (n != node1 && n != node2) + return eq; + + eq[eq.cnt()] += _capacitance / step * (node1->temp - node2->temp); + + if (node1->isref) + eq[eq.cnt()] += _capacitance / step * (-node1->temp); + else + eq[node1->id] += -1.0f * _capacitance / step; + + if (node2->isref) + eq[eq.cnt()] += _capacitance / step * (node2->temp); + else + eq[node2->id] += 1.0f * _capacitance / step; + + // We've assumed n was node1, reverse if necessary + if (n == node2) + eq *= -1.0f; + + return eq; +} + +/** + * ThermalModel + */ +ThermalModel::ThermalModel(const Params *p) + : ClockedObject(p), stepEvent(this), _step(p->step) +{ +} + +ThermalModel * +ThermalModelParams::create() +{ + return new ThermalModel(this); +} + +void +ThermalModel::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_step); +} + +void +ThermalModel::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_step); +} + +void +ThermalModel::doStep() +{ + // Calculate new temperatures! + // For each node in the system, create the kirchhoff nodal equation + LinearSystem ls(eq_nodes.size()); + for (unsigned i = 0; i < eq_nodes.size(); i++) { + auto n = eq_nodes[i]; + LinearEquation node_equation (eq_nodes.size()); + for (auto e : entities) { + LinearEquation eq = e->getEquation(n, eq_nodes.size(), _step); + node_equation = node_equation + eq; + } + ls[i] = node_equation; + } + + // Get temperatures for this iteration + std::vector <double> temps = ls.solve(); + for (unsigned i = 0; i < eq_nodes.size(); i++) + eq_nodes[i]->temp = temps[i]; + + // Schedule next computation + schedule(stepEvent, curTick() + SimClock::Int::s * _step); + + // Notify everybody + for (auto dom : domains) + dom->emitUpdate(); +} + +void +ThermalModel::startup() +{ + // Look for nodes connected to voltage references, these + // can be just set to the reference value (no nodal equation) + for (auto ref : references) { + ref->node->temp = ref->_temperature; + ref->node->isref = true; + } + // Setup the initial temperatures + for (auto dom : domains) + dom->getNode()->temp = dom->initialTemperature(); + + // Create a list of unknown temperature nodes + for (auto n : nodes) { + bool found = false; + for (auto ref : references) + if (ref->node == n) { + found = true; + break; + } + if (!found) + eq_nodes.push_back(n); + } + + // Assign each node an ID + for (unsigned i = 0; i < eq_nodes.size(); i++) + eq_nodes[i]->id = i; + + // Schedule first thermal update + schedule(stepEvent, curTick() + SimClock::Int::s * _step); +} + +void ThermalModel::addDomain(ThermalDomain * d) { + domains.push_back(d); + entities.push_back(d); +} +void ThermalModel::addReference(ThermalReference * r) { + references.push_back(r); + entities.push_back(r); +} +void ThermalModel::addCapacitor(ThermalCapacitor * c) { + capacitors.push_back(c); + entities.push_back(c); +} +void ThermalModel::addResistor(ThermalResistor * r) { + resistors.push_back(r); + entities.push_back(r); +} + +double ThermalModel::getTemp() const { + // Just pick the highest temperature + double temp = 0; + for (auto & n : eq_nodes) + temp = std::max(temp, n->temp); + return temp; +} |