blob: 9a2ce239c993bacf63aa3807f7b780814c072ff3 [file] [log] [blame]
/**
* Copyright (c) 2019, 2020 Inria
* All rights reserved.
*
* 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.
*/
#include "mem/cache/replacement_policies/dueling_rp.hh"
#include "base/logging.hh"
#include "params/DuelingRP.hh"
namespace gem5
{
namespace replacement_policy
{
Dueling::Dueling(const Params &p)
: Base(p), replPolicyA(p.replacement_policy_a),
replPolicyB(p.replacement_policy_b),
duelingMonitor(p.constituency_size, p.team_size),
duelingStats(this)
{
fatal_if((replPolicyA == nullptr) || (replPolicyB == nullptr),
"All replacement policies must be instantiated");
}
void
Dueling::invalidate(const std::shared_ptr<ReplacementData>& replacement_data)
{
std::shared_ptr<DuelerReplData> casted_replacement_data =
std::static_pointer_cast<DuelerReplData>(replacement_data);
replPolicyA->invalidate(casted_replacement_data->replDataA);
replPolicyB->invalidate(casted_replacement_data->replDataB);
}
void
Dueling::touch(const std::shared_ptr<ReplacementData>& replacement_data,
const PacketPtr pkt)
{
std::shared_ptr<DuelerReplData> casted_replacement_data =
std::static_pointer_cast<DuelerReplData>(replacement_data);
replPolicyA->touch(casted_replacement_data->replDataA, pkt);
replPolicyB->touch(casted_replacement_data->replDataB, pkt);
}
void
Dueling::touch(const std::shared_ptr<ReplacementData>& replacement_data) const
{
std::shared_ptr<DuelerReplData> casted_replacement_data =
std::static_pointer_cast<DuelerReplData>(replacement_data);
replPolicyA->touch(casted_replacement_data->replDataA);
replPolicyB->touch(casted_replacement_data->replDataB);
}
void
Dueling::reset(const std::shared_ptr<ReplacementData>& replacement_data,
const PacketPtr pkt)
{
std::shared_ptr<DuelerReplData> casted_replacement_data =
std::static_pointer_cast<DuelerReplData>(replacement_data);
replPolicyA->reset(casted_replacement_data->replDataA, pkt);
replPolicyB->reset(casted_replacement_data->replDataB, pkt);
// A miss in a set is a sample to the duel. A call to this function
// implies in the replacement of an entry, which was either caused by
// a miss, an external invalidation, or the initialization of the table
// entry (when warming up)
duelingMonitor.sample(static_cast<Dueler*>(casted_replacement_data.get()));
}
void
Dueling::reset(const std::shared_ptr<ReplacementData>& replacement_data) const
{
std::shared_ptr<DuelerReplData> casted_replacement_data =
std::static_pointer_cast<DuelerReplData>(replacement_data);
replPolicyA->reset(casted_replacement_data->replDataA);
replPolicyB->reset(casted_replacement_data->replDataB);
// A miss in a set is a sample to the duel. A call to this function
// implies in the replacement of an entry, which was either caused by
// a miss, an external invalidation, or the initialization of the table
// entry (when warming up)
duelingMonitor.sample(static_cast<Dueler*>(casted_replacement_data.get()));
}
ReplaceableEntry*
Dueling::getVictim(const ReplacementCandidates& candidates) const
{
// This function assumes that all candidates are either part of the same
// sampled set, or are not samples.
// @todo This should be improved at some point.
panic_if(candidates.size() != params().team_size, "We currently only "
"support team sizes that match the number of replacement candidates");
// The team with the most misses loses
bool winner = !duelingMonitor.getWinner();
// If the entry is a sample, it can only be used with a certain policy.
bool team;
bool is_sample = duelingMonitor.isSample(static_cast<Dueler*>(
std::static_pointer_cast<DuelerReplData>(
candidates[0]->replacementData).get()), team);
// All replacement candidates must be set appropriately, so that the
// proper replacement data is used. A replacement policy X must be used
// if the candidates are its samples - in which case they must always
// use X - or if it is not a sample, and X is currently the best RP.
// This assumes that A's team is "false", and B's team is "true".
bool team_a;
if ((is_sample && !team) || (!is_sample && !winner)) {
duelingStats.selectedA++;
team_a = true;
} else {
duelingStats.selectedB++;
team_a = false;
}
// Create a temporary list of replacement candidates which re-routes the
// replacement data of the selected team
std::vector<std::shared_ptr<ReplacementData>> dueling_replacement_data;
for (auto& candidate : candidates) {
std::shared_ptr<DuelerReplData> dueler_repl_data =
std::static_pointer_cast<DuelerReplData>(
candidate->replacementData);
// As of now we assume that all candidates are either part of
// the same sampled team, or are not samples.
bool candidate_team;
panic_if(
duelingMonitor.isSample(dueler_repl_data.get(), candidate_team) &&
(team != candidate_team),
"Not all sampled candidates belong to the same team");
// Copy the original entry's data, re-routing its replacement data
// to the selected one
dueling_replacement_data.push_back(dueler_repl_data);
candidate->replacementData = team_a ? dueler_repl_data->replDataA :
dueler_repl_data->replDataB;
}
// Use the selected replacement policy to find the victim
ReplaceableEntry* victim = team_a ? replPolicyA->getVictim(candidates) :
replPolicyB->getVictim(candidates);
// Search for entry within the original candidates and clean-up duplicates
for (int i = 0; i < candidates.size(); i++) {
candidates[i]->replacementData = dueling_replacement_data[i];
}
return victim;
}
std::shared_ptr<ReplacementData>
Dueling::instantiateEntry()
{
DuelerReplData* replacement_data = new DuelerReplData(
replPolicyA->instantiateEntry(), replPolicyB->instantiateEntry());
duelingMonitor.initEntry(static_cast<Dueler*>(replacement_data));
return std::shared_ptr<DuelerReplData>(replacement_data);
}
Dueling::DuelingStats::DuelingStats(statistics::Group* parent)
: statistics::Group(parent),
ADD_STAT(selectedA, "Number of times A was selected to victimize"),
ADD_STAT(selectedB, "Number of times B was selected to victimize")
{
}
} // namespace replacement_policy
} // namespace gem5