1/* 2 * Copyright (c) 2015 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 * Authors: David Guillen Fandos 38 */ 39 40#include "sim/power/thermal_model.hh" 41 42#include "base/statistics.hh" 43#include "params/ThermalCapacitor.hh" 44#include "params/ThermalReference.hh" 45#include "params/ThermalResistor.hh" 46#include "sim/clocked_object.hh" 47#include "sim/linear_solver.hh" 48#include "sim/power/thermal_domain.hh" 49#include "sim/sim_object.hh" 50 51/** 52 * ThermalReference 53 */ 54ThermalReference::ThermalReference(const Params *p) 55 : SimObject(p), _temperature(p->temperature), node(NULL) 56{ 57} 58 59ThermalReference * 60ThermalReferenceParams::create() 61{ 62 return new ThermalReference(this); 63} 64 65void 66ThermalReference::serialize(CheckpointOut &cp) const 67{ 68 SERIALIZE_SCALAR(_temperature); 69} 70 71void 72ThermalReference::unserialize(CheckpointIn &cp) 73{ 74 UNSERIALIZE_SCALAR(_temperature); 75} 76 77LinearEquation 78ThermalReference::getEquation(ThermalNode * n, unsigned nnodes, 79 double step) const { 80 // Just return an empty equation 81 return LinearEquation(nnodes); 82} 83 84/** 85 * ThermalResistor 86 */ 87ThermalResistor::ThermalResistor(const Params *p) 88 : SimObject(p), _resistance(p->resistance), node1(NULL), node2(NULL) 89{ 90} 91 92ThermalResistor * 93ThermalResistorParams::create() 94{ 95 return new ThermalResistor(this); 96} 97 98void 99ThermalResistor::serialize(CheckpointOut &cp) const 100{ 101 SERIALIZE_SCALAR(_resistance); 102} 103 104void 105ThermalResistor::unserialize(CheckpointIn &cp) 106{ 107 UNSERIALIZE_SCALAR(_resistance); 108} 109 110LinearEquation 111ThermalResistor::getEquation(ThermalNode * n, unsigned nnodes, 112 double step) const 113{ 114 // i[n] = (Vn2 - Vn1)/R 115 LinearEquation eq(nnodes); 116 117 if (n != node1 && n != node2) 118 return eq; 119 120 if (node1->isref) 121 eq[eq.cnt()] += -node1->temp / _resistance; 122 else 123 eq[node1->id] += -1.0f / _resistance; 124 125 if (node2->isref) 126 eq[eq.cnt()] += node2->temp / _resistance; 127 else 128 eq[node2->id] += 1.0f / _resistance; 129 130 // We've assumed n was node1, reverse if necessary 131 if (n == node2) 132 eq *= -1.0f; 133 134 return eq; 135} 136 137/** 138 * ThermalCapacitor 139 */ 140ThermalCapacitor::ThermalCapacitor(const Params *p) 141 : SimObject(p), _capacitance(p->capacitance), node1(NULL), node2(NULL) 142{ 143} 144 145ThermalCapacitor * 146ThermalCapacitorParams::create() 147{ 148 return new ThermalCapacitor(this); 149} 150 151void 152ThermalCapacitor::serialize(CheckpointOut &cp) const 153{ 154 SERIALIZE_SCALAR(_capacitance); 155} 156 157void 158ThermalCapacitor::unserialize(CheckpointIn &cp) 159{ 160 UNSERIALIZE_SCALAR(_capacitance); 161} 162 163LinearEquation 164ThermalCapacitor::getEquation(ThermalNode * n, unsigned nnodes, 165 double step) const 166{ 167 // i(t) = C * d(Vn2 - Vn1)/dt 168 // i[n] = C/step * (Vn2 - Vn1 - Vn2[n-1] + Vn1[n-1]) 169 LinearEquation eq(nnodes); 170 171 if (n != node1 && n != node2) 172 return eq; 173 174 eq[eq.cnt()] += _capacitance / step * (node1->temp - node2->temp); 175 176 if (node1->isref) 177 eq[eq.cnt()] += _capacitance / step * (-node1->temp); 178 else 179 eq[node1->id] += -1.0f * _capacitance / step; 180 181 if (node2->isref) 182 eq[eq.cnt()] += _capacitance / step * (node2->temp); 183 else 184 eq[node2->id] += 1.0f * _capacitance / step; 185 186 // We've assumed n was node1, reverse if necessary 187 if (n == node2) 188 eq *= -1.0f; 189 190 return eq; 191} 192 193/** 194 * ThermalModel 195 */ 196ThermalModel::ThermalModel(const Params *p) 197 : ClockedObject(p), stepEvent([this]{ doStep(); }, name()), _step(p->step) 198{ 199} 200 201ThermalModel * 202ThermalModelParams::create() 203{ 204 return new ThermalModel(this); 205} 206 207void 208ThermalModel::serialize(CheckpointOut &cp) const 209{ 210 SERIALIZE_SCALAR(_step); 211} 212 213void 214ThermalModel::unserialize(CheckpointIn &cp) 215{ 216 UNSERIALIZE_SCALAR(_step); 217} 218 219void 220ThermalModel::doStep() 221{ 222 // Calculate new temperatures! 223 // For each node in the system, create the kirchhoff nodal equation 224 LinearSystem ls(eq_nodes.size()); 225 for (unsigned i = 0; i < eq_nodes.size(); i++) { 226 auto n = eq_nodes[i]; 227 LinearEquation node_equation (eq_nodes.size()); 228 for (auto e : entities) { 229 LinearEquation eq = e->getEquation(n, eq_nodes.size(), _step); 230 node_equation = node_equation + eq; 231 } 232 ls[i] = node_equation; 233 } 234 235 // Get temperatures for this iteration 236 std::vector <double> temps = ls.solve(); 237 for (unsigned i = 0; i < eq_nodes.size(); i++) 238 eq_nodes[i]->temp = temps[i]; 239 240 // Schedule next computation 241 schedule(stepEvent, curTick() + SimClock::Int::s * _step); 242 243 // Notify everybody 244 for (auto dom : domains) 245 dom->emitUpdate(); 246} 247 248void 249ThermalModel::startup() 250{ 251 // Look for nodes connected to voltage references, these 252 // can be just set to the reference value (no nodal equation) 253 for (auto ref : references) { 254 ref->node->temp = ref->_temperature; 255 ref->node->isref = true; 256 } 257 // Setup the initial temperatures 258 for (auto dom : domains) 259 dom->getNode()->temp = dom->initialTemperature(); 260 261 // Create a list of unknown temperature nodes 262 for (auto n : nodes) { 263 bool found = false; 264 for (auto ref : references) 265 if (ref->node == n) { 266 found = true; 267 break; 268 } 269 if (!found) 270 eq_nodes.push_back(n); 271 } 272 273 // Assign each node an ID 274 for (unsigned i = 0; i < eq_nodes.size(); i++) 275 eq_nodes[i]->id = i; 276 277 // Schedule first thermal update 278 schedule(stepEvent, curTick() + SimClock::Int::s * _step); 279} 280 281void ThermalModel::addDomain(ThermalDomain * d) { 282 domains.push_back(d); 283 entities.push_back(d); 284} 285void ThermalModel::addReference(ThermalReference * r) { 286 references.push_back(r); 287 entities.push_back(r); 288} 289void ThermalModel::addCapacitor(ThermalCapacitor * c) { 290 capacitors.push_back(c); 291 entities.push_back(c); 292} 293void ThermalModel::addResistor(ThermalResistor * r) { 294 resistors.push_back(r); 295 entities.push_back(r); 296} 297 298double ThermalModel::getTemp() const { 299 // Just pick the highest temperature 300 double temp = 0; 301 for (auto & n : eq_nodes) 302 temp = std::max(temp, n->temp); 303 return temp; 304} 305