dvfs_handler.hh revision 10398
1/*
2 * Copyright (c) 2013-2014 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: Vasileios Spiliopoulos
38 *          Akash Bagdia
39 *          Stephan Diestelhorst
40 */
41
42/**
43 * @file
44 * DVFSHandler and DomainConfig class declaration used for managing voltage
45 * and frequency scaling of the various DVFS domains in the system (with each
46 * domain having their independent domain configuration information)
47 */
48
49
50#ifndef __SIM_DVFS_HANDLER_HH__
51#define __SIM_DVFS_HANDLER_HH__
52
53#include <vector>
54
55#include "debug/DVFS.hh"
56#include "params/ClockDomain.hh"
57#include "params/DVFSHandler.hh"
58#include "params/VoltageDomain.hh"
59#include "sim/clock_domain.hh"
60#include "sim/eventq.hh"
61#include "sim/sim_object.hh"
62#include "sim/voltage_domain.hh"
63
64/**
65 * DVFS Handler class, maintains a list of all the domains it can handle.
66 * Each entry of that list is an object of the DomainConfig class, and the
67 * handler uses the methods provided by that class to get access to the
68 * configuration of each domain. The handler is responsible for setting/getting
69 * clock periods and voltages from clock/voltage domains.
70 * The handler acts the bridge between software configurable information
71 * for each domain as provided to the controller and the hardware
72 * implementation details for those domains.
73 */
74class DVFSHandler : public SimObject
75{
76  public:
77    typedef DVFSHandlerParams Params;
78    DVFSHandler(const Params *p);
79
80    typedef SrcClockDomain::DomainID DomainID;
81    typedef SrcClockDomain::PerfLevel PerfLevel;
82
83    /**
84     * Get the number of domains assigned to this DVFS handler.
85     * @return Number of domains
86     */
87    uint32_t numDomains() const { return domainIDList.size(); }
88
89    /**
90     * Get the n-th domain ID, from the domains managed by this handler.
91     * @return Domain ID
92     */
93    DomainID domainID(uint32_t index) const;
94
95    /**
96     * Check whether a domain ID is known to the handler or not.
97     * @param domain_id Domain ID to check
98     * @return Domain ID known to handler?
99     */
100    bool validDomainID(DomainID domain_id) const;
101
102    /**
103     * Get transition latency to switch between performance levels.
104     * @return Transition latency
105     */
106    Tick transLatency() const { return _transLatency; }
107
108    /**
109     * Set a new performance level for the specified domain.  The actual update
110     * will be delayed by transLatency().
111     *
112     * @param domain_id Software visible ID of the domain to be configured
113     * @param perf_level Requested performance level (0 - fast, >0 slower)
114     * @return status whether the setting was successful
115     */
116    bool perfLevel(DomainID domain_id, PerfLevel perf_level);
117
118    /**
119     * Get the current performance level of a domain.  While a change request is
120     * in-flight, will return the current (i.e. old, unmodified) value.
121     *
122     * @param domain_id Domain ID to query
123     * @return Current performance level of the specified domain
124     */
125    PerfLevel perfLevel(DomainID domain_id) const {
126         assert(isEnabled());
127         return findDomain(domain_id)->perfLevel();
128    }
129
130    /**
131     * Read the clock period of the specified domain at the specified
132     * performance level.
133     * @param domain_id Domain ID to query
134     * @param perf_level Performance level of interest
135     * @return Clock period in ticks for the requested performance level of
136     * the respective domain
137     */
138    Tick clkPeriodAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
139    {
140        SrcClockDomain *d = findDomain(domain_id);
141        assert(d);
142        PerfLevel n = d->numPerfLevels();
143        if (perf_level < n)
144            return d->clkPeriodAtPerfLevel(perf_level);
145
146        warn("DVFSHandler %s reads illegal frequency level %u from "\
147             "SrcClockDomain %s. Returning 0\n", name(), perf_level, d->name());
148        return Tick(0);
149    }
150
151    /**
152     * Read the voltage of the specified domain at the specified
153     * performance level.
154     * @param domain_id Domain ID to query
155     * @param perf_level Performance level of interest
156     * @return Voltage for the requested performance level of the respective
157     * domain
158     */
159    double voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
160    {
161        VoltageDomain *d = findDomain(domain_id)->voltageDomain();
162        assert(d);
163        PerfLevel n = d->numVoltages();
164        if (perf_level < n)
165            return d->voltage(perf_level);
166
167        // Request outside of the range of the voltage domain
168        if (n == 1) {
169            DPRINTF(DVFS, "DVFS: Request for perf-level %i for single-point "\
170                    "voltage domain %s.  Returning voltage at level 0: %.2f "\
171                    "V\n", perf_level, d->name(), d->voltage(0));
172            // Special case for single point voltage domain -> same voltage for
173            // all points
174            return d->voltage(0);
175        }
176
177        warn("DVFSHandler %s reads illegal voltage level %u from "\
178             "VoltageDomain %s. Returning 0 V\n", name(), perf_level, d->name());
179        return 0.;
180    }
181
182    /**
183     * Get the total number of available performance levels.
184     *
185     * @param domain_id Domain ID to query
186     * @return Number of performance levels that where configured for the
187     * respective domain
188     */
189    PerfLevel numPerfLevels(PerfLevel domain_id) const
190    {
191        return findDomain(domain_id)->numPerfLevels();
192    }
193
194    /**
195     * Check enable status of the DVFS handler, when the handler is disabled, no
196     * request should be sent to the handler.
197     * @return True, if the handler is enabled
198     */
199    bool isEnabled() const { return enableHandler; }
200
201    void serialize(std::ostream &os);
202    void unserialize(Checkpoint *cp, const std::string &section);
203
204  private:
205    typedef std::map<DomainID, SrcClockDomain*> Domains;
206    Domains domains;
207
208    /**
209      * List of IDs avaiable in the domain list
210      */
211    std::vector<DomainID> domainIDList;
212
213    /**
214      * Clock domain of the system the handler is instantiated.
215      */
216    SrcClockDomain* sysClkDomain;
217
218    /**
219     * Search for a domain based on the domain ID.
220     *
221     * @param domain_id Domain ID to search for
222     * @return Pointer to the source clock domain with matching ID.
223     */
224    SrcClockDomain *findDomain(DomainID domain_id) const {
225        auto it = domains.find(domain_id);
226        panic_if(it == domains.end(),
227                 "DVFS: Could not find a domain for ID %d.\n",domain_id );
228        return domains.find(domain_id)->second;
229    }
230
231    /**
232     * Disabling the DVFS handler ensures that all the DVFS migration requests
233     * are ignored. Domains remain at their default frequency and voltage.
234     */
235    bool enableHandler;
236
237
238    /**
239     * This corresponds to the maximum transition latency associated with the
240     * hardware transitioning from a particular performance level to the other
241     */
242    const Tick _transLatency;
243
244
245
246    /**
247     * Update performance level event, encapsulates all the required information
248     * for a future call to change a domain's performance level.
249     */
250    struct UpdateEvent : public Event {
251        UpdateEvent() : Event(DVFS_Update_Pri), domainIDToSet(0),
252                        perfLevelToSet(0) {}
253
254        /**
255         * Static pointer to the single DVFS hander for all the update events
256         */
257        static DVFSHandler *dvfsHandler;
258
259        /**
260         * ID of the domain that will be changed by the in-flight event
261         */
262        DomainID domainIDToSet;
263
264        /**
265         * Target performance level of the in-flight event
266         */
267        PerfLevel perfLevelToSet;
268
269        /**
270         * Updates the performance level by modifying the clock and the voltage
271         * of the associated clocked objects.  Gets information from
272         * domainIDToSet and perfLevelToSet for easier calling through an
273         * event.
274         */
275        void updatePerfLevel();
276
277        void process() { updatePerfLevel(); }
278    };
279
280    typedef std::map<DomainID, UpdateEvent> UpdatePerfLevelEvents;
281    /**
282     * Map from domain IDs -> perf level update events, records in-flight change
283     * requests per domain ID.
284     */
285    UpdatePerfLevelEvents updatePerfLevelEvents;
286};
287
288#endif // __SIM_DVFS_HANDLER_HH__
289