blob: b840ab53c31b878ccb0bd0b0e915701ff98b33cf [file] [log] [blame]
/*
* Copyright (c) 2012-2014, TU Delft
* Copyright (c) 2012-2014, TU Eindhoven
* Copyright (c) 2012-2014, TU Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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
* HOLDER 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: Karthik Chandrasekar,
* Matthias Jung,
* Omar Naji,
* Sven Goossens,
* Éder F. Zulian
* Subash Kannoth
* Felipe S. Prado
*
*/
#include <fstream>
#include <algorithm>
#include <sstream>
#include "CommandAnalysis.h"
#include "CmdScheduler.h"
using namespace Data;
using namespace std;
bool commandSorter(const MemCommand& i, const MemCommand& j)
{
if (i.getTimeInt64() == j.getTimeInt64()) {
return i.getType() == MemCommand::PRE && j.getType() != MemCommand::PRE;
} else {
return i.getTimeInt64() < j.getTimeInt64();
}
}
CommandAnalysis::CommandAnalysis(const Data::MemorySpecification& memSpec) :
memSpec(memSpec)
{
auto &nBanks = memSpec.memArchSpec.nbrOfBanks;
// Initializing all counters and variables
numberofactsBanks.assign(static_cast<size_t>(nBanks), 0);
numberofpresBanks.assign(static_cast<size_t>(nBanks), 0);
numberofreadsBanks.assign(static_cast<size_t>(nBanks), 0);
numberofwritesBanks.assign(static_cast<size_t>(nBanks), 0);
actcyclesBanks.assign(static_cast<size_t>(nBanks), 0);
numberofrefbBanks.assign(static_cast<size_t>(nBanks), 0);
first_act_cycle_banks.resize(static_cast<size_t>(nBanks), 0);
clearStats(0);
zero = 0;
bank_state.resize(static_cast<size_t>(nBanks), BANK_PRECHARGED);
last_bank_state.resize(static_cast<size_t>(nBanks), BANK_PRECHARGED);
mem_state = MS_NOT_IN_PD;
cmd_list.clear();
cached_cmd.clear();
activation_cycle.resize(static_cast<size_t>(nBanks), 0);
num_banks = nBanks;
}
// function to clear counters
void CommandAnalysis::clearStats(const int64_t timestamp)
{
std::fill(numberofactsBanks.begin(), numberofactsBanks.end(), 0);
std::fill(numberofpresBanks.begin(), numberofpresBanks.end(), 0);
std::fill(numberofreadsBanks.begin(), numberofreadsBanks.end(), 0);
std::fill(numberofwritesBanks.begin(), numberofwritesBanks.end(), 0);
std::fill(actcyclesBanks.begin(), actcyclesBanks.end(), 0);
numberofrefs = 0;
f_act_pdns = 0;
s_act_pdns = 0;
f_pre_pdns = 0;
s_pre_pdns = 0;
numberofsrefs = 0;
actcycles = 0;
precycles = 0;
f_act_pdcycles = 0;
s_act_pdcycles = 0;
f_pre_pdcycles = 0;
s_pre_pdcycles = 0;
pup_act_cycles = 0;
pup_pre_cycles = 0;
sref_cycles = 0;
spup_cycles = 0;
sref_ref_act_cycles = 0;
sref_ref_pre_cycles = 0;
spup_ref_act_cycles = 0;
spup_ref_pre_cycles = 0;
idlecycles_act = 0;
idlecycles_pre = 0;
// reset count references to timestamp so that they are moved
// to start of next stats generation
std::fill(first_act_cycle_banks.begin(), first_act_cycle_banks.end(), timestamp);
first_act_cycle = timestamp;
pdn_cycle = timestamp;
sref_cycle_window = timestamp;
end_act_op = timestamp;
end_read_op = timestamp;
end_write_op = timestamp;
latest_read_cycle = -1;
latest_write_cycle = -1;
if (timestamp == 0) {
latest_pre_cycle = -1;
latest_act_cycle = -1;
sref_cycle = 0;
last_pre_cycle = 0;
sref_ref_act_cycles_window = 0;
sref_ref_pre_cycles_window = 0;
} else {
last_pre_cycle = max(timestamp,last_pre_cycle);
latest_pre_cycle = max(timestamp, latest_pre_cycle);
if (latest_act_cycle < timestamp)
latest_act_cycle = -1;
}
}
// function to clear all arrays
void CommandAnalysis::clear()
{
cached_cmd.clear();
cmd_list.clear();
last_bank_state.clear();
bank_state.clear();
}
// Reads through the trace file, identifies the timestamp, command and bank
// If the issued command includes an auto-precharge, adds an explicit
// precharge to a cached command list and computes the precharge offset from the
// issued command timestamp, when the auto-precharge would kick in
void CommandAnalysis::getCommands(std::vector<MemCommand>& list, bool lastupdate, int64_t timestamp)
{
if (!next_window_cmd_list.empty()) {
list.insert(list.begin(), next_window_cmd_list.begin(), next_window_cmd_list.end());
next_window_cmd_list.clear();
}
for (size_t i = 0; i < list.size(); ++i) {
MemCommand& cmd = list[i];
MemCommand::cmds cmdType = cmd.getType();
if (cmdType == MemCommand::ACT) {
activation_cycle[cmd.getBank()] = cmd.getTimeInt64();
} else if (cmdType == MemCommand::RDA || cmdType == MemCommand::WRA) {
// Remove auto-precharge flag from command
cmd.setType(cmd.typeWithoutAutoPrechargeFlag());
// Add the auto precharge to the list of cached_cmds
int64_t preTime = max(cmd.getTimeInt64() + cmd.getPrechargeOffset(memSpec, cmdType),
activation_cycle[cmd.getBank()] + memSpec.memTimingSpec.RAS);
list.push_back(MemCommand(MemCommand::PRE, cmd.getBank(), preTime));
}
if (!lastupdate && timestamp > 0) {
if(cmd.getTimeInt64() > timestamp)
{
MemCommand nextWindowCmd = list[i];
next_window_cmd_list.push_back(nextWindowCmd);
list.erase(find(list.begin(), list.end(), cmd));
}
}
}
sort(list.begin(), list.end(), commandSorter);
if (lastupdate && list.empty() == false) {
// Add cycles at the end of the list
int64_t t = timeToCompletion(list.back().getType()) + list.back().getTimeInt64() - 1;
list.push_back(MemCommand(MemCommand::NOP, 0, t));
}
evaluateCommands(list);
} // CommandAnalysis::getCommands
// Used to analyse a given list of commands and identify command timings
// and memory state transitions
void CommandAnalysis::evaluateCommands(vector<MemCommand>& cmd_list)
{
// for each command identify timestamp, type and bank
for (auto cmd : cmd_list) {
// For command type
int type = cmd.getType();
// For command bank
unsigned bank = cmd.getBank();
// Command Issue timestamp in clock cycles (cc)
int64_t timestamp = cmd.getTimeInt64();
if (type == MemCommand::ACT) {
handleAct(bank, timestamp);
} else if (type == MemCommand::RD) {
handleRd(bank, timestamp);
} else if (type == MemCommand::WR) {
handleWr(bank, timestamp);
} else if (type == MemCommand::REF) {
handleRef(bank, timestamp);
} else if (type == MemCommand::REFB) {
handleRefB(bank, timestamp);
} else if (type == MemCommand::PRE) {
handlePre(bank, timestamp);
} else if (type == MemCommand::PREA) {
handlePreA(bank, timestamp);
} else if (type == MemCommand::PDN_F_ACT) {
handlePdnFAct(bank, timestamp);
} else if (type == MemCommand::PDN_S_ACT) {
handlePdnSAct(bank, timestamp);
} else if (type == MemCommand::PDN_F_PRE) {
handlePdnFPre(bank, timestamp);
} else if (type == MemCommand::PDN_S_PRE) {
handlePdnSPre(bank, timestamp);
} else if (type == MemCommand::PUP_ACT) {
handlePupAct(timestamp);
} else if (type == MemCommand::PUP_PRE) {
handlePupPre(timestamp);
} else if (type == MemCommand::SREN) {
handleSREn(bank, timestamp);
} else if (type == MemCommand::SREX) {
handleSREx(bank, timestamp);
} else if (type == MemCommand::END || type == MemCommand::NOP) {
handleNopEnd(timestamp);
} else {
printWarning("Unknown command given, exiting.", type, timestamp, bank);
exit(-1);
}
}
} // CommandAnalysis::evaluateCommands
// To update idle period information whenever active cycles may be idle
void CommandAnalysis::idle_act_update(int64_t latest_read_cycle, int64_t latest_write_cycle,
int64_t latest_act_cycle, int64_t timestamp)
{
if (latest_read_cycle >= 0) {
end_read_op = latest_read_cycle + timeToCompletion(MemCommand::RD) - 1;
}
if (latest_write_cycle >= 0) {
end_write_op = latest_write_cycle + timeToCompletion(MemCommand::WR) - 1;
}
if (latest_act_cycle >= 0) {
end_act_op = latest_act_cycle + timeToCompletion(MemCommand::ACT) - 1;
}
idlecycles_act += max(zero, timestamp - max(max(end_read_op, end_write_op),
end_act_op));
} // CommandAnalysis::idle_act_update
// To update idle period information whenever precharged cycles may be idle
void CommandAnalysis::idle_pre_update(int64_t timestamp, int64_t latest_pre_cycle)
{
if (latest_pre_cycle > 0) {
idlecycles_pre += max(zero, timestamp - latest_pre_cycle -
memSpec.memTimingSpec.RP);
} else if (latest_pre_cycle == 0) {
idlecycles_pre += max(zero, timestamp - latest_pre_cycle);
}
}