1/*
2 * Copyright (c) 2012-2014, TU Delft
3 * Copyright (c) 2012-2014, TU Eindhoven
4 * Copyright (c) 2012-2014, TU Kaiserslautern
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * Authors: Karthik Chandrasekar,
35 *          Matthias Jung,
36 *          Omar Naji,
37 *          Sven Goossens,
38 *          Éder F. Zulian
39 *          Subash Kannoth
40 *          Felipe S. Prado
41 *
42 */
43
44#include <fstream>
45#include <algorithm>
46#include <sstream>
47
48#include "CommandAnalysis.h"
49#include "CmdScheduler.h"
50
51using namespace Data;
52using namespace std;
53
54bool commandSorter(const MemCommand& i, const MemCommand& j)
55{
56  if (i.getTimeInt64() == j.getTimeInt64()) {
57    return i.getType() == MemCommand::PRE && j.getType() != MemCommand::PRE;
58  } else {
59    return i.getTimeInt64() < j.getTimeInt64();
60  }
61}
62
63CommandAnalysis::CommandAnalysis(const Data::MemorySpecification& memSpec) :
64  memSpec(memSpec)
65
66{
67  auto &nBanks = memSpec.memArchSpec.nbrOfBanks;
68  // Initializing all counters and variables
69  numberofactsBanks.assign(static_cast<size_t>(nBanks), 0);
70  numberofpresBanks.assign(static_cast<size_t>(nBanks), 0);
71  numberofreadsBanks.assign(static_cast<size_t>(nBanks), 0);
72  numberofwritesBanks.assign(static_cast<size_t>(nBanks), 0);
73  actcyclesBanks.assign(static_cast<size_t>(nBanks), 0);
74  numberofrefbBanks.assign(static_cast<size_t>(nBanks), 0);
75
76  first_act_cycle_banks.resize(static_cast<size_t>(nBanks), 0);
77
78  clearStats(0);
79  zero = 0;
80
81  bank_state.resize(static_cast<size_t>(nBanks), BANK_PRECHARGED);
82  last_bank_state.resize(static_cast<size_t>(nBanks), BANK_PRECHARGED);
83  mem_state  = MS_NOT_IN_PD;
84
85  cmd_list.clear();
86  cached_cmd.clear();
87  activation_cycle.resize(static_cast<size_t>(nBanks), 0);
88  num_banks = nBanks;
89}
90
91// function to clear counters
92void CommandAnalysis::clearStats(const int64_t timestamp)
93{
94  std::fill(numberofactsBanks.begin(), numberofactsBanks.end(), 0);
95  std::fill(numberofpresBanks.begin(), numberofpresBanks.end(), 0);
96  std::fill(numberofreadsBanks.begin(), numberofreadsBanks.end(), 0);
97  std::fill(numberofwritesBanks.begin(), numberofwritesBanks.end(), 0);
98  std::fill(actcyclesBanks.begin(), actcyclesBanks.end(), 0);
99
100  numberofrefs        = 0;
101  f_act_pdns          = 0;
102  s_act_pdns          = 0;
103  f_pre_pdns          = 0;
104  s_pre_pdns          = 0;
105  numberofsrefs       = 0;
106
107  actcycles           = 0;
108  precycles           = 0;
109  f_act_pdcycles      = 0;
110  s_act_pdcycles      = 0;
111  f_pre_pdcycles      = 0;
112  s_pre_pdcycles      = 0;
113  pup_act_cycles      = 0;
114  pup_pre_cycles      = 0;
115  sref_cycles         = 0;
116  spup_cycles         = 0;
117  sref_ref_act_cycles = 0;
118  sref_ref_pre_cycles = 0;
119  spup_ref_act_cycles = 0;
120  spup_ref_pre_cycles = 0;
121  idlecycles_act      = 0;
122  idlecycles_pre      = 0;
123
124  // reset count references to timestamp so that they are moved
125  // to start of next stats generation
126  std::fill(first_act_cycle_banks.begin(), first_act_cycle_banks.end(), timestamp);
127  first_act_cycle     = timestamp;
128
129  pdn_cycle           = timestamp;
130  sref_cycle_window   = timestamp;
131
132  end_act_op          = timestamp;
133  end_read_op         = timestamp;
134  end_write_op        = timestamp;
135
136  latest_read_cycle   = -1;
137  latest_write_cycle  = -1;
138
139  if (timestamp == 0) {
140    latest_pre_cycle = -1;
141    latest_act_cycle = -1;
142    sref_cycle = 0;
143    last_pre_cycle = 0;
144    sref_ref_act_cycles_window = 0;
145    sref_ref_pre_cycles_window = 0;
146  } else {
147    last_pre_cycle = max(timestamp,last_pre_cycle);
148
149    latest_pre_cycle = max(timestamp, latest_pre_cycle);
150
151    if (latest_act_cycle < timestamp)
152        latest_act_cycle = -1;
153  }
154}
155
156// function to clear all arrays
157void CommandAnalysis::clear()
158{
159  cached_cmd.clear();
160  cmd_list.clear();
161  last_bank_state.clear();
162  bank_state.clear();
163}
164
165// Reads through the trace file, identifies the timestamp, command and bank
166// If the issued command includes an auto-precharge, adds an explicit
167// precharge to a cached command list and computes the precharge offset from the
168// issued command timestamp, when the auto-precharge would kick in
169
170void CommandAnalysis::getCommands(std::vector<MemCommand>& list, bool lastupdate, int64_t timestamp)
171{
172  if (!next_window_cmd_list.empty()) {
173    list.insert(list.begin(), next_window_cmd_list.begin(), next_window_cmd_list.end());
174    next_window_cmd_list.clear();
175  }
176  for (size_t i = 0; i < list.size(); ++i) {
177    MemCommand& cmd = list[i];
178    MemCommand::cmds cmdType = cmd.getType();
179    if (cmdType == MemCommand::ACT) {
180      activation_cycle[cmd.getBank()] = cmd.getTimeInt64();
181    } else if (cmdType == MemCommand::RDA || cmdType == MemCommand::WRA) {
182      // Remove auto-precharge flag from command
183      cmd.setType(cmd.typeWithoutAutoPrechargeFlag());
184
185      // Add the auto precharge to the list of cached_cmds
186      int64_t preTime = max(cmd.getTimeInt64() + cmd.getPrechargeOffset(memSpec, cmdType),
187                           activation_cycle[cmd.getBank()] + memSpec.memTimingSpec.RAS);
188      list.push_back(MemCommand(MemCommand::PRE, cmd.getBank(), preTime));
189    }
190
191    if (!lastupdate && timestamp > 0) {
192      if(cmd.getTimeInt64() > timestamp)
193      {
194          MemCommand nextWindowCmd = list[i];
195          next_window_cmd_list.push_back(nextWindowCmd);
196          list.erase(find(list.begin(), list.end(), cmd));
197      }
198    }
199  }
200  sort(list.begin(), list.end(), commandSorter);
201
202  if (lastupdate && list.empty() == false) {
203    // Add cycles at the end of the list
204    int64_t t = timeToCompletion(list.back().getType()) + list.back().getTimeInt64() - 1;
205    list.push_back(MemCommand(MemCommand::NOP, 0, t));
206  }
207
208  evaluateCommands(list);
209} // CommandAnalysis::getCommands
210
211
212// Used to analyse a given list of commands and identify command timings
213// and memory state transitions
214void CommandAnalysis::evaluateCommands(vector<MemCommand>& cmd_list)
215{
216  // for each command identify timestamp, type and bank
217  for (auto cmd : cmd_list) {
218    // For command type
219    int type = cmd.getType();
220    // For command bank
221    unsigned bank = cmd.getBank();
222    // Command Issue timestamp in clock cycles (cc)
223    int64_t timestamp = cmd.getTimeInt64();
224
225    if (type == MemCommand::ACT) {
226      handleAct(bank, timestamp);
227    } else if (type == MemCommand::RD) {
228      handleRd(bank, timestamp);
229    } else if (type == MemCommand::WR) {
230      handleWr(bank, timestamp);
231    } else if (type == MemCommand::REF) {
232      handleRef(bank, timestamp);
233    } else if (type == MemCommand::REFB) {
234      handleRefB(bank, timestamp);
235    } else if (type == MemCommand::PRE) {
236      handlePre(bank, timestamp);
237    } else if (type == MemCommand::PREA) {
238      handlePreA(bank, timestamp);
239    } else if (type == MemCommand::PDN_F_ACT) {
240      handlePdnFAct(bank, timestamp);
241    } else if (type == MemCommand::PDN_S_ACT) {
242      handlePdnSAct(bank, timestamp);
243    } else if (type == MemCommand::PDN_F_PRE) {
244      handlePdnFPre(bank, timestamp);
245    } else if (type == MemCommand::PDN_S_PRE) {
246      handlePdnSPre(bank, timestamp);
247    } else if (type == MemCommand::PUP_ACT) {
248      handlePupAct(timestamp);
249    } else if (type == MemCommand::PUP_PRE) {
250      handlePupPre(timestamp);
251    } else if (type == MemCommand::SREN) {
252      handleSREn(bank, timestamp);
253    } else if (type == MemCommand::SREX) {
254      handleSREx(bank, timestamp);
255    } else if (type == MemCommand::END || type == MemCommand::NOP) {
256      handleNopEnd(timestamp);
257    } else {
258      printWarning("Unknown command given, exiting.", type, timestamp, bank);
259      exit(-1);
260    }
261  }
262} // CommandAnalysis::evaluateCommands
263
264// To update idle period information whenever active cycles may be idle
265void CommandAnalysis::idle_act_update(int64_t latest_read_cycle, int64_t latest_write_cycle,
266                                      int64_t latest_act_cycle, int64_t timestamp)
267{
268  if (latest_read_cycle >= 0) {
269    end_read_op = latest_read_cycle + timeToCompletion(MemCommand::RD) - 1;
270  }
271
272  if (latest_write_cycle >= 0) {
273    end_write_op = latest_write_cycle + timeToCompletion(MemCommand::WR) - 1;
274  }
275
276  if (latest_act_cycle >= 0) {
277    end_act_op = latest_act_cycle + timeToCompletion(MemCommand::ACT) - 1;
278  }
279
280  idlecycles_act += max(zero, timestamp - max(max(end_read_op, end_write_op),
281                                              end_act_op));
282} // CommandAnalysis::idle_act_update
283
284// To update idle period information whenever precharged cycles may be idle
285void CommandAnalysis::idle_pre_update(int64_t timestamp, int64_t latest_pre_cycle)
286{
287  if (latest_pre_cycle > 0) {
288    idlecycles_pre += max(zero, timestamp - latest_pre_cycle -
289                          memSpec.memTimingSpec.RP);
290  } else if (latest_pre_cycle == 0) {
291    idlecycles_pre += max(zero, timestamp - latest_pre_cycle);
292  }
293}
294
295