thermal_model.cc revision 11420
111420Sdavid.guillen@arm.com/*
211420Sdavid.guillen@arm.com * Copyright (c) 2015 ARM Limited
311420Sdavid.guillen@arm.com * All rights reserved
411420Sdavid.guillen@arm.com *
511420Sdavid.guillen@arm.com * The license below extends only to copyright in the software and shall
611420Sdavid.guillen@arm.com * not be construed as granting a license to any other intellectual
711420Sdavid.guillen@arm.com * property including but not limited to intellectual property relating
811420Sdavid.guillen@arm.com * to a hardware implementation of the functionality of the software
911420Sdavid.guillen@arm.com * licensed hereunder.  You may use the software subject to the license
1011420Sdavid.guillen@arm.com * terms below provided that you ensure that this notice is replicated
1111420Sdavid.guillen@arm.com * unmodified and in its entirety in all distributions of the software,
1211420Sdavid.guillen@arm.com * modified or unmodified, in source code or in binary form.
1311420Sdavid.guillen@arm.com *
1411420Sdavid.guillen@arm.com * Redistribution and use in source and binary forms, with or without
1511420Sdavid.guillen@arm.com * modification, are permitted provided that the following conditions are
1611420Sdavid.guillen@arm.com * met: redistributions of source code must retain the above copyright
1711420Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer;
1811420Sdavid.guillen@arm.com * redistributions in binary form must reproduce the above copyright
1911420Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer in the
2011420Sdavid.guillen@arm.com * documentation and/or other materials provided with the distribution;
2111420Sdavid.guillen@arm.com * neither the name of the copyright holders nor the names of its
2211420Sdavid.guillen@arm.com * contributors may be used to endorse or promote products derived from
2311420Sdavid.guillen@arm.com * this software without specific prior written permission.
2411420Sdavid.guillen@arm.com *
2511420Sdavid.guillen@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2611420Sdavid.guillen@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2711420Sdavid.guillen@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2811420Sdavid.guillen@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911420Sdavid.guillen@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3011420Sdavid.guillen@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111420Sdavid.guillen@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211420Sdavid.guillen@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311420Sdavid.guillen@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411420Sdavid.guillen@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3511420Sdavid.guillen@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611420Sdavid.guillen@arm.com *
3711420Sdavid.guillen@arm.com * Authors: David Guillen Fandos
3811420Sdavid.guillen@arm.com */
3911420Sdavid.guillen@arm.com
4011420Sdavid.guillen@arm.com#include "sim/power/thermal_model.hh"
4111420Sdavid.guillen@arm.com
4211420Sdavid.guillen@arm.com#include "base/statistics.hh"
4311420Sdavid.guillen@arm.com#include "params/ThermalCapacitor.hh"
4411420Sdavid.guillen@arm.com#include "params/ThermalNode.hh"
4511420Sdavid.guillen@arm.com#include "params/ThermalReference.hh"
4611420Sdavid.guillen@arm.com#include "params/ThermalResistor.hh"
4711420Sdavid.guillen@arm.com#include "sim/clocked_object.hh"
4811420Sdavid.guillen@arm.com#include "sim/linear_solver.hh"
4911420Sdavid.guillen@arm.com#include "sim/power/thermal_domain.hh"
5011420Sdavid.guillen@arm.com#include "sim/sim_object.hh"
5111420Sdavid.guillen@arm.com
5211420Sdavid.guillen@arm.com/**
5311420Sdavid.guillen@arm.com * ThermalNode
5411420Sdavid.guillen@arm.com */
5511420Sdavid.guillen@arm.comThermalNode::ThermalNode(const Params *p)
5611420Sdavid.guillen@arm.com    : SimObject(p), id(-1), isref(false), temp(0.0f)
5711420Sdavid.guillen@arm.com{
5811420Sdavid.guillen@arm.com}
5911420Sdavid.guillen@arm.com
6011420Sdavid.guillen@arm.comThermalNode *
6111420Sdavid.guillen@arm.comThermalNodeParams::create()
6211420Sdavid.guillen@arm.com{
6311420Sdavid.guillen@arm.com    return new ThermalNode(this);
6411420Sdavid.guillen@arm.com}
6511420Sdavid.guillen@arm.com
6611420Sdavid.guillen@arm.com/**
6711420Sdavid.guillen@arm.com * ThermalReference
6811420Sdavid.guillen@arm.com */
6911420Sdavid.guillen@arm.comThermalReference::ThermalReference(const Params *p)
7011420Sdavid.guillen@arm.com    : SimObject(p), _temperature(p->temperature), node(NULL)
7111420Sdavid.guillen@arm.com{
7211420Sdavid.guillen@arm.com}
7311420Sdavid.guillen@arm.com
7411420Sdavid.guillen@arm.comThermalReference *
7511420Sdavid.guillen@arm.comThermalReferenceParams::create()
7611420Sdavid.guillen@arm.com{
7711420Sdavid.guillen@arm.com    return new ThermalReference(this);
7811420Sdavid.guillen@arm.com}
7911420Sdavid.guillen@arm.com
8011420Sdavid.guillen@arm.comvoid
8111420Sdavid.guillen@arm.comThermalReference::serialize(CheckpointOut &cp) const
8211420Sdavid.guillen@arm.com{
8311420Sdavid.guillen@arm.com    SERIALIZE_SCALAR(_temperature);
8411420Sdavid.guillen@arm.com}
8511420Sdavid.guillen@arm.com
8611420Sdavid.guillen@arm.comvoid
8711420Sdavid.guillen@arm.comThermalReference::unserialize(CheckpointIn &cp)
8811420Sdavid.guillen@arm.com{
8911420Sdavid.guillen@arm.com    UNSERIALIZE_SCALAR(_temperature);
9011420Sdavid.guillen@arm.com}
9111420Sdavid.guillen@arm.com
9211420Sdavid.guillen@arm.comLinearEquation
9311420Sdavid.guillen@arm.comThermalReference::getEquation(ThermalNode * n, unsigned nnodes,
9411420Sdavid.guillen@arm.com                              double step) const {
9511420Sdavid.guillen@arm.com    // Just return an empty equation
9611420Sdavid.guillen@arm.com    return LinearEquation(nnodes);
9711420Sdavid.guillen@arm.com}
9811420Sdavid.guillen@arm.com
9911420Sdavid.guillen@arm.com/**
10011420Sdavid.guillen@arm.com * ThermalResistor
10111420Sdavid.guillen@arm.com */
10211420Sdavid.guillen@arm.comThermalResistor::ThermalResistor(const Params *p)
10311420Sdavid.guillen@arm.com    : SimObject(p), _resistance(p->resistance), node1(NULL), node2(NULL)
10411420Sdavid.guillen@arm.com{
10511420Sdavid.guillen@arm.com}
10611420Sdavid.guillen@arm.com
10711420Sdavid.guillen@arm.comThermalResistor *
10811420Sdavid.guillen@arm.comThermalResistorParams::create()
10911420Sdavid.guillen@arm.com{
11011420Sdavid.guillen@arm.com    return new ThermalResistor(this);
11111420Sdavid.guillen@arm.com}
11211420Sdavid.guillen@arm.com
11311420Sdavid.guillen@arm.comvoid
11411420Sdavid.guillen@arm.comThermalResistor::serialize(CheckpointOut &cp) const
11511420Sdavid.guillen@arm.com{
11611420Sdavid.guillen@arm.com    SERIALIZE_SCALAR(_resistance);
11711420Sdavid.guillen@arm.com}
11811420Sdavid.guillen@arm.com
11911420Sdavid.guillen@arm.comvoid
12011420Sdavid.guillen@arm.comThermalResistor::unserialize(CheckpointIn &cp)
12111420Sdavid.guillen@arm.com{
12211420Sdavid.guillen@arm.com    UNSERIALIZE_SCALAR(_resistance);
12311420Sdavid.guillen@arm.com}
12411420Sdavid.guillen@arm.com
12511420Sdavid.guillen@arm.comLinearEquation
12611420Sdavid.guillen@arm.comThermalResistor::getEquation(ThermalNode * n, unsigned nnodes,
12711420Sdavid.guillen@arm.com                             double step) const
12811420Sdavid.guillen@arm.com{
12911420Sdavid.guillen@arm.com    // i[n] = (Vn2 - Vn1)/R
13011420Sdavid.guillen@arm.com    LinearEquation eq(nnodes);
13111420Sdavid.guillen@arm.com
13211420Sdavid.guillen@arm.com    if (n != node1 && n != node2)
13311420Sdavid.guillen@arm.com        return eq;
13411420Sdavid.guillen@arm.com
13511420Sdavid.guillen@arm.com    if (node1->isref)
13611420Sdavid.guillen@arm.com        eq[eq.cnt()] += -node1->temp / _resistance;
13711420Sdavid.guillen@arm.com    else
13811420Sdavid.guillen@arm.com        eq[node1->id] += -1.0f / _resistance;
13911420Sdavid.guillen@arm.com
14011420Sdavid.guillen@arm.com    if (node2->isref)
14111420Sdavid.guillen@arm.com        eq[eq.cnt()] += node2->temp / _resistance;
14211420Sdavid.guillen@arm.com    else
14311420Sdavid.guillen@arm.com        eq[node2->id] += 1.0f / _resistance;
14411420Sdavid.guillen@arm.com
14511420Sdavid.guillen@arm.com    // We've assumed n was node1, reverse if necessary
14611420Sdavid.guillen@arm.com    if (n == node2)
14711420Sdavid.guillen@arm.com        eq *= -1.0f;
14811420Sdavid.guillen@arm.com
14911420Sdavid.guillen@arm.com    return eq;
15011420Sdavid.guillen@arm.com}
15111420Sdavid.guillen@arm.com
15211420Sdavid.guillen@arm.com/**
15311420Sdavid.guillen@arm.com * ThermalCapacitor
15411420Sdavid.guillen@arm.com */
15511420Sdavid.guillen@arm.comThermalCapacitor::ThermalCapacitor(const Params *p)
15611420Sdavid.guillen@arm.com    : SimObject(p), _capacitance(p->capacitance), node1(NULL), node2(NULL)
15711420Sdavid.guillen@arm.com{
15811420Sdavid.guillen@arm.com}
15911420Sdavid.guillen@arm.com
16011420Sdavid.guillen@arm.comThermalCapacitor *
16111420Sdavid.guillen@arm.comThermalCapacitorParams::create()
16211420Sdavid.guillen@arm.com{
16311420Sdavid.guillen@arm.com    return new ThermalCapacitor(this);
16411420Sdavid.guillen@arm.com}
16511420Sdavid.guillen@arm.com
16611420Sdavid.guillen@arm.comvoid
16711420Sdavid.guillen@arm.comThermalCapacitor::serialize(CheckpointOut &cp) const
16811420Sdavid.guillen@arm.com{
16911420Sdavid.guillen@arm.com    SERIALIZE_SCALAR(_capacitance);
17011420Sdavid.guillen@arm.com}
17111420Sdavid.guillen@arm.com
17211420Sdavid.guillen@arm.comvoid
17311420Sdavid.guillen@arm.comThermalCapacitor::unserialize(CheckpointIn &cp)
17411420Sdavid.guillen@arm.com{
17511420Sdavid.guillen@arm.com    UNSERIALIZE_SCALAR(_capacitance);
17611420Sdavid.guillen@arm.com}
17711420Sdavid.guillen@arm.com
17811420Sdavid.guillen@arm.comLinearEquation
17911420Sdavid.guillen@arm.comThermalCapacitor::getEquation(ThermalNode * n, unsigned nnodes,
18011420Sdavid.guillen@arm.com                              double step) const
18111420Sdavid.guillen@arm.com{
18211420Sdavid.guillen@arm.com    // i(t) = C * d(Vn2 - Vn1)/dt
18311420Sdavid.guillen@arm.com    // i[n] = C/step * (Vn2 - Vn1 - Vn2[n-1] + Vn1[n-1])
18411420Sdavid.guillen@arm.com    LinearEquation eq(nnodes);
18511420Sdavid.guillen@arm.com
18611420Sdavid.guillen@arm.com    if (n != node1 && n != node2)
18711420Sdavid.guillen@arm.com        return eq;
18811420Sdavid.guillen@arm.com
18911420Sdavid.guillen@arm.com    eq[eq.cnt()] += _capacitance / step * (node1->temp - node2->temp);
19011420Sdavid.guillen@arm.com
19111420Sdavid.guillen@arm.com    if (node1->isref)
19211420Sdavid.guillen@arm.com        eq[eq.cnt()] += _capacitance / step * (-node1->temp);
19311420Sdavid.guillen@arm.com    else
19411420Sdavid.guillen@arm.com        eq[node1->id] += -1.0f * _capacitance / step;
19511420Sdavid.guillen@arm.com
19611420Sdavid.guillen@arm.com    if (node2->isref)
19711420Sdavid.guillen@arm.com        eq[eq.cnt()] += _capacitance / step * (node2->temp);
19811420Sdavid.guillen@arm.com    else
19911420Sdavid.guillen@arm.com        eq[node2->id] += 1.0f * _capacitance / step;
20011420Sdavid.guillen@arm.com
20111420Sdavid.guillen@arm.com    // We've assumed n was node1, reverse if necessary
20211420Sdavid.guillen@arm.com    if (n == node2)
20311420Sdavid.guillen@arm.com        eq *= -1.0f;
20411420Sdavid.guillen@arm.com
20511420Sdavid.guillen@arm.com    return eq;
20611420Sdavid.guillen@arm.com}
20711420Sdavid.guillen@arm.com
20811420Sdavid.guillen@arm.com/**
20911420Sdavid.guillen@arm.com * ThermalModel
21011420Sdavid.guillen@arm.com */
21111420Sdavid.guillen@arm.comThermalModel::ThermalModel(const Params *p)
21211420Sdavid.guillen@arm.com    : ClockedObject(p), stepEvent(this), _step(p->step)
21311420Sdavid.guillen@arm.com{
21411420Sdavid.guillen@arm.com}
21511420Sdavid.guillen@arm.com
21611420Sdavid.guillen@arm.comThermalModel *
21711420Sdavid.guillen@arm.comThermalModelParams::create()
21811420Sdavid.guillen@arm.com{
21911420Sdavid.guillen@arm.com    return new ThermalModel(this);
22011420Sdavid.guillen@arm.com}
22111420Sdavid.guillen@arm.com
22211420Sdavid.guillen@arm.comvoid
22311420Sdavid.guillen@arm.comThermalModel::serialize(CheckpointOut &cp) const
22411420Sdavid.guillen@arm.com{
22511420Sdavid.guillen@arm.com    SERIALIZE_SCALAR(_step);
22611420Sdavid.guillen@arm.com}
22711420Sdavid.guillen@arm.com
22811420Sdavid.guillen@arm.comvoid
22911420Sdavid.guillen@arm.comThermalModel::unserialize(CheckpointIn &cp)
23011420Sdavid.guillen@arm.com{
23111420Sdavid.guillen@arm.com    UNSERIALIZE_SCALAR(_step);
23211420Sdavid.guillen@arm.com}
23311420Sdavid.guillen@arm.com
23411420Sdavid.guillen@arm.comvoid
23511420Sdavid.guillen@arm.comThermalModel::doStep()
23611420Sdavid.guillen@arm.com{
23711420Sdavid.guillen@arm.com    // Calculate new temperatures!
23811420Sdavid.guillen@arm.com    // For each node in the system, create the kirchhoff nodal equation
23911420Sdavid.guillen@arm.com    LinearSystem ls(eq_nodes.size());
24011420Sdavid.guillen@arm.com    for (unsigned i = 0; i < eq_nodes.size(); i++) {
24111420Sdavid.guillen@arm.com        auto n = eq_nodes[i];
24211420Sdavid.guillen@arm.com        LinearEquation node_equation (eq_nodes.size());
24311420Sdavid.guillen@arm.com        for (auto e : entities) {
24411420Sdavid.guillen@arm.com            LinearEquation eq = e->getEquation(n, eq_nodes.size(), _step);
24511420Sdavid.guillen@arm.com            node_equation = node_equation + eq;
24611420Sdavid.guillen@arm.com        }
24711420Sdavid.guillen@arm.com        ls[i] = node_equation;
24811420Sdavid.guillen@arm.com    }
24911420Sdavid.guillen@arm.com
25011420Sdavid.guillen@arm.com    // Get temperatures for this iteration
25111420Sdavid.guillen@arm.com    std::vector <double> temps = ls.solve();
25211420Sdavid.guillen@arm.com    for (unsigned i = 0; i < eq_nodes.size(); i++)
25311420Sdavid.guillen@arm.com        eq_nodes[i]->temp = temps[i];
25411420Sdavid.guillen@arm.com
25511420Sdavid.guillen@arm.com    // Schedule next computation
25611420Sdavid.guillen@arm.com    schedule(stepEvent, curTick() + SimClock::Int::s * _step);
25711420Sdavid.guillen@arm.com
25811420Sdavid.guillen@arm.com    // Notify everybody
25911420Sdavid.guillen@arm.com    for (auto dom : domains)
26011420Sdavid.guillen@arm.com        dom->emitUpdate();
26111420Sdavid.guillen@arm.com}
26211420Sdavid.guillen@arm.com
26311420Sdavid.guillen@arm.comvoid
26411420Sdavid.guillen@arm.comThermalModel::startup()
26511420Sdavid.guillen@arm.com{
26611420Sdavid.guillen@arm.com    // Look for nodes connected to voltage references, these
26711420Sdavid.guillen@arm.com    // can be just set to the reference value (no nodal equation)
26811420Sdavid.guillen@arm.com    for (auto ref : references) {
26911420Sdavid.guillen@arm.com        ref->node->temp = ref->_temperature;
27011420Sdavid.guillen@arm.com        ref->node->isref = true;
27111420Sdavid.guillen@arm.com    }
27211420Sdavid.guillen@arm.com    // Setup the initial temperatures
27311420Sdavid.guillen@arm.com    for (auto dom : domains)
27411420Sdavid.guillen@arm.com        dom->getNode()->temp = dom->initialTemperature();
27511420Sdavid.guillen@arm.com
27611420Sdavid.guillen@arm.com    // Create a list of unknown temperature nodes
27711420Sdavid.guillen@arm.com    for (auto n : nodes) {
27811420Sdavid.guillen@arm.com        bool found = false;
27911420Sdavid.guillen@arm.com        for (auto ref : references)
28011420Sdavid.guillen@arm.com            if (ref->node == n) {
28111420Sdavid.guillen@arm.com                found = true;
28211420Sdavid.guillen@arm.com                break;
28311420Sdavid.guillen@arm.com            }
28411420Sdavid.guillen@arm.com        if (!found)
28511420Sdavid.guillen@arm.com            eq_nodes.push_back(n);
28611420Sdavid.guillen@arm.com    }
28711420Sdavid.guillen@arm.com
28811420Sdavid.guillen@arm.com    // Assign each node an ID
28911420Sdavid.guillen@arm.com    for (unsigned i = 0; i < eq_nodes.size(); i++)
29011420Sdavid.guillen@arm.com        eq_nodes[i]->id = i;
29111420Sdavid.guillen@arm.com
29211420Sdavid.guillen@arm.com    // Schedule first thermal update
29311420Sdavid.guillen@arm.com    schedule(stepEvent, curTick() + SimClock::Int::s * _step);
29411420Sdavid.guillen@arm.com}
29511420Sdavid.guillen@arm.com
29611420Sdavid.guillen@arm.comvoid ThermalModel::addDomain(ThermalDomain * d) {
29711420Sdavid.guillen@arm.com    domains.push_back(d);
29811420Sdavid.guillen@arm.com    entities.push_back(d);
29911420Sdavid.guillen@arm.com}
30011420Sdavid.guillen@arm.comvoid ThermalModel::addReference(ThermalReference * r) {
30111420Sdavid.guillen@arm.com    references.push_back(r);
30211420Sdavid.guillen@arm.com    entities.push_back(r);
30311420Sdavid.guillen@arm.com}
30411420Sdavid.guillen@arm.comvoid ThermalModel::addCapacitor(ThermalCapacitor * c) {
30511420Sdavid.guillen@arm.com    capacitors.push_back(c);
30611420Sdavid.guillen@arm.com    entities.push_back(c);
30711420Sdavid.guillen@arm.com}
30811420Sdavid.guillen@arm.comvoid ThermalModel::addResistor(ThermalResistor * r) {
30911420Sdavid.guillen@arm.com    resistors.push_back(r);
31011420Sdavid.guillen@arm.com    entities.push_back(r);
31111420Sdavid.guillen@arm.com}
31211420Sdavid.guillen@arm.com
31311420Sdavid.guillen@arm.comdouble ThermalModel::getTemp() const {
31411420Sdavid.guillen@arm.com    // Just pick the highest temperature
31511420Sdavid.guillen@arm.com    double temp = 0;
31611420Sdavid.guillen@arm.com    for (auto & n : eq_nodes)
31711420Sdavid.guillen@arm.com        temp = std::max(temp, n->temp);
31811420Sdavid.guillen@arm.com    return temp;
31911420Sdavid.guillen@arm.com}
320