110249Sstephan.diestelhorst@arm.com/*
210249Sstephan.diestelhorst@arm.com * Copyright (c) 2013-2014 ARM Limited
310249Sstephan.diestelhorst@arm.com * All rights reserved
410249Sstephan.diestelhorst@arm.com *
510249Sstephan.diestelhorst@arm.com * The license below extends only to copyright in the software and shall
610249Sstephan.diestelhorst@arm.com * not be construed as granting a license to any other intellectual
710249Sstephan.diestelhorst@arm.com * property including but not limited to intellectual property relating
810249Sstephan.diestelhorst@arm.com * to a hardware implementation of the functionality of the software
910249Sstephan.diestelhorst@arm.com * licensed hereunder.  You may use the software subject to the license
1010249Sstephan.diestelhorst@arm.com * terms below provided that you ensure that this notice is replicated
1110249Sstephan.diestelhorst@arm.com * unmodified and in its entirety in all distributions of the software,
1210249Sstephan.diestelhorst@arm.com * modified or unmodified, in source code or in binary form.
1310249Sstephan.diestelhorst@arm.com *
1410249Sstephan.diestelhorst@arm.com * Redistribution and use in source and binary forms, with or without
1510249Sstephan.diestelhorst@arm.com * modification, are permitted provided that the following conditions are
1610249Sstephan.diestelhorst@arm.com * met: redistributions of source code must retain the above copyright
1710249Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer;
1810249Sstephan.diestelhorst@arm.com * redistributions in binary form must reproduce the above copyright
1910249Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer in the
2010249Sstephan.diestelhorst@arm.com * documentation and/or other materials provided with the distribution;
2110249Sstephan.diestelhorst@arm.com * neither the name of the copyright holders nor the names of its
2210249Sstephan.diestelhorst@arm.com * contributors may be used to endorse or promote products derived from
2310249Sstephan.diestelhorst@arm.com * this software without specific prior written permission.
2410249Sstephan.diestelhorst@arm.com *
2510249Sstephan.diestelhorst@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610249Sstephan.diestelhorst@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710249Sstephan.diestelhorst@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810249Sstephan.diestelhorst@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910249Sstephan.diestelhorst@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010249Sstephan.diestelhorst@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110249Sstephan.diestelhorst@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210249Sstephan.diestelhorst@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310249Sstephan.diestelhorst@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410249Sstephan.diestelhorst@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510249Sstephan.diestelhorst@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610249Sstephan.diestelhorst@arm.com *
3710249Sstephan.diestelhorst@arm.com * Authors: Vasileios Spiliopoulos
3810249Sstephan.diestelhorst@arm.com *          Akash Bagdia
3910249Sstephan.diestelhorst@arm.com *          Stephan Diestelhorst
4010249Sstephan.diestelhorst@arm.com */
4110249Sstephan.diestelhorst@arm.com
4211793Sbrandon.potter@amd.com#include "sim/dvfs_handler.hh"
4311793Sbrandon.potter@amd.com
4410249Sstephan.diestelhorst@arm.com#include <set>
4510249Sstephan.diestelhorst@arm.com#include <utility>
4610249Sstephan.diestelhorst@arm.com
4712334Sgabeblack@google.com#include "base/logging.hh"
4811800Sbrandon.potter@amd.com#include "base/trace.hh"
4910249Sstephan.diestelhorst@arm.com#include "debug/DVFS.hh"
5010249Sstephan.diestelhorst@arm.com#include "params/DVFSHandler.hh"
5110249Sstephan.diestelhorst@arm.com#include "sim/clock_domain.hh"
5211800Sbrandon.potter@amd.com#include "sim/eventq_impl.hh"
5310249Sstephan.diestelhorst@arm.com#include "sim/stat_control.hh"
5410249Sstephan.diestelhorst@arm.com#include "sim/voltage_domain.hh"
5510249Sstephan.diestelhorst@arm.com
5610249Sstephan.diestelhorst@arm.com//
5710249Sstephan.diestelhorst@arm.com//
5810249Sstephan.diestelhorst@arm.com// DVFSHandler methods implementation
5910249Sstephan.diestelhorst@arm.com//
6010249Sstephan.diestelhorst@arm.com
6110249Sstephan.diestelhorst@arm.comDVFSHandler::DVFSHandler(const Params *p)
6210249Sstephan.diestelhorst@arm.com    : SimObject(p),
6310249Sstephan.diestelhorst@arm.com      sysClkDomain(p->sys_clk_domain),
6410249Sstephan.diestelhorst@arm.com      enableHandler(p->enable),
6510249Sstephan.diestelhorst@arm.com      _transLatency(p->transition_latency)
6610249Sstephan.diestelhorst@arm.com{
6710249Sstephan.diestelhorst@arm.com    // Check supplied list of domains for sanity and add them to the
6810249Sstephan.diestelhorst@arm.com    // domain ID -> domain* hash
6911321Ssteve.reinhardt@amd.com    for (auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) {
7010249Sstephan.diestelhorst@arm.com        SrcClockDomain *d = *dit;
7110249Sstephan.diestelhorst@arm.com        DomainID domain_id = d->domainID();
7210249Sstephan.diestelhorst@arm.com
7310249Sstephan.diestelhorst@arm.com        fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\
7410249Sstephan.diestelhorst@arm.com                 "system clk domain entry");
7510249Sstephan.diestelhorst@arm.com        fatal_if(domain_id == SrcClockDomain::emptyDomainID,
7610249Sstephan.diestelhorst@arm.com                 "DVFS: Controlled domain %s needs to have a properly "\
7710249Sstephan.diestelhorst@arm.com                 " assigned ID.\n", d->name());
7810249Sstephan.diestelhorst@arm.com
7910249Sstephan.diestelhorst@arm.com        auto entry = std::make_pair(domain_id, d);
8010249Sstephan.diestelhorst@arm.com        bool new_elem = domains.insert(entry).second;
8110249Sstephan.diestelhorst@arm.com        fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\
8210249Sstephan.diestelhorst@arm.com                 "unique ID.\n", d->name(), domain_id);
8310249Sstephan.diestelhorst@arm.com
8410249Sstephan.diestelhorst@arm.com        // Create a dedicated event slot per known domain ID
8510249Sstephan.diestelhorst@arm.com        UpdateEvent *event = &updatePerfLevelEvents[domain_id];
8610249Sstephan.diestelhorst@arm.com        event->domainIDToSet = d->domainID();
8710395Sstephan.diestelhorst@arm.com
8810395Sstephan.diestelhorst@arm.com        // Add domain ID to the list of domains
8910395Sstephan.diestelhorst@arm.com        domainIDList.push_back(d->domainID());
9010249Sstephan.diestelhorst@arm.com    }
9110249Sstephan.diestelhorst@arm.com    UpdateEvent::dvfsHandler = this;
9210249Sstephan.diestelhorst@arm.com}
9310249Sstephan.diestelhorst@arm.com
9410249Sstephan.diestelhorst@arm.comDVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
9510249Sstephan.diestelhorst@arm.com
9610395Sstephan.diestelhorst@arm.comDVFSHandler::DomainID
9710395Sstephan.diestelhorst@arm.comDVFSHandler::domainID(uint32_t index) const
9810395Sstephan.diestelhorst@arm.com{
9910395Sstephan.diestelhorst@arm.com    fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
10010395Sstephan.diestelhorst@arm.com             "bound, max value %d\n", (domainIDList.size() - 1));
10110395Sstephan.diestelhorst@arm.com
10210395Sstephan.diestelhorst@arm.com    assert(domains.find(domainIDList[index]) != domains.end());
10310395Sstephan.diestelhorst@arm.com
10410395Sstephan.diestelhorst@arm.com    return domainIDList[index];
10510395Sstephan.diestelhorst@arm.com}
10610395Sstephan.diestelhorst@arm.com
10710249Sstephan.diestelhorst@arm.combool
10810249Sstephan.diestelhorst@arm.comDVFSHandler::validDomainID(DomainID domain_id) const
10910249Sstephan.diestelhorst@arm.com{
11010249Sstephan.diestelhorst@arm.com    assert(isEnabled());
11110249Sstephan.diestelhorst@arm.com    // This is ensure that the domain id as requested by the software is
11210249Sstephan.diestelhorst@arm.com    // availabe in the handler.
11310249Sstephan.diestelhorst@arm.com    if (domains.find(domain_id) != domains.end())
11410249Sstephan.diestelhorst@arm.com        return true;
11510249Sstephan.diestelhorst@arm.com    warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
11610249Sstephan.diestelhorst@arm.com         "domain\n", domain_id);
11710249Sstephan.diestelhorst@arm.com    return false;
11810249Sstephan.diestelhorst@arm.com}
11910249Sstephan.diestelhorst@arm.com
12010249Sstephan.diestelhorst@arm.combool
12110249Sstephan.diestelhorst@arm.comDVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level)
12210249Sstephan.diestelhorst@arm.com{
12310249Sstephan.diestelhorst@arm.com    assert(isEnabled());
12410249Sstephan.diestelhorst@arm.com
12510249Sstephan.diestelhorst@arm.com    DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level);
12610249Sstephan.diestelhorst@arm.com
12710249Sstephan.diestelhorst@arm.com    auto d = findDomain(domain_id);
12810249Sstephan.diestelhorst@arm.com    if (!d->validPerfLevel(perf_level)) {
12910249Sstephan.diestelhorst@arm.com        warn("DVFS: invalid performance level %d for domain ID %d, request "\
13010249Sstephan.diestelhorst@arm.com             "ignored\n", perf_level, domain_id);
13110249Sstephan.diestelhorst@arm.com        return false;
13210249Sstephan.diestelhorst@arm.com    }
13310249Sstephan.diestelhorst@arm.com
13410249Sstephan.diestelhorst@arm.com    UpdateEvent *update_event = &updatePerfLevelEvents[domain_id];
13510249Sstephan.diestelhorst@arm.com    // Drop an old DVFS change request once we have established that this is a
13610249Sstephan.diestelhorst@arm.com    // reasonable request
13710249Sstephan.diestelhorst@arm.com    if (update_event->scheduled()) {
13810249Sstephan.diestelhorst@arm.com        DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n");
13910249Sstephan.diestelhorst@arm.com        deschedule(update_event);
14010249Sstephan.diestelhorst@arm.com    }
14110249Sstephan.diestelhorst@arm.com
14210249Sstephan.diestelhorst@arm.com    update_event->perfLevelToSet = perf_level;
14310249Sstephan.diestelhorst@arm.com
14410249Sstephan.diestelhorst@arm.com    // State changes that restore to the current state (and / or overwrite a not
14510249Sstephan.diestelhorst@arm.com    // yet completed in-flight request) will be squashed
14610249Sstephan.diestelhorst@arm.com    if (d->perfLevel() == perf_level) {
14710249Sstephan.diestelhorst@arm.com        DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\
14810249Sstephan.diestelhorst@arm.com                "%d -> %d\n", d->perfLevel(), perf_level);
14910249Sstephan.diestelhorst@arm.com        return false;
15010249Sstephan.diestelhorst@arm.com    }
15110249Sstephan.diestelhorst@arm.com
15210249Sstephan.diestelhorst@arm.com    // At this point, a new transition will certainly take place -> schedule
15310249Sstephan.diestelhorst@arm.com    Tick when = curTick() + _transLatency;
15410249Sstephan.diestelhorst@arm.com    DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when);
15510249Sstephan.diestelhorst@arm.com
15610249Sstephan.diestelhorst@arm.com    schedule(update_event, when);
15710249Sstephan.diestelhorst@arm.com    return true;
15810249Sstephan.diestelhorst@arm.com}
15910249Sstephan.diestelhorst@arm.com
16010249Sstephan.diestelhorst@arm.comvoid
16110249Sstephan.diestelhorst@arm.comDVFSHandler::UpdateEvent::updatePerfLevel()
16210249Sstephan.diestelhorst@arm.com{
16310249Sstephan.diestelhorst@arm.com    // Perform explicit stats dump for power estimation before performance
16410249Sstephan.diestelhorst@arm.com    // level migration
16510249Sstephan.diestelhorst@arm.com    Stats::dump();
16610249Sstephan.diestelhorst@arm.com    Stats::reset();
16710249Sstephan.diestelhorst@arm.com
16810249Sstephan.diestelhorst@arm.com    // Update the performance level in the clock domain
16910249Sstephan.diestelhorst@arm.com    auto d = dvfsHandler->findDomain(domainIDToSet);
17010249Sstephan.diestelhorst@arm.com    assert(d->perfLevel() != perfLevelToSet);
17110249Sstephan.diestelhorst@arm.com
17210249Sstephan.diestelhorst@arm.com    d->perfLevel(perfLevelToSet);
17310249Sstephan.diestelhorst@arm.com}
17410249Sstephan.diestelhorst@arm.com
17511800Sbrandon.potter@amd.comdouble
17611800Sbrandon.potter@amd.comDVFSHandler::voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
17711800Sbrandon.potter@amd.com{
17811800Sbrandon.potter@amd.com    VoltageDomain *d = findDomain(domain_id)->voltageDomain();
17911800Sbrandon.potter@amd.com    assert(d);
18011800Sbrandon.potter@amd.com    PerfLevel n = d->numVoltages();
18111800Sbrandon.potter@amd.com    if (perf_level < n)
18211800Sbrandon.potter@amd.com        return d->voltage(perf_level);
18311800Sbrandon.potter@amd.com
18411800Sbrandon.potter@amd.com    // Request outside of the range of the voltage domain
18511800Sbrandon.potter@amd.com    if (n == 1) {
18611800Sbrandon.potter@amd.com        DPRINTF(DVFS, "DVFS: Request for perf-level %i for single-point "\
18711800Sbrandon.potter@amd.com                "voltage domain %s.  Returning voltage at level 0: %.2f "\
18811800Sbrandon.potter@amd.com                "V\n", perf_level, d->name(), d->voltage(0));
18911800Sbrandon.potter@amd.com        // Special case for single point voltage domain -> same voltage for
19011800Sbrandon.potter@amd.com        // all points
19111800Sbrandon.potter@amd.com        return d->voltage(0);
19211800Sbrandon.potter@amd.com    }
19311800Sbrandon.potter@amd.com
19411800Sbrandon.potter@amd.com    warn("DVFSHandler %s reads illegal voltage level %u from "\
19511800Sbrandon.potter@amd.com         "VoltageDomain %s. Returning 0 V\n", name(), perf_level, d->name());
19611800Sbrandon.potter@amd.com    return 0.;
19711800Sbrandon.potter@amd.com}
19811800Sbrandon.potter@amd.com
19910249Sstephan.diestelhorst@arm.comvoid
20010905Sandreas.sandberg@arm.comDVFSHandler::serialize(CheckpointOut &cp) const
20110249Sstephan.diestelhorst@arm.com{
20210249Sstephan.diestelhorst@arm.com    //This is to ensure that the handler status is maintained during the
20310249Sstephan.diestelhorst@arm.com    //entire simulation run and not changed from command line during checkpoint
20410249Sstephan.diestelhorst@arm.com    //and restore
20510249Sstephan.diestelhorst@arm.com    SERIALIZE_SCALAR(enableHandler);
20610249Sstephan.diestelhorst@arm.com
20710249Sstephan.diestelhorst@arm.com    // Pull out the hashed data structure into easy-to-serialise arrays;
20810249Sstephan.diestelhorst@arm.com    // ensuring that the data associated with any pending update event is saved
20910249Sstephan.diestelhorst@arm.com    std::vector<DomainID> domain_ids;
21010249Sstephan.diestelhorst@arm.com    std::vector<PerfLevel> perf_levels;
21110249Sstephan.diestelhorst@arm.com    std::vector<Tick> whens;
21210905Sandreas.sandberg@arm.com    for (const auto &ev_pair : updatePerfLevelEvents) {
21310905Sandreas.sandberg@arm.com        DomainID id = ev_pair.first;
21410905Sandreas.sandberg@arm.com        const UpdateEvent *event = &ev_pair.second;
21510249Sstephan.diestelhorst@arm.com
21610249Sstephan.diestelhorst@arm.com        assert(id == event->domainIDToSet);
21710249Sstephan.diestelhorst@arm.com        domain_ids.push_back(id);
21810249Sstephan.diestelhorst@arm.com        perf_levels.push_back(event->perfLevelToSet);
21910249Sstephan.diestelhorst@arm.com        whens.push_back(event->scheduled() ? event->when() : 0);
22010249Sstephan.diestelhorst@arm.com    }
22110905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(domain_ids);
22210905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(perf_levels);
22310905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(whens);
22410249Sstephan.diestelhorst@arm.com}
22510249Sstephan.diestelhorst@arm.com
22610249Sstephan.diestelhorst@arm.comvoid
22710905Sandreas.sandberg@arm.comDVFSHandler::unserialize(CheckpointIn &cp)
22810249Sstephan.diestelhorst@arm.com{
22910395Sstephan.diestelhorst@arm.com    bool temp = enableHandler;
23010395Sstephan.diestelhorst@arm.com
23110249Sstephan.diestelhorst@arm.com    UNSERIALIZE_SCALAR(enableHandler);
23210249Sstephan.diestelhorst@arm.com
23311321Ssteve.reinhardt@amd.com    if (temp != enableHandler) {
23410395Sstephan.diestelhorst@arm.com        warn("DVFS: Forcing enable handler status to unserialized value of %d",
23510395Sstephan.diestelhorst@arm.com             enableHandler);
23610395Sstephan.diestelhorst@arm.com    }
23710395Sstephan.diestelhorst@arm.com
23810249Sstephan.diestelhorst@arm.com    // Reconstruct the map of domain IDs and their scheduled events
23910249Sstephan.diestelhorst@arm.com    std::vector<DomainID> domain_ids;
24010249Sstephan.diestelhorst@arm.com    std::vector<PerfLevel> perf_levels;
24110249Sstephan.diestelhorst@arm.com    std::vector<Tick> whens;
24210905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(domain_ids);
24310905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(perf_levels);
24410905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(whens);
24510249Sstephan.diestelhorst@arm.com
24610249Sstephan.diestelhorst@arm.com    for (size_t i = 0; i < domain_ids.size(); ++i) {;
24710249Sstephan.diestelhorst@arm.com        UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]];
24810249Sstephan.diestelhorst@arm.com
24910249Sstephan.diestelhorst@arm.com        event->domainIDToSet = domain_ids[i];
25010249Sstephan.diestelhorst@arm.com        event->perfLevelToSet = perf_levels[i];
25110249Sstephan.diestelhorst@arm.com
25210249Sstephan.diestelhorst@arm.com        // Schedule all previously scheduled events
25310249Sstephan.diestelhorst@arm.com        if (whens[i])
25410249Sstephan.diestelhorst@arm.com            schedule(event, whens[i]);
25510249Sstephan.diestelhorst@arm.com    }
25610249Sstephan.diestelhorst@arm.com    UpdateEvent::dvfsHandler = this;
25710249Sstephan.diestelhorst@arm.com}
25810249Sstephan.diestelhorst@arm.com
25910249Sstephan.diestelhorst@arm.comDVFSHandler*
26010249Sstephan.diestelhorst@arm.comDVFSHandlerParams::create()
26110249Sstephan.diestelhorst@arm.com{
26210249Sstephan.diestelhorst@arm.com    return new DVFSHandler(this);
26310249Sstephan.diestelhorst@arm.com}
264