<commit_before>using namespace std;

#include "core.h"
#include "iocoom_core_model.h"

#include "log.h"
#include "dynamic_instruction_info.h"
#include "config.hpp"
#include "simulator.h"
#include "branch_predictor.h"

IOCOOMCoreModel::IOCOOMCoreModel(Core *core, float frequency)
   : CoreModel(core, frequency)
   , m_instruction_count(0)
   , m_total_memory_stall_cycles(0)
   , m_register_scoreboard(512)
   , m_register_wait_unit_list(512)
   , m_store_buffer(0)
   , m_load_unit(0)
{
   config::Config *cfg = Sim()->getCfg();

   try
   {
      m_store_buffer = new StoreBuffer(cfg->getInt("perf_model/core/iocoom/num_store_buffer_entries",1));
      m_load_unit = new LoadUnit(cfg->getInt("perf_model/core/iocoom/num_outstanding_loads",3));
   }
   catch (...)
   {
      LOG_PRINT_ERROR("Config info not available.");
   }

   initializeRegisterScoreboard();
   initializeRegisterWaitUnitList();
   
   // For Power and AreaModeling
   m_mcpat_core_interface = new McPATCoreInterface(
                            cfg->getInt("perf_model/core/iocoom/num_outstanding_loads", 3),
                            cfg->getInt("perf_model/core/iocoom/num_store_buffer_entries", 1));
}

IOCOOMCoreModel::~IOCOOMCoreModel()
{
   delete m_mcpat_core_interface;
   delete m_load_unit;
   delete m_store_buffer;
}

void IOCOOMCoreModel::outputSummary(std::ostream &os)
{
   os << "Core Performance Model Summary:" << endl;
   os << "  Instructions: " << m_instruction_count << endl;
   CoreModel::outputSummary(os);
   os << "  Memory Stall Cycles: " << m_total_memory_stall_cycles << endl;
}

