dvfs_handler.cc revision 11793
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
4710249Sstephan.diestelhorst@arm.com#include "base/misc.hh"
4810249Sstephan.diestelhorst@arm.com#include "debug/DVFS.hh"
4910249Sstephan.diestelhorst@arm.com#include "params/DVFSHandler.hh"
5010249Sstephan.diestelhorst@arm.com#include "sim/clock_domain.hh"
5110249Sstephan.diestelhorst@arm.com#include "sim/stat_control.hh"
5210249Sstephan.diestelhorst@arm.com#include "sim/voltage_domain.hh"
5310249Sstephan.diestelhorst@arm.com
5410249Sstephan.diestelhorst@arm.com//
5510249Sstephan.diestelhorst@arm.com//
5610249Sstephan.diestelhorst@arm.com// DVFSHandler methods implementation
5710249Sstephan.diestelhorst@arm.com//
5810249Sstephan.diestelhorst@arm.com
5910249Sstephan.diestelhorst@arm.comDVFSHandler::DVFSHandler(const Params *p)
6010249Sstephan.diestelhorst@arm.com    : SimObject(p),
6110249Sstephan.diestelhorst@arm.com      sysClkDomain(p->sys_clk_domain),
6210249Sstephan.diestelhorst@arm.com      enableHandler(p->enable),
6310249Sstephan.diestelhorst@arm.com      _transLatency(p->transition_latency)
6410249Sstephan.diestelhorst@arm.com{
6510249Sstephan.diestelhorst@arm.com    // Check supplied list of domains for sanity and add them to the
6610249Sstephan.diestelhorst@arm.com    // domain ID -> domain* hash
6711321Ssteve.reinhardt@amd.com    for (auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) {
6810249Sstephan.diestelhorst@arm.com        SrcClockDomain *d = *dit;
6910249Sstephan.diestelhorst@arm.com        DomainID domain_id = d->domainID();
7010249Sstephan.diestelhorst@arm.com
7110249Sstephan.diestelhorst@arm.com        fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\
7210249Sstephan.diestelhorst@arm.com                 "system clk domain entry");
7310249Sstephan.diestelhorst@arm.com        fatal_if(domain_id == SrcClockDomain::emptyDomainID,
7410249Sstephan.diestelhorst@arm.com                 "DVFS: Controlled domain %s needs to have a properly "\
7510249Sstephan.diestelhorst@arm.com                 " assigned ID.\n", d->name());
7610249Sstephan.diestelhorst@arm.com
7710249Sstephan.diestelhorst@arm.com        auto entry = std::make_pair(domain_id, d);
7810249Sstephan.diestelhorst@arm.com        bool new_elem = domains.insert(entry).second;
7910249Sstephan.diestelhorst@arm.com        fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\
8010249Sstephan.diestelhorst@arm.com                 "unique ID.\n", d->name(), domain_id);
8110249Sstephan.diestelhorst@arm.com
8210249Sstephan.diestelhorst@arm.com        // Create a dedicated event slot per known domain ID
8310249Sstephan.diestelhorst@arm.com        UpdateEvent *event = &updatePerfLevelEvents[domain_id];
8410249Sstephan.diestelhorst@arm.com        event->domainIDToSet = d->domainID();
8510395Sstephan.diestelhorst@arm.com
8610395Sstephan.diestelhorst@arm.com        // Add domain ID to the list of domains
8710395Sstephan.diestelhorst@arm.com        domainIDList.push_back(d->domainID());
8810249Sstephan.diestelhorst@arm.com    }
8910249Sstephan.diestelhorst@arm.com    UpdateEvent::dvfsHandler = this;
9010249Sstephan.diestelhorst@arm.com}
9110249Sstephan.diestelhorst@arm.com
9210249Sstephan.diestelhorst@arm.comDVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
9310249Sstephan.diestelhorst@arm.com
9410395Sstephan.diestelhorst@arm.comDVFSHandler::DomainID
9510395Sstephan.diestelhorst@arm.comDVFSHandler::domainID(uint32_t index) const
9610395Sstephan.diestelhorst@arm.com{
9710395Sstephan.diestelhorst@arm.com    fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
9810395Sstephan.diestelhorst@arm.com             "bound, max value %d\n", (domainIDList.size() - 1));
9910395Sstephan.diestelhorst@arm.com
10010395Sstephan.diestelhorst@arm.com    assert(domains.find(domainIDList[index]) != domains.end());
10110395Sstephan.diestelhorst@arm.com
10210395Sstephan.diestelhorst@arm.com    return domainIDList[index];
10310395Sstephan.diestelhorst@arm.com}
10410395Sstephan.diestelhorst@arm.com
10510249Sstephan.diestelhorst@arm.combool
10610249Sstephan.diestelhorst@arm.comDVFSHandler::validDomainID(DomainID domain_id) const
10710249Sstephan.diestelhorst@arm.com{
10810249Sstephan.diestelhorst@arm.com    assert(isEnabled());
10910249Sstephan.diestelhorst@arm.com    // This is ensure that the domain id as requested by the software is
11010249Sstephan.diestelhorst@arm.com    // availabe in the handler.
11110249Sstephan.diestelhorst@arm.com    if (domains.find(domain_id) != domains.end())
11210249Sstephan.diestelhorst@arm.com        return true;
11310249Sstephan.diestelhorst@arm.com    warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
11410249Sstephan.diestelhorst@arm.com         "domain\n", domain_id);
11510249Sstephan.diestelhorst@arm.com    return false;
11610249Sstephan.diestelhorst@arm.com}
11710249Sstephan.diestelhorst@arm.com
11810249Sstephan.diestelhorst@arm.combool
11910249Sstephan.diestelhorst@arm.comDVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level)
12010249Sstephan.diestelhorst@arm.com{
12110249Sstephan.diestelhorst@arm.com    assert(isEnabled());
12210249Sstephan.diestelhorst@arm.com
12310249Sstephan.diestelhorst@arm.com    DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level);
12410249Sstephan.diestelhorst@arm.com
12510249Sstephan.diestelhorst@arm.com    auto d = findDomain(domain_id);
12610249Sstephan.diestelhorst@arm.com    if (!d->validPerfLevel(perf_level)) {
12710249Sstephan.diestelhorst@arm.com        warn("DVFS: invalid performance level %d for domain ID %d, request "\
12810249Sstephan.diestelhorst@arm.com             "ignored\n", perf_level, domain_id);
12910249Sstephan.diestelhorst@arm.com        return false;
13010249Sstephan.diestelhorst@arm.com    }
13110249Sstephan.diestelhorst@arm.com
13210249Sstephan.diestelhorst@arm.com    UpdateEvent *update_event = &updatePerfLevelEvents[domain_id];
13310249Sstephan.diestelhorst@arm.com    // Drop an old DVFS change request once we have established that this is a
13410249Sstephan.diestelhorst@arm.com    // reasonable request
13510249Sstephan.diestelhorst@arm.com    if (update_event->scheduled()) {
13610249Sstephan.diestelhorst@arm.com        DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n");
13710249Sstephan.diestelhorst@arm.com        deschedule(update_event);
13810249Sstephan.diestelhorst@arm.com    }
13910249Sstephan.diestelhorst@arm.com
14010249Sstephan.diestelhorst@arm.com    update_event->perfLevelToSet = perf_level;
14110249Sstephan.diestelhorst@arm.com
14210249Sstephan.diestelhorst@arm.com    // State changes that restore to the current state (and / or overwrite a not
14310249Sstephan.diestelhorst@arm.com    // yet completed in-flight request) will be squashed
14410249Sstephan.diestelhorst@arm.com    if (d->perfLevel() == perf_level) {
14510249Sstephan.diestelhorst@arm.com        DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\
14610249Sstephan.diestelhorst@arm.com                "%d -> %d\n", d->perfLevel(), perf_level);
14710249Sstephan.diestelhorst@arm.com        return false;
14810249Sstephan.diestelhorst@arm.com    }
14910249Sstephan.diestelhorst@arm.com
15010249Sstephan.diestelhorst@arm.com    // At this point, a new transition will certainly take place -> schedule
15110249Sstephan.diestelhorst@arm.com    Tick when = curTick() + _transLatency;
15210249Sstephan.diestelhorst@arm.com    DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when);
15310249Sstephan.diestelhorst@arm.com
15410249Sstephan.diestelhorst@arm.com    schedule(update_event, when);
15510249Sstephan.diestelhorst@arm.com    return true;
15610249Sstephan.diestelhorst@arm.com}
15710249Sstephan.diestelhorst@arm.com
15810249Sstephan.diestelhorst@arm.comvoid
15910249Sstephan.diestelhorst@arm.comDVFSHandler::UpdateEvent::updatePerfLevel()
16010249Sstephan.diestelhorst@arm.com{
16110249Sstephan.diestelhorst@arm.com    // Perform explicit stats dump for power estimation before performance
16210249Sstephan.diestelhorst@arm.com    // level migration
16310249Sstephan.diestelhorst@arm.com    Stats::dump();
16410249Sstephan.diestelhorst@arm.com    Stats::reset();
16510249Sstephan.diestelhorst@arm.com
16610249Sstephan.diestelhorst@arm.com    // Update the performance level in the clock domain
16710249Sstephan.diestelhorst@arm.com    auto d = dvfsHandler->findDomain(domainIDToSet);
16810249Sstephan.diestelhorst@arm.com    assert(d->perfLevel() != perfLevelToSet);
16910249Sstephan.diestelhorst@arm.com
17010249Sstephan.diestelhorst@arm.com    d->perfLevel(perfLevelToSet);
17110249Sstephan.diestelhorst@arm.com}
17210249Sstephan.diestelhorst@arm.com
17310249Sstephan.diestelhorst@arm.comvoid
17410905Sandreas.sandberg@arm.comDVFSHandler::serialize(CheckpointOut &cp) const
17510249Sstephan.diestelhorst@arm.com{
17610249Sstephan.diestelhorst@arm.com    //This is to ensure that the handler status is maintained during the
17710249Sstephan.diestelhorst@arm.com    //entire simulation run and not changed from command line during checkpoint
17810249Sstephan.diestelhorst@arm.com    //and restore
17910249Sstephan.diestelhorst@arm.com    SERIALIZE_SCALAR(enableHandler);
18010249Sstephan.diestelhorst@arm.com
18110249Sstephan.diestelhorst@arm.com    // Pull out the hashed data structure into easy-to-serialise arrays;
18210249Sstephan.diestelhorst@arm.com    // ensuring that the data associated with any pending update event is saved
18310249Sstephan.diestelhorst@arm.com    std::vector<DomainID> domain_ids;
18410249Sstephan.diestelhorst@arm.com    std::vector<PerfLevel> perf_levels;
18510249Sstephan.diestelhorst@arm.com    std::vector<Tick> whens;
18610905Sandreas.sandberg@arm.com    for (const auto &ev_pair : updatePerfLevelEvents) {
18710905Sandreas.sandberg@arm.com        DomainID id = ev_pair.first;
18810905Sandreas.sandberg@arm.com        const UpdateEvent *event = &ev_pair.second;
18910249Sstephan.diestelhorst@arm.com
19010249Sstephan.diestelhorst@arm.com        assert(id == event->domainIDToSet);
19110249Sstephan.diestelhorst@arm.com        domain_ids.push_back(id);
19210249Sstephan.diestelhorst@arm.com        perf_levels.push_back(event->perfLevelToSet);
19310249Sstephan.diestelhorst@arm.com        whens.push_back(event->scheduled() ? event->when() : 0);
19410249Sstephan.diestelhorst@arm.com    }
19510905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(domain_ids);
19610905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(perf_levels);
19710905Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(whens);
19810249Sstephan.diestelhorst@arm.com}
19910249Sstephan.diestelhorst@arm.com
20010249Sstephan.diestelhorst@arm.comvoid
20110905Sandreas.sandberg@arm.comDVFSHandler::unserialize(CheckpointIn &cp)
20210249Sstephan.diestelhorst@arm.com{
20310395Sstephan.diestelhorst@arm.com    bool temp = enableHandler;
20410395Sstephan.diestelhorst@arm.com
20510249Sstephan.diestelhorst@arm.com    UNSERIALIZE_SCALAR(enableHandler);
20610249Sstephan.diestelhorst@arm.com
20711321Ssteve.reinhardt@amd.com    if (temp != enableHandler) {
20810395Sstephan.diestelhorst@arm.com        warn("DVFS: Forcing enable handler status to unserialized value of %d",
20910395Sstephan.diestelhorst@arm.com             enableHandler);
21010395Sstephan.diestelhorst@arm.com    }
21110395Sstephan.diestelhorst@arm.com
21210249Sstephan.diestelhorst@arm.com    // Reconstruct the map of domain IDs and their scheduled events
21310249Sstephan.diestelhorst@arm.com    std::vector<DomainID> domain_ids;
21410249Sstephan.diestelhorst@arm.com    std::vector<PerfLevel> perf_levels;
21510249Sstephan.diestelhorst@arm.com    std::vector<Tick> whens;
21610905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(domain_ids);
21710905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(perf_levels);
21810905Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(whens);
21910249Sstephan.diestelhorst@arm.com
22010249Sstephan.diestelhorst@arm.com    for (size_t i = 0; i < domain_ids.size(); ++i) {;
22110249Sstephan.diestelhorst@arm.com        UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]];
22210249Sstephan.diestelhorst@arm.com
22310249Sstephan.diestelhorst@arm.com        event->domainIDToSet = domain_ids[i];
22410249Sstephan.diestelhorst@arm.com        event->perfLevelToSet = perf_levels[i];
22510249Sstephan.diestelhorst@arm.com
22610249Sstephan.diestelhorst@arm.com        // Schedule all previously scheduled events
22710249Sstephan.diestelhorst@arm.com        if (whens[i])
22810249Sstephan.diestelhorst@arm.com            schedule(event, whens[i]);
22910249Sstephan.diestelhorst@arm.com    }
23010249Sstephan.diestelhorst@arm.com    UpdateEvent::dvfsHandler = this;
23110249Sstephan.diestelhorst@arm.com}
23210249Sstephan.diestelhorst@arm.com
23310249Sstephan.diestelhorst@arm.comDVFSHandler*
23410249Sstephan.diestelhorst@arm.comDVFSHandlerParams::create()
23510249Sstephan.diestelhorst@arm.com{
23610249Sstephan.diestelhorst@arm.com    return new DVFSHandler(this);
23710249Sstephan.diestelhorst@arm.com}
238