| /* |
| * Copyright (c) 2015-2016 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: Akash Bagdia |
| * David Guillen Fandos |
| */ |
| |
| #include "sim/clocked_object.hh" |
| |
| #include "base/logging.hh" |
| #include "sim/power/power_model.hh" |
| |
| ClockedObject::ClockedObject(const ClockedObjectParams *p) : |
| SimObject(p), Clocked(*p->clk_domain), |
| _currPwrState(p->default_p_state), |
| prvEvalTick(0) |
| { |
| // Register the power_model with the object |
| for (auto & power_model: p->power_model) |
| power_model->setClockedObject(this); |
| } |
| |
| void |
| ClockedObject::serialize(CheckpointOut &cp) const |
| { |
| unsigned int currPwrState = (unsigned int)_currPwrState; |
| |
| SERIALIZE_SCALAR(currPwrState); |
| SERIALIZE_SCALAR(prvEvalTick); |
| } |
| |
| void |
| ClockedObject::unserialize(CheckpointIn &cp) |
| { |
| unsigned int currPwrState; |
| |
| UNSERIALIZE_SCALAR(currPwrState); |
| UNSERIALIZE_SCALAR(prvEvalTick); |
| |
| _currPwrState = Enums::PwrState(currPwrState); |
| } |
| |
| void |
| ClockedObject::pwrState(Enums::PwrState p) |
| { |
| // Function should ideally be called only when there is a state change |
| if (_currPwrState == p) { |
| warn_once("ClockedObject: Already in the requested power state, " \ |
| "request ignored"); |
| return; |
| } |
| |
| // No need to compute stats if in the same tick, update state though. This |
| // can happen in cases like a) during start of the simulation multiple |
| // state changes happens in init/startup phase, b) one takes a decision to |
| // migrate state but decides to reverts back to the original state in the |
| // same tick if other conditions are not met elsewhere. |
| // Any state change related stats would have been recorded on previous call |
| // to the pwrState() function. |
| if (prvEvalTick == curTick() && curTick() != 0) { |
| warn("ClockedObject %s: More than one power state change request "\ |
| "encountered within the same simulation tick %d", |
| name(), prvEvalTick); |
| _currPwrState = p; |
| return; |
| } |
| |
| // Record stats for previous state. |
| computeStats(); |
| |
| _currPwrState = p; |
| |
| numPwrStateTransitions++; |
| } |
| |
| void |
| ClockedObject::computeStats() |
| { |
| // Calculate time elapsed from last (valid) state change |
| Tick elapsed_time = curTick() - prvEvalTick; |
| |
| pwrStateResidencyTicks[_currPwrState] += elapsed_time; |
| |
| // Time spent in CLK_GATED state, this might change depending on |
| // transition to other low power states in respective simulation |
| // objects. |
| if (_currPwrState == Enums::PwrState::CLK_GATED) { |
| pwrStateClkGateDist.sample(elapsed_time); |
| } |
| |
| prvEvalTick = curTick(); |
| } |
| |
| std::vector<double> |
| ClockedObject::pwrStateWeights() const |
| { |
| // Get residency stats |
| std::vector<double> ret; |
| Stats::VCounter residencies; |
| pwrStateResidencyTicks.value(residencies); |
| |
| // Account for current state too! |
| Tick elapsed_time = curTick() - prvEvalTick; |
| residencies[_currPwrState] += elapsed_time; |
| |
| ret.resize(Enums::PwrState::Num_PwrState); |
| for (unsigned i = 0; i < Enums::PwrState::Num_PwrState; i++) |
| ret[i] = residencies[i] / \ |
| (pwrStateResidencyTicks.total() + elapsed_time); |
| |
| return ret; |
| } |
| |
| void |
| ClockedObject::regStats() |
| { |
| SimObject::regStats(); |
| |
| using namespace Stats; |
| |
| numPwrStateTransitions |
| .name(params()->name + ".numPwrStateTransitions") |
| .desc("Number of power state transitions") |
| .flags(nozero) |
| ; |
| |
| // Each sample is time in ticks |
| unsigned num_bins = std::max(params()->p_state_clk_gate_bins, 10U); |
| pwrStateClkGateDist |
| .init(params()->p_state_clk_gate_min, params()->p_state_clk_gate_max, |
| (params()->p_state_clk_gate_max / num_bins)) |
| .name(params()->name + ".pwrStateClkGateDist") |
| .desc("Distribution of time spent in the clock gated state") |
| .flags(pdf | nozero | nonan) |
| ; |
| |
| pwrStateResidencyTicks |
| .init(Enums::PwrState::Num_PwrState) |
| .name(params()->name + ".pwrStateResidencyTicks") |
| .desc("Cumulative time (in ticks) in various power states") |
| .flags(nozero) |
| ; |
| for (int i = 0; i < Enums::PwrState::Num_PwrState; i++) { |
| pwrStateResidencyTicks.subname(i, Enums::PwrStateStrings[i]); |
| } |
| |
| numPwrStateTransitions = 0; |
| |
| /** |
| * For every stats dump, the power state residency and other distribution |
| * stats should be computed just before the dump to ensure correct stats |
| * value being reported for current dump window. It avoids things like |
| * having any unreported time spent in a power state to be forwarded to the |
| * next dump window which might have rather unpleasant effects (like |
| * perturbing the distribution stats). |
| */ |
| registerDumpCallback(new ClockedObjectDumpCallback(this)); |
| } |