void IOCOOMCoreModel::handleInstruction(Instruction *instruction)
{
   // Execute this first so that instructions have the opportunity to
   // abort further processing (via AbortInstructionException)
   UInt64 cost = instruction->getCost();

   // icache modeling
   modelIcache(instruction->getAddress());

   /* 
      model instruction in the following steps:
      - find when read operations are available
      - find latency of instruction
      - update write operands
   */
   const OperandList &ops = instruction->getOperands();

   // buffer write operands to be updated after instruction executes
   DynamicInstructionInfoQueue write_info;

   // Time when register operands are ready
   UInt64 read_register_operands_ready = m_cycle_count;
   CoreUnit register_wait_unit = INVALID_UNIT;
   // REG read operands
   for (unsigned int i = 0; i < ops.size(); i++)
   {
      const Operand &o = ops[i];

      if ( (o.m_direction != Operand::READ) || (o.m_type != Operand::REG) )
         continue;

      LOG_ASSERT_ERROR(o.m_value < m_register_scoreboard.size(),
                       "Register value out of range: %llu", o.m_value);

      // Check which register takes the longest to get ready
      // If that register is waiting on a memory read, count as memory stall cycles
      // Else, do not count as memory stall cycles
      if (read_register_operands_ready < m_register_scoreboard[o.m_value])
      {
         if (m_register_wait_unit_list[o.m_value] == LOAD_UNIT)
            register_wait_unit = LOAD_UNIT;
         else if (m_register_wait_unit_list[o.m_value] == EXECUTION_UNIT)
            register_wait_unit = EXECUTION_UNIT;
         else
            LOG_PRINT_ERROR("Unrecognized Core Unit(%u)", m_register_wait_unit_list[o.m_value]);

         read_register_operands_ready = m_register_scoreboard[o.m_value];
      }
   }
   // Update total memory stall cycles
   if (register_wait_unit == LOAD_UNIT)
      m_total_memory_stall_cycles += (read_register_operands_ready - m_cycle_count);

   // Assume memory is read only after all registers are read
   // This may be required since some registers may be used as the address for memory operations
   // Time when load unit and memory operands are ready
   UInt64 load_unit_ready = read_register_operands_ready;
   UInt64 read_memory_operands_ready = read_register_operands_ready;
   // MEMORY read & write operands
   for (unsigned int i = 0; i < ops.size(); i++)
   {
      const Operand &o = ops[i];

      if (o.m_type != Operand::MEMORY)
         continue;
         
      DynamicInstructionInfo &info = getDynamicInstructionInfo();

      if (o.m_direction == Operand::READ)
      {
         LOG_ASSERT_ERROR(info.type == DynamicInstructionInfo::MEMORY_READ,
                          "Expected memory read info, got: %d.", info.type);

         pair<UInt64,UInt64> load_timing_info = executeLoad(read_register_operands_ready, info);
         UInt64 load_ready = load_timing_info.first;
         UInt64 load_latency = load_timing_info.second;
         UInt64 load_completion_time = load_ready + load_latency;

         // This 'ready' is related to a structural hazard in the LOAD Unit
         if (load_unit_ready < load_ready)
            load_unit_ready = load_ready;
         
         // Read memory completion time is when all the read operands are available and ready for execution unit<commit_msg>[core][iocoom] Subtracted out the register time waiting on execution unit<commit_after>using namespace std;

#include "core.h"
#include "iocoom_core_model.h"

#include "log.h"
#include "dynamic_instruction_info.h"
#include "config.hpp"
#include "simulator.h"
#include "branch_predictor.h"

IOCOOMCoreModel::IOCOOMCoreModel(Core *core, float frequency)
   : CoreModel(core, frequency)
   , m_instruction_count(0)
   , m_total_memory_stall_cycles(0)
   , m_register_scoreboard(512)
   , m_register_wait_unit_list(512)
   , m_store_buffer(0)
   , m_load_unit(0)
{
   config::Config *cfg = Sim()->getCfg();

   try
   {
      m_store_buffer = new StoreBuffer(cfg->getInt("perf_model/core/iocoom/num_store_buffer_entries",1));
      m_load_unit = new LoadUnit(cfg->getInt("perf_model/core/iocoom/num_outstanding_loads",3));
   }
   catch (...)
   {
      LOG_PRINT_ERROR("Config info not available.");
   }

   initializeRegisterScoreboard();
   initializeRegisterWaitUnitList();
   
   // For Power and AreaModeling
   m_mcpat_core_interface = new McPATCoreInterface(
                            cfg->getInt("perf_model/core/iocoom/num_outstanding_loads", 3),
                            cfg->getInt("perf_model/core/iocoom/num_store_buffer_entries", 1));
}

IOCOOMCoreModel::~IOCOOMCoreModel()
{
   delete m_mcpat_core_interface;
   delete m_load_unit;
   delete m_store_buffer;
}

void IOCOOMCoreModel::outputSummary(std::ostream &os)
{
   os << "Core Performance Model Summary:" << endl;
   os << "  Instructions: " << m_instruction_count << endl;
   CoreModel::outputSummary(os);
   os << "  Memory Stall Cycles: " << m_total_memory_stall_cycles << endl;
}

void IOCOOMCoreModel::handleInstruction(Instruction *instruction)
{
   // Execute this first so that instructions have the opportunity to
   // abort further processing (via AbortInstructionException)
   UInt64 cost = instruction->getCost();

   // icache modeling
   modelIcache(instruction->getAddress());

   /* 
      model instruction in the following steps:
      - find when read operations are available
      - find latency of instruction
      - update write operands
   */
   const OperandList &ops = instruction->getOperands();

   // buffer write operands to be updated after instruction executes
   DynamicInstructionInfoQueue write_info;

   // Time when register operands are ready (waiting for either the load unit or the execution unit)
   UInt64 read_register_operands_ready_load_unit_wait = m_cycle_count;
   UInt64 read_register_operands_ready_execution_unit_wait = m_cycle_count;

   // REG read operands
   for (unsigned int i = 0; i < ops.size(); i++)
   {
      const Operand &o = ops[i];

      if ( (o.m_direction != Operand::READ) || (o.m_type != Operand::REG) )
         continue;

      LOG_ASSERT_ERROR(o.m_value < m_register_scoreboard.size(),
                       "Register value out of range: %llu", o.m_value);

      // Compute the ready time for registers that are waiting on the LOAD_UNIT
      // and on the EXECUTION_UNIT
      // The final ready time is the max of this
      if (m_register_wait_unit_list[o.m_value] == LOAD_UNIT)
      {
         if (read_register_operands_ready_load_unit_wait < m_register_scoreboard[o.m_value])
            read_register_operands_ready_load_unit_wait = m_register_scoreboard[o.m_value];
      }
      else if (m_register_wait_unit_list[o.m_value] == EXECUTION_UNIT)
      {
         if (read_register_operands_ready_execution_unit_wait < m_register_scoreboard[o.m_value])
            read_register_operands_ready_execution_unit_wait = m_register_scoreboard[o.m_value];
      }
      else
      {
         LOG_ASSERT_ERROR(m_register_scoreboard[o.m_value] <= m_cycle_count,
                          "Unrecognized Core Unit(%u)", m_register_wait_unit_list[o.m_value]);
      }
   }
   
   // The read register ready time is the max of this
   UInt64 read_register_operands_ready = max<UInt64>(read_register_operands_ready_load_unit_wait,
                                                     read_register_operands_ready_execution_unit_wait);
   
   // Update total memory stall cycles - Subtract out the stall cycles for the execution unit
   m_total_memory_stall_cycles += (read_register_operands_ready - read_register_operands_ready_execution_unit_wait);

   // Assume memory is read only after all registers are read
   // This may be required since some registers may be used as the address for memory operations
   // Time when load unit and memory operands are ready
   UInt64 load_unit_ready = read_register_operands_ready;
   UInt64 read_memory_operands_ready = read_register_operands_ready;
   // MEMORY read & write operands
   for (unsigned int i = 0; i < ops.size(); i++)
   {
      const Operand &o = ops[i];

      if (o.m_type != Operand::MEMORY)
         continue;
         
      DynamicInstructionInfo &info = getDynamicInstructionInfo();

      if (o.m_direction == Operand::READ)
      {
         LOG_ASSERT_ERROR(info.type == DynamicInstructionInfo::MEMORY_READ,
                          "Expected memory read info, got: %d.", info.type);

         pair<UInt64,UInt64> load_timing_info = executeLoad(read_register_operands_ready, info);
         UInt64 load_ready = load_timing_info.first;
         UInt64 load_latency = load_timing_info.second;
         UInt64 load_completion_time = load_ready + load_latency;

         // This 'ready' is related to a structural hazard in the LOAD Unit
         if (load_unit_ready < load_ready)
            load_unit_ready = load_ready;
         
         // Read memory completion time is when all the read operands are available and ready for execution unit
{'fraction_non_alphanumeric': 0.08999435772051909, 'fraction_numerical': 0.006958811359789355, 'mean_word_length': 3.2438148443735035, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '242940', 'n_tokens_mistral': 3322, 'n_tokens_neox': 3232, 'n_words': 777}