summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVijay Kandiah <[email protected]>2021-10-17 02:07:39 -0500
committerGitHub <[email protected]>2021-10-17 02:07:39 -0500
commit4a4fc87a2dcd95bfe298f2b3d18a9833a506e499 (patch)
treef45fe00a86fb814ebf3f5e711674f233dcdb73a2 /src
parent90ec3399763d7c8512cfe7dc193473086c38ca38 (diff)
parent84c4f46fb78b529ab2447d7a676f5b3ac2d9c05f (diff)
Merge pull request #5 from accel-sim/dev
GPGPU-Sim Latest Dev Integration
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.cc16
-rw-r--r--src/abstract_hardware_model.h71
-rw-r--r--src/cuda-sim/instructions.cc99
-rw-r--r--src/cuda-sim/ptx_ir.cc4
-rw-r--r--src/cuda-sim/ptx_ir.h4
-rw-r--r--src/cuda-sim/ptx_parser.cc14
-rw-r--r--src/gpgpu-sim/gpu-cache.cc223
-rw-r--r--src/gpgpu-sim/gpu-cache.h203
-rw-r--r--src/gpgpu-sim/gpu-sim.cc11
-rw-r--r--src/gpgpu-sim/l2cache.cc131
-rw-r--r--src/gpgpu-sim/l2cache.h7
-rw-r--r--src/gpgpu-sim/shader.cc362
-rw-r--r--src/gpgpu-sim/shader.h138
13 files changed, 917 insertions, 366 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index 5ad6f10..30aee60 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -205,8 +205,8 @@ gpgpu_t::gpgpu_t(const gpgpu_functional_sim_config &config, gpgpu_context *ctx)
gpu_tot_sim_cycle = 0;
}
-address_type line_size_based_tag_func(new_addr_type address,
- new_addr_type line_size) {
+new_addr_type line_size_based_tag_func(new_addr_type address,
+ new_addr_type line_size) {
// gives the tag for an address based on a given line size
return address & ~(line_size - 1);
}
@@ -448,7 +448,8 @@ void warp_inst_t::generate_mem_accesses() {
for (unsigned thread = 0; thread < m_config->warp_size; thread++) {
if (!active(thread)) continue;
new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[0];
- unsigned block_address = line_size_based_tag_func(addr, cache_block_size);
+ new_addr_type block_address =
+ line_size_based_tag_func(addr, cache_block_size);
accesses[block_address].set(thread);
unsigned idx = addr - block_address;
for (unsigned i = 0; i < data_size; i++) byte_mask.set(idx + i);
@@ -530,7 +531,8 @@ void warp_inst_t::memory_coalescing_arch(bool is_write,
(m_per_scalar_thread[thread].memreqaddr[access] != 0);
access++) {
new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[access];
- unsigned block_address = line_size_based_tag_func(addr, segment_size);
+ new_addr_type block_address =
+ line_size_based_tag_func(addr, segment_size);
unsigned chunk =
(addr & 127) / 32; // which 32-byte chunk within in a 128-byte
// chunk does this thread access?
@@ -552,7 +554,8 @@ void warp_inst_t::memory_coalescing_arch(bool is_write,
if (block_address != line_size_based_tag_func(
addr + data_size_coales - 1, segment_size)) {
addr = addr + data_size_coales - 1;
- unsigned block_address = line_size_based_tag_func(addr, segment_size);
+ new_addr_type block_address =
+ line_size_based_tag_func(addr, segment_size);
unsigned chunk = (addr & 127) / 32;
transaction_info &info = subwarp_transactions[block_address];
info.chunks.set(chunk);
@@ -625,7 +628,8 @@ void warp_inst_t::memory_coalescing_arch_atomic(bool is_write,
if (!active(thread)) continue;
new_addr_type addr = m_per_scalar_thread[thread].memreqaddr[0];
- unsigned block_address = line_size_based_tag_func(addr, segment_size);
+ new_addr_type block_address =
+ line_size_based_tag_func(addr, segment_size);
unsigned chunk =
(addr & 127) / 32; // which 32-byte chunk within in a 128-byte chunk
// does this thread access?
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 49f3e9f..35e28ca 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -65,7 +65,7 @@ enum FuncCache {
FuncCachePreferL1 = 2
};
-enum AdaptiveCache { FIXED = 0, ADAPTIVE_VOLTA = 1 };
+enum AdaptiveCache { FIXED = 0, ADAPTIVE_CACHE = 1 };
#ifdef __cplusplus
@@ -75,8 +75,8 @@ enum AdaptiveCache { FIXED = 0, ADAPTIVE_VOLTA = 1 };
typedef unsigned long long new_addr_type;
typedef unsigned long long cudaTextureObject_t;
-typedef unsigned address_type;
-typedef unsigned addr_t;
+typedef unsigned long long address_type;
+typedef unsigned long long addr_t;
// the following are operations the timing model can see
#define SPECIALIZED_UNIT_NUM 8
@@ -373,6 +373,8 @@ class core_config {
}
unsigned mem_warp_parts;
mutable unsigned gpgpu_shmem_size;
+ char *gpgpu_shmem_option;
+ std::vector<unsigned> shmem_opt_list;
unsigned gpgpu_shmem_sizeDefault;
unsigned gpgpu_shmem_sizePrefL1;
unsigned gpgpu_shmem_sizePrefShared;
@@ -869,6 +871,13 @@ class mem_fetch_allocator {
virtual mem_fetch *alloc(const class warp_inst_t &inst,
const mem_access_t &access,
unsigned long long cycle) const = 0;
+ virtual mem_fetch *alloc(new_addr_type addr, mem_access_type type,
+ const active_mask_t &active_mask,
+ const mem_access_byte_mask_t &byte_mask,
+ const mem_access_sector_mask_t &sector_mask,
+ unsigned size, bool wr, unsigned long long cycle,
+ unsigned wid, unsigned sid, unsigned tpc,
+ mem_fetch *original_mf) const = 0;
};
// the maximum number of destination, source, or address uarch operands in a
@@ -1291,6 +1300,7 @@ class register_set {
}
m_name = name;
}
+ const char *get_name() { return m_name; }
bool has_free() {
for (unsigned i = 0; i < regs.size(); i++) {
if (regs[i]->empty()) {
@@ -1315,7 +1325,35 @@ class register_set {
}
return false;
}
+ bool has_ready(bool sub_core_model, unsigned reg_id) {
+ if (!sub_core_model) return has_ready();
+ assert(reg_id < regs.size());
+ return (not regs[reg_id]->empty());
+ }
+ unsigned get_ready_reg_id() {
+ // for sub core model we need to figure which reg_id has the ready warp
+ // this function should only be called if has_ready() was true
+ assert(has_ready());
+ warp_inst_t **ready;
+ ready = NULL;
+ unsigned reg_id;
+ for (unsigned i = 0; i < regs.size(); i++) {
+ if (not regs[i]->empty()) {
+ if (ready and (*ready)->get_uid() < regs[i]->get_uid()) {
+ // ready is oldest
+ } else {
+ ready = &regs[i];
+ reg_id = i;
+ }
+ }
+ }
+ return reg_id;
+ }
+ unsigned get_schd_id(unsigned reg_id) {
+ assert(not regs[reg_id]->empty());
+ return regs[reg_id]->get_schd_id();
+ }
void move_in(warp_inst_t *&src) {
warp_inst_t **free = get_free();
move_warp(*free, src);
@@ -1323,10 +1361,29 @@ class register_set {
// void copy_in( warp_inst_t* src ){
// src->copy_contents_to(*get_free());
//}
+ void move_in(bool sub_core_model, unsigned reg_id, warp_inst_t *&src) {
+ warp_inst_t **free;
+ if (!sub_core_model) {
+ free = get_free();
+ } else {
+ assert(reg_id < regs.size());
+ free = get_free(sub_core_model, reg_id);
+ }
+ move_warp(*free, src);
+ }
+
void move_out_to(warp_inst_t *&dest) {
warp_inst_t **ready = get_ready();
move_warp(dest, *ready);
}
+ void move_out_to(bool sub_core_model, unsigned reg_id, warp_inst_t *&dest) {
+ if (!sub_core_model) {
+ return move_out_to(dest);
+ }
+ warp_inst_t **ready = get_ready(sub_core_model, reg_id);
+ assert(ready != NULL);
+ move_warp(dest, *ready);
+ }
warp_inst_t **get_ready() {
warp_inst_t **ready;
@@ -1342,6 +1399,14 @@ class register_set {
}
return ready;
}
+ warp_inst_t **get_ready(bool sub_core_model, unsigned reg_id) {
+ if (!sub_core_model) return get_ready();
+ warp_inst_t **ready;
+ ready = NULL;
+ assert(reg_id < regs.size());
+ if (not regs[reg_id]->empty()) ready = &regs[reg_id];
+ return ready;
+ }
void print(FILE *fp) const {
fprintf(fp, "%s : @%p\n", m_name, this);
diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc
index 8936fa8..0b990e8 100644
--- a/src/cuda-sim/instructions.cc
+++ b/src/cuda-sim/instructions.cc
@@ -166,8 +166,9 @@ void inst_not_implemented(const ptx_instruction *pI);
ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo,
operand_info dstInfo, unsigned type,
ptx_thread_info *thread);
-
-void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, int op_code);
+
+void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread,
+ int op_code);
void sign_extend(ptx_reg_t &data, unsigned src_size, const operand_info &dst);
@@ -1711,40 +1712,50 @@ void bfi_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
}
thread->set_operand_value(dst, data, i_type, thread, pI);
}
-void bfind_impl(const ptx_instruction *pI, ptx_thread_info *thread)
-{
- const operand_info &dst = pI->dst();
+void bfind_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
+ const operand_info &dst = pI->dst();
const operand_info &src1 = pI->src1();
const unsigned i_type = pI->get_type();
- const ptx_reg_t src1_data = thread->get_operand_value(src1, dst, i_type, thread, 1);
- const int msb = ( i_type == U32_TYPE || i_type == S32_TYPE) ? 31 : 63;
+ const ptx_reg_t src1_data =
+ thread->get_operand_value(src1, dst, i_type, thread, 1);
+ const int msb = (i_type == U32_TYPE || i_type == S32_TYPE) ? 31 : 63;
unsigned long a = 0;
- switch (i_type)
- {
- case S32_TYPE: a = src1_data.s32; break;
- case U32_TYPE: a = src1_data.u32; break;
- case S64_TYPE: a = src1_data.s64; break;
- case U64_TYPE: a = src1_data.u64; break;
- default: assert(false); abort();
+ switch (i_type) {
+ case S32_TYPE:
+ a = src1_data.s32;
+ break;
+ case U32_TYPE:
+ a = src1_data.u32;
+ break;
+ case S64_TYPE:
+ a = src1_data.s64;
+ break;
+ case U64_TYPE:
+ a = src1_data.u64;
+ break;
+ default:
+ assert(false);
+ abort();
}
// negate negative signed inputs
- if ( ( i_type == S32_TYPE || i_type == S64_TYPE ) && ( a & ( 1 << msb ) ) ) {
- a = ~a;
+ if ((i_type == S32_TYPE || i_type == S64_TYPE) && (a & (1 << msb))) {
+ a = ~a;
}
uint32_t d_data = 0xffffffff;
for (uint32_t i = msb; i >= 0; i--) {
- if (a & (1<<i)) { d_data = i; break; }
+ if (a & (1 << i)) {
+ d_data = i;
+ break;
+ }
}
// if (.shiftamt && d != 0xffffffff) { d = msb - d; }
// store d
thread->set_operand_value(dst, d_data, U32_TYPE, thread, pI);
-
-
}
void bra_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
@@ -6339,12 +6350,10 @@ void vmad_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
#define VMAX 0
#define VMIN 1
-void vmax_impl(const ptx_instruction *pI, ptx_thread_info *thread)
-{
- video_mem_instruction(pI, thread, VMAX);
+void vmax_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
+ video_mem_instruction(pI, thread, VMAX);
}
-void vmin_impl(const ptx_instruction *pI, ptx_thread_info *thread)
-{
+void vmin_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
video_mem_instruction(pI, thread, VMIN);
}
void vset_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
@@ -6440,12 +6449,12 @@ void vote_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
}
}
-void activemask_impl( const ptx_instruction *pI, ptx_thread_info *thread )
-{
+void activemask_impl(const ptx_instruction *pI, ptx_thread_info *thread) {
active_mask_t l_activemask_bitset = pI->get_warp_active_mask();
- uint32_t l_activemask_uint = static_cast<uint32_t>(l_activemask_bitset.to_ulong());
+ uint32_t l_activemask_uint =
+ static_cast<uint32_t>(l_activemask_bitset.to_ulong());
- const operand_info &dst = pI->dst();
+ const operand_info &dst = pI->dst();
thread->set_operand_value(dst, l_activemask_uint, U32_TYPE, thread, pI);
}
@@ -6527,12 +6536,12 @@ ptx_reg_t srcOperandModifiers(ptx_reg_t opData, operand_info opInfo,
return result;
}
-void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, int op_code)
-{
- const operand_info &dst = pI->dst(); // d
- const operand_info &src1 = pI->src1(); // a
- const operand_info &src2 = pI->src2(); // b
- const operand_info &src3 = pI->src3(); // c
+void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread,
+ int op_code) {
+ const operand_info &dst = pI->dst(); // d
+ const operand_info &src1 = pI->src1(); // a
+ const operand_info &src2 = pI->src2(); // b
+ const operand_info &src3 = pI->src3(); // c
const unsigned i_type = pI->get_type();
@@ -6557,19 +6566,18 @@ void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, i
auto option = options.begin();
assert(*option == ATOMIC_MAX || *option == ATOMIC_MIN);
- switch ( i_type ) {
+ switch (i_type) {
case S32_TYPE: {
// assert all operands are S32_TYPE:
scalar_type = pI->get_scalar_type();
- for (std::list<int>::iterator scalar = scalar_type.begin(); scalar != scalar_type.end(); scalar++)
- {
+ for (std::list<int>::iterator scalar = scalar_type.begin();
+ scalar != scalar_type.end(); scalar++) {
assert(*scalar == S32_TYPE);
}
assert(scalar_type.size() == 3);
scalar_type.clear();
- switch (op_code)
- {
+ switch (op_code) {
case VMAX:
data.s32 = MY_MAX_I(ta.s32, tb.s32);
break;
@@ -6580,26 +6588,23 @@ void video_mem_instruction(const ptx_instruction *pI, ptx_thread_info *thread, i
assert(0);
}
- switch (*option)
- {
+ switch (*option) {
case ATOMIC_MAX:
data.s32 = MY_MAX_I(data.s32, c.s32);
- break;
+ break;
case ATOMIC_MIN:
data.s32 = MY_MIN_I(data.s32, c.s32);
- break;
+ break;
default:
- assert(0); // not yet implemented
+ assert(0); // not yet implemented
}
break;
-
}
default:
- assert(0); // not yet implemented
+ assert(0); // not yet implemented
}
thread->set_operand_value(dst, data, i_type, thread, pI);
return;
}
-
diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc
index e5b5fb7..d3da4b5 100644
--- a/src/cuda-sim/ptx_ir.cc
+++ b/src/cuda-sim/ptx_ir.cc
@@ -1147,8 +1147,8 @@ static std::list<operand_info> check_operands(
const std::list<operand_info> &operands, gpgpu_context *ctx) {
static int g_warn_literal_operands_two_type_inst;
if ((opcode == CVT_OP) || (opcode == SET_OP) || (opcode == SLCT_OP) ||
- (opcode == TEX_OP) || (opcode == MMA_OP) || (opcode == DP4A_OP) ||
- (opcode == VMIN_OP) || (opcode == VMAX_OP) ) {
+ (opcode == TEX_OP) || (opcode == MMA_OP) || (opcode == DP4A_OP) ||
+ (opcode == VMIN_OP) || (opcode == VMAX_OP)) {
// just make sure these do not have have const operands...
if (!g_warn_literal_operands_two_type_inst) {
std::list<operand_info>::const_iterator o;
diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h
index 4243941..8251759 100644
--- a/src/cuda-sim/ptx_ir.h
+++ b/src/cuda-sim/ptx_ir.h
@@ -966,8 +966,8 @@ class ptx_instruction : public warp_inst_t {
int get_pred_mod() const { return m_pred_mod; }
const char *get_source() const { return m_source.c_str(); }
- const std::list<int> get_scalar_type() const {return m_scalar_type;}
- const std::list<int> get_options() const {return m_options;}
+ const std::list<int> get_scalar_type() const { return m_scalar_type; }
+ const std::list<int> get_options() const { return m_options; }
typedef std::vector<operand_info>::const_iterator const_iterator;
diff --git a/src/cuda-sim/ptx_parser.cc b/src/cuda-sim/ptx_parser.cc
index afdb41b..86a33c2 100644
--- a/src/cuda-sim/ptx_parser.cc
+++ b/src/cuda-sim/ptx_parser.cc
@@ -622,13 +622,13 @@ void ptx_recognizer::add_scalar_type_spec(int type_spec) {
g_ptx_token_decode[type_spec].c_str());
g_scalar_type.push_back(type_spec);
if (g_scalar_type.size() > 1) {
- parse_assert((g_opcode == -1) || (g_opcode == CVT_OP) ||
- (g_opcode == SET_OP) || (g_opcode == SLCT_OP) ||
- (g_opcode == TEX_OP) || (g_opcode == MMA_OP) ||
- (g_opcode == DP4A_OP) || (g_opcode == VMIN_OP) ||
- (g_opcode == VMAX_OP),
- "only cvt, set, slct, tex, vmin, vmax and dp4a can have more than one "
- "type specifier.");
+ parse_assert(
+ (g_opcode == -1) || (g_opcode == CVT_OP) || (g_opcode == SET_OP) ||
+ (g_opcode == SLCT_OP) || (g_opcode == TEX_OP) ||
+ (g_opcode == MMA_OP) || (g_opcode == DP4A_OP) ||
+ (g_opcode == VMIN_OP) || (g_opcode == VMAX_OP),
+ "only cvt, set, slct, tex, vmin, vmax and dp4a can have more than one "
+ "type specifier.");
}
g_scalar_type_spec = type_spec;
}
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 75c3691..7416246 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -37,7 +37,8 @@
const char *cache_request_status_str(enum cache_request_status status) {
static const char *static_cache_request_status_str[] = {
- "HIT", "HIT_RESERVED", "MISS", "RESERVATION_FAIL", "SECTOR_MISS"};
+ "HIT", "HIT_RESERVED", "MISS", "RESERVATION_FAIL",
+ "SECTOR_MISS", "MSHR_HIT"};
assert(sizeof(static_cache_request_status_str) / sizeof(const char *) ==
NUM_CACHE_REQUEST_STATUS);
@@ -63,9 +64,9 @@ unsigned l1d_cache_config::set_bank(new_addr_type addr) const {
// For sector cache, we select one sector per bank (sector interleaving)
// This is what was found in Volta (one sector per bank, sector interleaving)
// otherwise, line interleaving
- return cache_config::hash_function(addr, l1_banks, l1_banks_byte_interleaving,
- m_l1_banks_log2,
- l1_banks_hashing_function);
+ return cache_config::hash_function(addr, l1_banks,
+ l1_banks_byte_interleaving_log2,
+ l1_banks_log2, l1_banks_hashing_function);
}
unsigned cache_config::set_index(new_addr_type addr) const {
@@ -210,6 +211,7 @@ void tag_array::init(int core_id, int type_id) {
m_core_id = core_id;
m_type_id = type_id;
is_used = false;
+ m_dirty = 0;
}
void tag_array::add_pending_line(mem_fetch *mf) {
@@ -231,15 +233,15 @@ void tag_array::remove_pending_line(mem_fetch *mf) {
}
enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
- mem_fetch *mf,
+ mem_fetch *mf, bool is_write,
bool probe_mode) const {
mem_access_sector_mask_t mask = mf->get_access_sector_mask();
- return probe(addr, idx, mask, probe_mode, mf);
+ return probe(addr, idx, mask, is_write, probe_mode, mf);
}
enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
mem_access_sector_mask_t mask,
- bool probe_mode,
+ bool is_write, bool probe_mode,
mem_fetch *mf) const {
// assert( m_config.m_write_policy == READ_ONLY );
unsigned set_index = m_config.set_index(addr);
@@ -250,7 +252,6 @@ enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
unsigned long long valid_timestamp = (unsigned)-1;
bool all_reserved = true;
-
// check for hit or pending hit
for (unsigned way = 0; way < m_config.m_assoc; way++) {
unsigned index = set_index * m_config.m_assoc + way;
@@ -263,7 +264,7 @@ enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
idx = index;
return HIT;
} else if (line->get_status(mask) == MODIFIED) {
- if (line->is_readable(mask)) {
+ if ((!is_write && line->is_readable(mask)) || is_write) {
idx = index;
return HIT;
} else {
@@ -279,20 +280,31 @@ enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
}
}
if (!line->is_reserved_line()) {
- all_reserved = false;
- if (line->is_invalid_line()) {
- invalid_line = index;
- } else {
- // valid line : keep track of most appropriate replacement candidate
- if (m_config.m_replacement_policy == LRU) {
- if (line->get_last_access_time() < valid_timestamp) {
- valid_timestamp = line->get_last_access_time();
- valid_line = index;
- }
- } else if (m_config.m_replacement_policy == FIFO) {
- if (line->get_alloc_time() < valid_timestamp) {
- valid_timestamp = line->get_alloc_time();
- valid_line = index;
+ // percentage of dirty lines in the cache
+ // number of dirty lines / total lines in the cache
+ float dirty_line_percentage =
+ ((float)m_dirty / (m_config.m_nset * m_config.m_assoc)) * 100;
+ // If the cacheline is from a load op (not modified),
+ // or the total dirty cacheline is above a specific value,
+ // Then this cacheline is eligible to be considered for replacement candidate
+ // i.e. Only evict clean cachelines until total dirty cachelines reach the limit.
+ if (!line->is_modified_line() ||
+ dirty_line_percentage >= m_config.m_wr_percent) {
+ all_reserved = false;
+ if (line->is_invalid_line()) {
+ invalid_line = index;
+ } else {
+ // valid line : keep track of most appropriate replacement candidate
+ if (m_config.m_replacement_policy == LRU) {
+ if (line->get_last_access_time() < valid_timestamp) {
+ valid_timestamp = line->get_last_access_time();
+ valid_line = index;
+ }
+ } else if (m_config.m_replacement_policy == FIFO) {
+ if (line->get_alloc_time() < valid_timestamp) {
+ valid_timestamp = line->get_alloc_time();
+ valid_line = index;
+ }
}
}
}
@@ -312,15 +324,6 @@ enum cache_request_status tag_array::probe(new_addr_type addr, unsigned &idx,
abort(); // if an unreserved block exists, it is either invalid or
// replaceable
- if (probe_mode && m_config.is_streaming()) {
- line_table::const_iterator i =
- pending_lines.find(m_config.block_addr(addr));
- assert(mf);
- if (!mf->is_write() && i != pending_lines.end()) {
- if (i->second != mf->get_inst().get_uid()) return SECTOR_MISS;
- }
- }
-
return MISS;
}
@@ -340,7 +343,7 @@ enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
m_access++;
is_used = true;
shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache
- enum cache_request_status status = probe(addr, idx, mf);
+ enum cache_request_status status = probe(addr, idx, mf, mf->is_write());
switch (status) {
case HIT_RESERVED:
m_pending_hit++;
@@ -353,8 +356,12 @@ enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
if (m_config.m_alloc_policy == ON_MISS) {
if (m_lines[idx]->is_modified_line()) {
wb = true;
+ // m_lines[idx]->set_byte_mask(mf);
evicted.set_info(m_lines[idx]->m_block_addr,
- m_lines[idx]->get_modified_size());
+ m_lines[idx]->get_modified_size(),
+ m_lines[idx]->get_dirty_byte_mask(),
+ m_lines[idx]->get_dirty_sector_mask());
+ m_dirty--;
}
m_lines[idx]->allocate(m_config.tag(addr), m_config.block_addr(addr),
time, mf->get_access_sector_mask());
@@ -365,8 +372,12 @@ enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
m_sector_miss++;
shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
if (m_config.m_alloc_policy == ON_MISS) {
+ bool before = m_lines[idx]->is_modified_line();
((sector_cache_block *)m_lines[idx])
->allocate_sector(time, mf->get_access_sector_mask());
+ if (before && !m_lines[idx]->is_modified_line()) {
+ m_dirty--;
+ }
}
break;
case RESERVATION_FAIL:
@@ -383,31 +394,45 @@ enum cache_request_status tag_array::access(new_addr_type addr, unsigned time,
return status;
}
-void tag_array::fill(new_addr_type addr, unsigned time, mem_fetch *mf) {
- fill(addr, time, mf->get_access_sector_mask());
+void tag_array::fill(new_addr_type addr, unsigned time, mem_fetch *mf,
+ bool is_write) {
+ fill(addr, time, mf->get_access_sector_mask(), mf->get_access_byte_mask(),
+ is_write);
}
void tag_array::fill(new_addr_type addr, unsigned time,
- mem_access_sector_mask_t mask) {
+ mem_access_sector_mask_t mask,
+ mem_access_byte_mask_t byte_mask, bool is_write) {
// assert( m_config.m_alloc_policy == ON_FILL );
unsigned idx;
- enum cache_request_status status = probe(addr, idx, mask);
+ enum cache_request_status status = probe(addr, idx, mask, is_write);
+ bool before = m_lines[idx]->is_modified_line();
// assert(status==MISS||status==SECTOR_MISS); // MSHR should have prevented
// redundant memory request
- if (status == MISS)
+ if (status == MISS) {
m_lines[idx]->allocate(m_config.tag(addr), m_config.block_addr(addr), time,
mask);
- else if (status == SECTOR_MISS) {
+ } else if (status == SECTOR_MISS) {
assert(m_config.m_cache_type == SECTOR);
((sector_cache_block *)m_lines[idx])->allocate_sector(time, mask);
}
-
- m_lines[idx]->fill(time, mask);
+ if (before && !m_lines[idx]->is_modified_line()) {
+ m_dirty--;
+ }
+ before = m_lines[idx]->is_modified_line();
+ m_lines[idx]->fill(time, mask, byte_mask);
+ if (m_lines[idx]->is_modified_line() && !before) {
+ m_dirty++;
+ }
}
void tag_array::fill(unsigned index, unsigned time, mem_fetch *mf) {
assert(m_config.m_alloc_policy == ON_MISS);
- m_lines[index]->fill(time, mf->get_access_sector_mask());
+ bool before = m_lines[index]->is_modified_line();
+ m_lines[index]->fill(time, mf->get_access_sector_mask(), mf->get_access_byte_mask());
+ if (m_lines[index]->is_modified_line() && !before) {
+ m_dirty++;
+ }
}
// TODO: we need write back the flushed data to the upper level
@@ -416,10 +441,12 @@ void tag_array::flush() {
for (unsigned i = 0; i < m_config.get_num_lines(); i++)
if (m_lines[i]->is_modified_line()) {
- for (unsigned j = 0; j < SECTOR_CHUNCK_SIZE; j++)
+ for (unsigned j = 0; j < SECTOR_CHUNCK_SIZE; j++) {
m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j));
+ }
}
+ m_dirty = 0;
is_used = false;
}
@@ -430,6 +457,7 @@ void tag_array::invalidate() {
for (unsigned j = 0; j < SECTOR_CHUNCK_SIZE; j++)
m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j));
+ m_dirty = 0;
is_used = false;
}
@@ -485,8 +513,10 @@ bool was_writeback_sent(const std::list<cache_event> &events,
cache_event &wb_event) {
for (std::list<cache_event>::const_iterator e = events.begin();
e != events.end(); e++) {
- if ((*e).m_cache_event_type == WRITE_BACK_REQUEST_SENT) wb_event = *e;
- return true;
+ if ((*e).m_cache_event_type == WRITE_BACK_REQUEST_SENT) {
+ wb_event = *e;
+ return true;
+ }
}
return false;
}
@@ -771,7 +801,9 @@ void cache_stats::print_stats(FILE *fout, const char *cache_name) const {
cache_request_status_str((enum cache_request_status)status),
m_stats[type][status]);
- if (status != RESERVATION_FAIL)
+ if (status != RESERVATION_FAIL && status != MSHR_HIT)
+ // MSHR_HIT is a special type of SECTOR_MISS
+ // so its already included in the SECTOR_MISS
total_access[type] += m_stats[type][status];
}
}
@@ -1057,8 +1089,7 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time) {
if (m_config.m_alloc_policy == ON_MISS)
m_tag_array->fill(e->second.m_cache_index, time, mf);
else if (m_config.m_alloc_policy == ON_FILL) {
- m_tag_array->fill(e->second.m_block_addr, time, mf);
- if (m_config.is_streaming()) m_tag_array->remove_pending_line(mf);
+ m_tag_array->fill(e->second.m_block_addr, time, mf, mf->is_write());
} else
abort();
bool has_atomic = false;
@@ -1066,9 +1097,13 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time) {
if (has_atomic) {
assert(m_config.m_alloc_policy == ON_MISS);
cache_block_t *block = m_tag_array->get_block(e->second.m_cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED,
mf->get_access_sector_mask()); // mark line as dirty for
// atomic operation
+ block->set_byte_mask(mf);
}
m_extra_mf_fields.erase(mf);
m_bandwidth_management.use_fill_port(mf);
@@ -1123,6 +1158,7 @@ void baseline_cache::send_read_request(new_addr_type addr,
m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
m_mshrs.add(mshr_addr, mf);
+ m_stats.inc_stats(mf->get_access_type(), MSHR_HIT);
do_miss = true;
} else if (!mshr_hit && mshr_avail &&
@@ -1133,9 +1169,6 @@ void baseline_cache::send_read_request(new_addr_type addr,
m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
m_mshrs.add(mshr_addr, mf);
- if (m_config.is_streaming() && m_config.m_cache_type == SECTOR) {
- m_tag_array->add_pending_line(mf);
- }
m_extra_mf_fields[mf] = extra_mf_fields(
mshr_addr, mf->get_addr(), cache_index, mf->get_data_size(), m_config);
mf->set_data_size(m_config.get_atom_sz());
@@ -1162,6 +1195,25 @@ void data_cache::send_write_request(mem_fetch *mf, cache_event request,
mf->set_status(m_miss_queue_status, time);
}
+void data_cache::update_m_readable(mem_fetch *mf, unsigned cache_index) {
+ cache_block_t *block = m_tag_array->get_block(cache_index);
+ for (unsigned i = 0; i < SECTOR_CHUNCK_SIZE; i++) {
+ if (mf->get_access_sector_mask().test(i)) {
+ bool all_set = true;
+ for (unsigned k = i * SECTOR_SIZE; k < (i + 1) * SECTOR_SIZE; k++) {
+ // If any bit in the byte mask (within the sector) is not set,
+ // the sector is unreadble
+ if (!block->get_dirty_byte_mask().test(k)) {
+ all_set = false;
+ break;
+ }
+ }
+ if (all_set)
+ block->set_m_readable(true, mf->get_access_sector_mask());
+ }
+ }
+}
+
/****** Write-hit functions (Set by config file) ******/
/// Write-back hit: Mark block as modified
@@ -1173,7 +1225,12 @@ cache_request_status data_cache::wr_hit_wb(new_addr_type addr,
new_addr_type block_addr = m_config.block_addr(addr);
m_tag_array->access(block_addr, time, cache_index, mf); // update LRU state
cache_block_t *block = m_tag_array->get_block(cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED, mf->get_access_sector_mask());
+ block->set_byte_mask(mf);
+ update_m_readable(mf,cache_index);
return HIT;
}
@@ -1192,7 +1249,12 @@ cache_request_status data_cache::wr_hit_wt(new_addr_type addr,
new_addr_type block_addr = m_config.block_addr(addr);
m_tag_array->access(block_addr, time, cache_index, mf); // update LRU state
cache_block_t *block = m_tag_array->get_block(cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED, mf->get_access_sector_mask());
+ block->set_byte_mask(mf);
+ update_m_readable(mf,cache_index);
// generate a write-through
send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
@@ -1302,8 +1364,10 @@ enum cache_request_status data_cache::wr_miss_wa_naive(
assert(status ==
MISS); // SECTOR_MISS and HIT_RESERVED should not send write back
mem_fetch *wb = m_memfetch_creator->alloc(
- evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ evicted.m_block_addr, m_wrbk_type, mf->get_access_warp_mask(),
+ evicted.m_byte_mask, evicted.m_sector_mask, evicted.m_modified_size,
+ true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, -1, -1, -1,
+ NULL);
// the evicted block may have wrong chip id when advanced L2 hashing is
// used, so set the right chip address from the original mf
wb->set_chip(mf->get_tlx_addr().chip);
@@ -1340,7 +1404,11 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write(
m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
assert(status != HIT);
cache_block_t *block = m_tag_array->get_block(cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED, mf->get_access_sector_mask());
+ block->set_byte_mask(mf);
if (status == HIT_RESERVED)
block->set_ignore_on_fill(true, mf->get_access_sector_mask());
@@ -1349,8 +1417,10 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write(
// (already modified lower level)
if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
mem_fetch *wb = m_memfetch_creator->alloc(
- evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ evicted.m_block_addr, m_wrbk_type, mf->get_access_warp_mask(),
+ evicted.m_byte_mask, evicted.m_sector_mask, evicted.m_modified_size,
+ true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, -1, -1, -1,
+ NULL);
// the evicted block may have wrong chip id when advanced L2 hashing is
// used, so set the right chip address from the original mf
wb->set_chip(mf->get_tlx_addr().chip);
@@ -1411,6 +1481,7 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write(
cache_block_t *block = m_tag_array->get_block(cache_index);
block->set_modified_on_fill(true, mf->get_access_sector_mask());
+ block->set_byte_mask_on_fill(true);
events.push_back(cache_event(WRITE_ALLOCATE_SENT));
@@ -1419,8 +1490,10 @@ enum cache_request_status data_cache::wr_miss_wa_fetch_on_write(
// (already modified lower level)
if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
mem_fetch *wb = m_memfetch_creator->alloc(
- evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ evicted.m_block_addr, m_wrbk_type, mf->get_access_warp_mask(),
+ evicted.m_byte_mask, evicted.m_sector_mask, evicted.m_modified_size,
+ true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, -1, -1, -1,
+ NULL);
// the evicted block may have wrong chip id when advanced L2 hashing is
// used, so set the right chip address from the original mf
wb->set_chip(mf->get_tlx_addr().chip);
@@ -1448,6 +1521,10 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read(
return RESERVATION_FAIL; // cannot handle request this cycle
}
+ if (m_config.m_write_policy == WRITE_THROUGH) {
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
+ }
+
bool wb = false;
evicted_block_info evicted;
@@ -1455,25 +1532,35 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read(
m_tag_array->access(block_addr, time, cache_index, wb, evicted, mf);
assert(m_status != HIT);
cache_block_t *block = m_tag_array->get_block(cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED, mf->get_access_sector_mask());
+ block->set_byte_mask(mf);
if (m_status == HIT_RESERVED) {
block->set_ignore_on_fill(true, mf->get_access_sector_mask());
block->set_modified_on_fill(true, mf->get_access_sector_mask());
+ block->set_byte_mask_on_fill(true);
}
if (mf->get_access_byte_mask().count() == m_config.get_atom_sz()) {
block->set_m_readable(true, mf->get_access_sector_mask());
} else {
block->set_m_readable(false, mf->get_access_sector_mask());
+ if (m_status == HIT_RESERVED)
+ block->set_readable_on_fill(true, mf->get_access_sector_mask());
}
+ update_m_readable(mf,cache_index);
if (m_status != RESERVATION_FAIL) {
// If evicted block is modified and not a write-through
// (already modified lower level)
if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
mem_fetch *wb = m_memfetch_creator->alloc(
- evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ evicted.m_block_addr, m_wrbk_type, mf->get_access_warp_mask(),
+ evicted.m_byte_mask, evicted.m_sector_mask, evicted.m_modified_size,
+ true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, -1, -1, -1,
+ NULL);
// the evicted block may have wrong chip id when advanced L2 hashing is
// used, so set the right chip address from the original mf
wb->set_chip(mf->get_tlx_addr().chip);
@@ -1516,8 +1603,12 @@ enum cache_request_status data_cache::rd_hit_base(
if (mf->isatomic()) {
assert(mf->get_access_type() == GLOBAL_ACC_R);
cache_block_t *block = m_tag_array->get_block(cache_index);
+ if (!block->is_modified_line()) {
+ m_tag_array->inc_dirty();
+ }
block->set_status(MODIFIED,
- mf->get_access_sector_mask()); // mark line as dirty
+ mf->get_access_sector_mask()); // mark line as
+ block->set_byte_mask(mf);
}
return HIT;
}
@@ -1548,8 +1639,10 @@ enum cache_request_status data_cache::rd_miss_base(
// (already modified lower level)
if (wb && (m_config.m_write_policy != WRITE_THROUGH)) {
mem_fetch *wb = m_memfetch_creator->alloc(
- evicted.m_block_addr, m_wrbk_type, evicted.m_modified_size, true,
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle);
+ evicted.m_block_addr, m_wrbk_type, mf->get_access_warp_mask(),
+ evicted.m_byte_mask, evicted.m_sector_mask, evicted.m_modified_size,
+ true, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, -1, -1, -1,
+ NULL);
// the evicted block may have wrong chip id when advanced L2 hashing is
// used, so set the right chip address from the original mf
wb->set_chip(mf->get_tlx_addr().chip);
@@ -1572,7 +1665,7 @@ enum cache_request_status read_only_cache::access(
new_addr_type block_addr = m_config.block_addr(addr);
unsigned cache_index = (unsigned)-1;
enum cache_request_status status =
- m_tag_array->probe(block_addr, cache_index, mf);
+ m_tag_array->probe(block_addr, cache_index, mf, mf->is_write());
enum cache_request_status cache_status = RESERVATION_FAIL;
if (status == HIT) {
@@ -1659,7 +1752,7 @@ enum cache_request_status data_cache::access(new_addr_type addr, mem_fetch *mf,
new_addr_type block_addr = m_config.block_addr(addr);
unsigned cache_index = (unsigned)-1;
enum cache_request_status probe_status =
- m_tag_array->probe(block_addr, cache_index, mf, true);
+ m_tag_array->probe(block_addr, cache_index, mf, mf->is_write(), true);
enum cache_request_status access_status =
process_tag_probe(wr, probe_status, addr, cache_index, mf, time, events);
m_stats.inc_stats(mf->get_access_type(),
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 5c28b41..67d084c 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -49,6 +49,7 @@ enum cache_request_status {
MISS,
RESERVATION_FAIL,
SECTOR_MISS,
+ MSHR_HIT,
NUM_CACHE_REQUEST_STATUS
};
@@ -71,14 +72,26 @@ enum cache_event_type {
struct evicted_block_info {
new_addr_type m_block_addr;
unsigned m_modified_size;
+ mem_access_byte_mask_t m_byte_mask;
+ mem_access_sector_mask_t m_sector_mask;
evicted_block_info() {
m_block_addr = 0;
m_modified_size = 0;
+ m_byte_mask.reset();
+ m_sector_mask.reset();
}
void set_info(new_addr_type block_addr, unsigned modified_size) {
m_block_addr = block_addr;
m_modified_size = modified_size;
}
+ void set_info(new_addr_type block_addr, unsigned modified_size,
+ mem_access_byte_mask_t byte_mask,
+ mem_access_sector_mask_t sector_mask) {
+ m_block_addr = block_addr;
+ m_modified_size = modified_size;
+ m_byte_mask = byte_mask;
+ m_sector_mask = sector_mask;
+ }
};
struct cache_event {
@@ -108,7 +121,8 @@ struct cache_block_t {
virtual void allocate(new_addr_type tag, new_addr_type block_addr,
unsigned time,
mem_access_sector_mask_t sector_mask) = 0;
- virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask) = 0;
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) = 0;
virtual bool is_invalid_line() = 0;
virtual bool is_valid_line() = 0;
@@ -119,7 +133,10 @@ struct cache_block_t {
mem_access_sector_mask_t sector_mask) = 0;
virtual void set_status(enum cache_block_state m_status,
mem_access_sector_mask_t sector_mask) = 0;
-
+ virtual void set_byte_mask(mem_fetch *mf) = 0;
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) = 0;
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() = 0;
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() = 0;
virtual unsigned long long get_last_access_time() = 0;
virtual void set_last_access_time(unsigned long long time,
mem_access_sector_mask_t sector_mask) = 0;
@@ -128,6 +145,9 @@ struct cache_block_t {
mem_access_sector_mask_t sector_mask) = 0;
virtual void set_modified_on_fill(bool m_modified,
mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_byte_mask_on_fill(bool m_modified) = 0;
virtual unsigned get_modified_size() = 0;
virtual void set_m_readable(bool readable,
mem_access_sector_mask_t sector_mask) = 0;
@@ -147,6 +167,7 @@ struct line_cache_block : public cache_block_t {
m_status = INVALID;
m_ignore_on_fill_status = false;
m_set_modified_on_fill = false;
+ m_set_readable_on_fill = false;
m_readable = true;
}
void allocate(new_addr_type tag, new_addr_type block_addr, unsigned time,
@@ -159,13 +180,19 @@ struct line_cache_block : public cache_block_t {
m_status = RESERVED;
m_ignore_on_fill_status = false;
m_set_modified_on_fill = false;
+ m_set_readable_on_fill = false;
+ m_set_byte_mask_on_fill = false;
}
- void fill(unsigned time, mem_access_sector_mask_t sector_mask) {
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) {
// if(!m_ignore_on_fill_status)
// assert( m_status == RESERVED );
m_status = m_set_modified_on_fill ? MODIFIED : VALID;
+ if (m_set_readable_on_fill) m_readable = true;
+ if (m_set_byte_mask_on_fill) set_byte_mask(byte_mask);
+
m_fill_time = time;
}
virtual bool is_invalid_line() { return m_status == INVALID; }
@@ -181,6 +208,20 @@ struct line_cache_block : public cache_block_t {
mem_access_sector_mask_t sector_mask) {
m_status = status;
}
+ virtual void set_byte_mask(mem_fetch *mf) {
+ m_dirty_byte_mask = m_dirty_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_dirty_byte_mask = m_dirty_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_dirty_byte_mask;
+ }
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() {
+ mem_access_sector_mask_t sector_mask;
+ if (m_status == MODIFIED) sector_mask.set();
+ return sector_mask;
+ }
virtual unsigned long long get_last_access_time() {
return m_last_access_time;
}
@@ -197,6 +238,13 @@ struct line_cache_block : public cache_block_t {
mem_access_sector_mask_t sector_mask) {
m_set_modified_on_fill = m_modified;
}
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) {
+ m_set_readable_on_fill = readable;
+ }
+ virtual void set_byte_mask_on_fill(bool m_modified) {
+ m_set_byte_mask_on_fill = m_modified;
+ }
virtual unsigned get_modified_size() {
return SECTOR_CHUNCK_SIZE * SECTOR_SIZE; // i.e. cache line size
}
@@ -218,7 +266,10 @@ struct line_cache_block : public cache_block_t {
cache_block_state m_status;
bool m_ignore_on_fill_status;
bool m_set_modified_on_fill;
+ bool m_set_readable_on_fill;
+ bool m_set_byte_mask_on_fill;
bool m_readable;
+ mem_access_byte_mask_t m_dirty_byte_mask;
};
struct sector_cache_block : public cache_block_t {
@@ -232,11 +283,13 @@ struct sector_cache_block : public cache_block_t {
m_status[i] = INVALID;
m_ignore_on_fill_status[i] = false;
m_set_modified_on_fill[i] = false;
+ m_set_readable_on_fill[i] = false;
m_readable[i] = true;
}
m_line_alloc_time = 0;
m_line_last_access_time = 0;
m_line_fill_time = 0;
+ m_dirty_byte_mask.reset();
}
virtual void allocate(new_addr_type tag, new_addr_type block_addr,
@@ -261,6 +314,8 @@ struct sector_cache_block : public cache_block_t {
m_status[sidx] = RESERVED;
m_ignore_on_fill_status[sidx] = false;
m_set_modified_on_fill[sidx] = false;
+ m_set_readable_on_fill[sidx] = false;
+ m_set_byte_mask_on_fill = false;
// set line stats
m_line_alloc_time = time; // only set this for the first allocated sector
@@ -283,6 +338,8 @@ struct sector_cache_block : public cache_block_t {
else
m_set_modified_on_fill[sidx] = false;
+ m_set_readable_on_fill[sidx] = false;
+
m_status[sidx] = RESERVED;
m_ignore_on_fill_status[sidx] = false;
// m_set_modified_on_fill[sidx] = false;
@@ -293,14 +350,20 @@ struct sector_cache_block : public cache_block_t {
m_line_fill_time = 0;
}
- virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask) {
+ virtual void fill(unsigned time, mem_access_sector_mask_t sector_mask,
+ mem_access_byte_mask_t byte_mask) {
unsigned sidx = get_sector_index(sector_mask);
// if(!m_ignore_on_fill_status[sidx])
// assert( m_status[sidx] == RESERVED );
-
m_status[sidx] = m_set_modified_on_fill[sidx] ? MODIFIED : VALID;
+ if (m_set_readable_on_fill[sidx]) {
+ m_readable[sidx] = true;
+ m_set_readable_on_fill[sidx] = false;
+ }
+ if (m_set_byte_mask_on_fill) set_byte_mask(byte_mask);
+
m_sector_fill_time[sidx] = time;
m_line_fill_time = time;
}
@@ -340,6 +403,22 @@ struct sector_cache_block : public cache_block_t {
m_status[sidx] = status;
}
+ virtual void set_byte_mask(mem_fetch *mf) {
+ m_dirty_byte_mask = m_dirty_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_dirty_byte_mask = m_dirty_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_dirty_byte_mask;
+ }
+ virtual mem_access_sector_mask_t get_dirty_sector_mask() {
+ mem_access_sector_mask_t sector_mask;
+ for (unsigned i = 0; i < SECTOR_CHUNCK_SIZE; i++) {
+ if (m_status[i] == MODIFIED) sector_mask.set(i);
+ }
+ return sector_mask;
+ }
virtual unsigned long long get_last_access_time() {
return m_line_last_access_time;
}
@@ -365,7 +444,15 @@ struct sector_cache_block : public cache_block_t {
unsigned sidx = get_sector_index(sector_mask);
m_set_modified_on_fill[sidx] = m_modified;
}
+ virtual void set_byte_mask_on_fill(bool m_modified) {
+ m_set_byte_mask_on_fill = m_modified;
+ }
+ virtual void set_readable_on_fill(bool readable,
+ mem_access_sector_mask_t sector_mask) {
+ unsigned sidx = get_sector_index(sector_mask);
+ m_set_readable_on_fill[sidx] = readable;
+ }
virtual void set_m_readable(bool readable,
mem_access_sector_mask_t sector_mask) {
unsigned sidx = get_sector_index(sector_mask);
@@ -400,7 +487,10 @@ struct sector_cache_block : public cache_block_t {
cache_block_state m_status[SECTOR_CHUNCK_SIZE];
bool m_ignore_on_fill_status[SECTOR_CHUNCK_SIZE];
bool m_set_modified_on_fill[SECTOR_CHUNCK_SIZE];
+ bool m_set_readable_on_fill[SECTOR_CHUNCK_SIZE];
+ bool m_set_byte_mask_on_fill;
bool m_readable[SECTOR_CHUNCK_SIZE];
+ mem_access_byte_mask_t m_dirty_byte_mask;
unsigned get_sector_index(mem_access_sector_mask_t sector_mask) {
assert(sector_mask.count() == 1);
@@ -463,6 +553,7 @@ class cache_config {
m_data_port_width = 0;
m_set_index_function = LINEAR_SET_FUNCTION;
m_is_streaming = false;
+ m_wr_percent = 0;
}
void init(char *config, FuncCache status) {
cache_status = status;
@@ -503,16 +594,6 @@ class cache_config {
default:
exit_parse_error();
}
- switch (rp) {
- case 'L':
- m_replacement_policy = LRU;
- break;
- case 'F':
- m_replacement_policy = FIFO;
- break;
- default:
- exit_parse_error();
- }
switch (wp) {
case 'R':
m_write_policy = READ_ONLY;
@@ -546,22 +627,27 @@ class cache_config {
exit_parse_error();
}
if (m_alloc_policy == STREAMING) {
- // For streaming cache, we set the alloc policy to be on-fill to remove
- // all line_alloc_fail stalls we set the MSHRs to be equal to max
- // allocated cache lines. This is possible by moving TAG to be shared
- // between cache line and MSHR enrty (i.e. for each cache line, there is
- // an MSHR rntey associated with it) This is the easiest think we can
- // think about to model (mimic) L1 streaming cache in Pascal and Volta
- // Based on our microbenchmakrs, MSHRs entries have been increasing
- // substantially in Pascal and Volta For more information about streaming
- // cache, see:
- // http://on-demand.gputechconf.com/gtc/2017/presentation/s7798-luke-durant-inside-volta.pdf
- // https://ieeexplore.ieee.org/document/8344474/
+ /*
+ For streaming cache:
+ (1) we set the alloc policy to be on-fill to remove all line_alloc_fail
+ stalls. if the whole memory is allocated to the L1 cache, then make the
+ allocation to be on_MISS otherwise, make it ON_FILL to eliminate line
+ allocation fails. i.e. MSHR throughput is the same, independent on the L1
+ cache size/associativity So, we set the allocation policy per kernel
+ basis, see shader.cc, max_cta() function
+
+ (2) We also set the MSHRs to be equal to max
+ allocated cache lines. This is possible by moving TAG to be shared
+ between cache line and MSHR enrty (i.e. for each cache line, there is
+ an MSHR rntey associated with it). This is the easiest think we can
+ think of to model (mimic) L1 streaming cache in Pascal and Volta
+
+ For more information about streaming cache, see:
+ http://on-demand.gputechconf.com/gtc/2017/presentation/s7798-luke-durant-inside-volta.pdf
+ https://ieeexplore.ieee.org/document/8344474/
+ */
m_is_streaming = true;
m_alloc_policy = ON_FILL;
- m_mshr_entries = m_nset * m_assoc * MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
- if (m_cache_type == SECTOR) m_mshr_entries *= SECTOR_CHUNCK_SIZE;
- m_mshr_max_merge = MAX_WARP_PER_SM;
}
switch (mshr_type) {
case 'F':
@@ -610,7 +696,8 @@ class cache_config {
}
// detect invalid configuration
- if (m_alloc_policy == ON_FILL and m_write_policy == WRITE_BACK) {
+ if ((m_alloc_policy == ON_FILL || m_alloc_policy == STREAMING) and
+ m_write_policy == WRITE_BACK) {
// A writeback cache with allocate-on-fill policy will inevitably lead to
// deadlock: The deadlock happens when an incoming cache-fill evicts a
// dirty line, generating a writeback request. If the memory subsystem is
@@ -656,6 +743,9 @@ class cache_config {
case 'L':
m_set_index_function = LINEAR_SET_FUNCTION;
break;
+ case 'X':
+ m_set_index_function = BITWISE_XORING_FUNCTION;
+ break;
default:
exit_parse_error();
}
@@ -675,11 +765,11 @@ class cache_config {
}
unsigned get_max_num_lines() const {
assert(m_valid);
- return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * m_nset * original_m_assoc;
+ return get_max_cache_multiplier() * m_nset * original_m_assoc;
}
unsigned get_max_assoc() const {
assert(m_valid);
- return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * original_m_assoc;
+ return get_max_cache_multiplier() * original_m_assoc;
}
void print(FILE *fp) const {
fprintf(fp, "Size = %d B (%d Set x %d-way x %d byte line)\n",
@@ -688,6 +778,10 @@ class cache_config {
virtual unsigned set_index(new_addr_type addr) const;
+ virtual unsigned get_max_cache_multiplier() const {
+ return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
+ }
+
unsigned hash_function(new_addr_type addr, unsigned m_nset,
unsigned m_line_sz_log2, unsigned m_nset_log2,
unsigned m_index_function) const;
@@ -722,10 +816,18 @@ class cache_config {
}
bool is_streaming() { return m_is_streaming; }
FuncCache get_cache_status() { return cache_status; }
+ void set_allocation_policy(enum allocation_policy_t alloc) {
+ m_alloc_policy = alloc;
+ }
char *m_config_string;
char *m_config_stringPrefL1;
char *m_config_stringPrefShared;
FuncCache cache_status;
+ unsigned m_wr_percent;
+ write_allocate_policy_t get_write_allocate_policy() {
+ return m_write_alloc_policy;
+ }
+ write_policy_t get_write_policy() { return m_write_policy; }
protected:
void exit_parse_error() {
@@ -789,16 +891,28 @@ class l1d_cache_config : public cache_config {
l1d_cache_config() : cache_config() {}
unsigned set_bank(new_addr_type addr) const;
void init(char *config, FuncCache status) {
- m_banks_byte_interleaving_log2 = LOGB2(l1_banks_byte_interleaving);
- m_l1_banks_log2 = LOGB2(l1_banks);
+ l1_banks_byte_interleaving_log2 = LOGB2(l1_banks_byte_interleaving);
+ l1_banks_log2 = LOGB2(l1_banks);
cache_config::init(config, status);
}
unsigned l1_latency;
unsigned l1_banks;
- unsigned m_l1_banks_log2;
+ unsigned l1_banks_log2;
unsigned l1_banks_byte_interleaving;
- unsigned m_banks_byte_interleaving_log2;
+ unsigned l1_banks_byte_interleaving_log2;
unsigned l1_banks_hashing_function;
+ unsigned m_unified_cache_size;
+ virtual unsigned get_max_cache_multiplier() const {
+ // set * assoc * cacheline size. Then convert Byte to KB
+ // gpgpu_unified_cache_size is in KB while original_sz is in B
+ if (m_unified_cache_size > 0) {
+ unsigned original_size = m_nset * original_m_assoc * m_line_sz / 1024;
+ assert(m_unified_cache_size % original_size == 0);
+ return m_unified_cache_size / original_size;
+ } else {
+ return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
+ }
+ }
};
class l2_cache_config : public cache_config {
@@ -818,9 +932,10 @@ class tag_array {
~tag_array();
enum cache_request_status probe(new_addr_type addr, unsigned &idx,
- mem_fetch *mf, bool probe_mode = false) const;
+ mem_fetch *mf, bool is_write,
+ bool probe_mode = false) const;
enum cache_request_status probe(new_addr_type addr, unsigned &idx,
- mem_access_sector_mask_t mask,
+ mem_access_sector_mask_t mask, bool is_write,
bool probe_mode = false,
mem_fetch *mf = NULL) const;
enum cache_request_status access(new_addr_type addr, unsigned time,
@@ -829,9 +944,10 @@ class tag_array {
unsigned &idx, bool &wb,
evicted_block_info &evicted, mem_fetch *mf);
- void fill(new_addr_type addr, unsigned time, mem_fetch *mf);
+ void fill(new_addr_type addr, unsigned time, mem_fetch *mf, bool is_write);
void fill(unsigned idx, unsigned time, mem_fetch *mf);
- void fill(new_addr_type addr, unsigned time, mem_access_sector_mask_t mask);
+ void fill(new_addr_type addr, unsigned time, mem_access_sector_mask_t mask,
+ mem_access_byte_mask_t byte_mask, bool is_write);
unsigned size() const { return m_config.get_num_lines(); }
cache_block_t *get_block(unsigned idx) { return m_lines[idx]; }
@@ -849,6 +965,7 @@ class tag_array {
void update_cache_parameters(cache_config &config);
void add_pending_line(mem_fetch *mf);
void remove_pending_line(mem_fetch *mf);
+ void inc_dirty() { m_dirty++; }
protected:
// This constructor is intended for use only from derived classes that wish to
@@ -869,6 +986,7 @@ class tag_array {
// allocated but not filled
unsigned m_res_fail;
unsigned m_sector_miss;
+ unsigned m_dirty;
// performance counters for calculating the amount of misses within a time
// window
@@ -1214,7 +1332,8 @@ class baseline_cache : public cache_t {
// something is read or written without doing anything else.
void force_tag_access(new_addr_type addr, unsigned time,
mem_access_sector_mask_t mask) {
- m_tag_array->fill(addr, time, mask);
+ mem_access_byte_mask_t byte_mask;
+ m_tag_array->fill(addr, time, mask, byte_mask, true);
}
protected:
@@ -1451,7 +1570,7 @@ class data_cache : public baseline_cache {
/// Sends write request to lower level memory (write or writeback)
void send_write_request(mem_fetch *mf, cache_event request, unsigned time,
std::list<cache_event> &events);
-
+ void update_m_readable(mem_fetch *mf, unsigned cache_index);
// Member Function pointers - Set by configuration options
// to the functions below each grouping
/******* Write-hit configs *******/
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index 1650688..56ede05 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -249,6 +249,8 @@ void shader_core_config::reg_options(class OptionParser *opp) {
" {<nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_"
"alloc>,<mshr>:<N>:<merge>,<mq> | none}",
"none");
+ option_parser_register(opp, "-gpgpu_l1_cache_write_ratio", OPT_UINT32,
+ &m_L1D_config.m_wr_percent, "L1D write ratio", "0");
option_parser_register(opp, "-gpgpu_l1_banks", OPT_UINT32,
&m_L1D_config.l1_banks, "The number of L1 cache banks",
"1");
@@ -326,7 +328,14 @@ void shader_core_config::reg_options(class OptionParser *opp) {
option_parser_register(
opp, "-gpgpu_shmem_size", OPT_UINT32, &gpgpu_shmem_size,
"Size of shared memory per shader core (default 16kB)", "16384");
- option_parser_register(opp, "-gpgpu_adaptive_cache_config", OPT_UINT32,
+ option_parser_register(opp, "-gpgpu_shmem_option", OPT_CSTR,
+ &gpgpu_shmem_option,
+ "Option list of shared memory sizes", "0");
+ option_parser_register(
+ opp, "-gpgpu_unified_l1d_size", OPT_UINT32,
+ &m_L1D_config.m_unified_cache_size,
+ "Size of unified data cache(L1D + shared memory) in KB", "0");
+ option_parser_register(opp, "-gpgpu_adaptive_cache_config", OPT_BOOL,
&adaptive_cache_config, "adaptive_cache_config", "0");
option_parser_register(
opp, "-gpgpu_shmem_sizeDefault", OPT_UINT32, &gpgpu_shmem_sizeDefault,
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index ab6e5c2..f1c761f 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -57,6 +57,19 @@ mem_fetch *partition_mf_allocator::alloc(new_addr_type addr,
return mf;
}
+mem_fetch *partition_mf_allocator::alloc(
+ new_addr_type addr, mem_access_type type, const active_mask_t &active_mask,
+ const mem_access_byte_mask_t &byte_mask,
+ const mem_access_sector_mask_t &sector_mask, unsigned size, bool wr,
+ unsigned long long cycle, unsigned wid, unsigned sid, unsigned tpc,
+ mem_fetch *original_mf) const {
+ mem_access_t access(type, addr, size, wr, active_mask, byte_mask, sector_mask,
+ m_memory_config->gpgpu_ctx);
+ mem_fetch *mf =
+ new mem_fetch(access, NULL, wr ? WRITE_PACKET_SIZE : READ_PACKET_SIZE,
+ wid, sid, tpc, m_memory_config, cycle, original_mf);
+ return mf;
+}
memory_partition_unit::memory_partition_unit(unsigned partition_id,
const memory_config *config,
class memory_stats_t *stats,
@@ -541,10 +554,15 @@ void memory_sub_partition::cache_cycle(unsigned cycle) {
m_config->m_L2_config.m_write_alloc_policy ==
LAZY_FETCH_ON_READ) &&
!was_writeallocate_sent(events)) {
- mf->set_reply();
- mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,
- m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle);
- m_L2_icnt_queue->push(mf);
+ if (mf->get_access_type() == L1_WRBK_ACC) {
+ m_request_tracker.erase(mf);
+ delete mf;
+ } else {
+ mf->set_reply();
+ mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,
+ m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle);
+ m_L2_icnt_queue->push(mf);
+ }
}
// L2 cache accepted request
m_icnt_L2_queue->pop();
@@ -694,71 +712,68 @@ bool memory_sub_partition::busy() const { return !m_request_tracker.empty(); }
std::vector<mem_fetch *>
memory_sub_partition::breakdown_request_to_sector_requests(mem_fetch *mf) {
std::vector<mem_fetch *> result;
-
+ mem_access_sector_mask_t sector_mask = mf->get_access_sector_mask();
if (mf->get_data_size() == SECTOR_SIZE &&
mf->get_access_sector_mask().count() == 1) {
result.push_back(mf);
- } else if (mf->get_data_size() == 128 || mf->get_data_size() == 64) {
- // We only accept 32, 64 and 128 bytes reqs
- unsigned start = 0, end = 0;
- if (mf->get_data_size() == 128) {
+ } else if (mf->get_data_size() == MAX_MEMORY_ACCESS_SIZE) {
+ // break down every sector
+ mem_access_byte_mask_t mask;
+ for (unsigned i = 0; i < SECTOR_CHUNCK_SIZE; i++) {
+ for (unsigned k = i * SECTOR_SIZE; k < (i + 1) * SECTOR_SIZE; k++) {
+ mask.set(k);
+ }
+ mem_fetch *n_mf = m_mf_allocator->alloc(
+ mf->get_addr() + SECTOR_SIZE * i, mf->get_access_type(),
+ mf->get_access_warp_mask(), mf->get_access_byte_mask() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), SECTOR_SIZE, mf->is_write(),
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, mf->get_wid(),
+ mf->get_sid(), mf->get_tpc(), mf);
+
+ result.push_back(n_mf);
+ }
+ // This is for constant cache
+ } else if (mf->get_data_size() == 64 &&
+ (mf->get_access_sector_mask().all() ||
+ mf->get_access_sector_mask().none())) {
+ unsigned start;
+ if (mf->get_addr() % MAX_MEMORY_ACCESS_SIZE == 0)
start = 0;
- end = 3;
- } else if (mf->get_data_size() == 64 &&
- mf->get_access_sector_mask().to_string() == "1100") {
+ else
start = 2;
- end = 3;
- } else if (mf->get_data_size() == 64 &&
- mf->get_access_sector_mask().to_string() == "0011") {
- start = 0;
- end = 1;
- } else if (mf->get_data_size() == 64 &&
- (mf->get_access_sector_mask().to_string() == "1111" ||
- mf->get_access_sector_mask().to_string() == "0000")) {
- if (mf->get_addr() % 128 == 0) {
- start = 0;
- end = 1;
- } else {
- start = 2;
- end = 3;
+ mem_access_byte_mask_t mask;
+ for (unsigned i = start; i < start + 2; i++) {
+ for (unsigned k = i * SECTOR_SIZE; k < (i + 1) * SECTOR_SIZE; k++) {
+ mask.set(k);
}
- } else {
- printf(
- "Invalid sector received, address = 0x%06llx, sector mask = %s, data "
- "size = %d",
- mf->get_addr(), mf->get_access_sector_mask(), mf->get_data_size());
- assert(0 && "Undefined sector mask is received");
- }
-
- std::bitset<SECTOR_SIZE * SECTOR_CHUNCK_SIZE> byte_sector_mask;
- byte_sector_mask.reset();
- for (unsigned k = start * SECTOR_SIZE; k < SECTOR_SIZE; ++k)
- byte_sector_mask.set(k);
-
- for (unsigned j = start, i = 0; j <= end; ++j, ++i) {
- const mem_access_t *ma = new mem_access_t(
- mf->get_access_type(), mf->get_addr() + SECTOR_SIZE * i, SECTOR_SIZE,
- mf->is_write(), mf->get_access_warp_mask(),
- mf->get_access_byte_mask() & byte_sector_mask,
- std::bitset<SECTOR_CHUNCK_SIZE>().set(j), m_gpu->gpgpu_ctx);
-
- mem_fetch *n_mf =
- new mem_fetch(*ma, NULL, mf->get_ctrl_size(), mf->get_wid(),
- mf->get_sid(), mf->get_tpc(), mf->get_mem_config(),
- m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, mf);
+ mem_fetch *n_mf = m_mf_allocator->alloc(
+ mf->get_addr(), mf->get_access_type(), mf->get_access_warp_mask(),
+ mf->get_access_byte_mask() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), SECTOR_SIZE, mf->is_write(),
+ m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, mf->get_wid(),
+ mf->get_sid(), mf->get_tpc(), mf);
result.push_back(n_mf);
- byte_sector_mask <<= SECTOR_SIZE;
}
} else {
- printf(
- "Invalid sector received, address = 0x%06llx, sector mask = %d, byte "
- "mask = , data size = %u",
- mf->get_addr(), mf->get_access_sector_mask().count(),
- mf->get_data_size());
- assert(0 && "Undefined data size is received");
- }
+ for (unsigned i = 0; i < SECTOR_CHUNCK_SIZE; i++) {
+ if (sector_mask.test(i)) {
+ mem_access_byte_mask_t mask;
+ for (unsigned k = i * SECTOR_SIZE; k < (i + 1) * SECTOR_SIZE; k++) {
+ mask.set(k);
+ }
+ mem_fetch *n_mf = m_mf_allocator->alloc(
+ mf->get_addr() + SECTOR_SIZE * i, mf->get_access_type(),
+ mf->get_access_warp_mask(), mf->get_access_byte_mask() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), SECTOR_SIZE,
+ mf->is_write(), m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle,
+ mf->get_wid(), mf->get_sid(), mf->get_tpc(), mf);
+ result.push_back(n_mf);
+ }
+ }
+ }
+ if (result.size() == 0) assert(0 && "no mf sent");
return result;
}
diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h
index 3152db3..beed765 100644
--- a/src/gpgpu-sim/l2cache.h
+++ b/src/gpgpu-sim/l2cache.h
@@ -51,6 +51,13 @@ class partition_mf_allocator : public mem_fetch_allocator {
virtual mem_fetch *alloc(new_addr_type addr, mem_access_type type,
unsigned size, bool wr,
unsigned long long cycle) const;
+ virtual mem_fetch *alloc(new_addr_type addr, mem_access_type type,
+ const active_mask_t &active_mask,
+ const mem_access_byte_mask_t &byte_mask,
+ const mem_access_sector_mask_t &sector_mask,
+ unsigned size, bool wr, unsigned long long cycle,
+ unsigned wid, unsigned sid, unsigned tpc,
+ mem_fetch *original_mf) const;
private:
const memory_config *m_memory_config;
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index c6e7b8f..bcfda18 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -61,6 +61,20 @@ mem_fetch *shader_core_mem_fetch_allocator::alloc(
m_core_id, m_cluster_id, m_memory_config, cycle);
return mf;
}
+
+mem_fetch *shader_core_mem_fetch_allocator::alloc(
+ new_addr_type addr, mem_access_type type, const active_mask_t &active_mask,
+ const mem_access_byte_mask_t &byte_mask,
+ const mem_access_sector_mask_t &sector_mask, unsigned size, bool wr,
+ unsigned long long cycle, unsigned wid, unsigned sid, unsigned tpc,
+ mem_fetch *original_mf) const {
+ mem_access_t access(type, addr, size, wr, active_mask, byte_mask, sector_mask,
+ m_memory_config->gpgpu_ctx);
+ mem_fetch *mf = new mem_fetch(
+ access, NULL, wr ? WRITE_PACKET_SIZE : READ_PACKET_SIZE, wid, m_core_id,
+ m_cluster_id, m_memory_config, cycle, original_mf);
+ return mf;
+}
/////////////////////////////////////////////////////////////////////////////
std::list<unsigned> shader_core_ctx::get_regs_written(const inst_t &fvt) const {
@@ -108,7 +122,7 @@ void shader_core_ctx::create_front_pipeline() {
if (m_config->sub_core_model) {
// in subcore model, each scheduler should has its own issue register, so
- // num scheduler = reg width
+ // ensure num scheduler = reg width
assert(m_config->gpgpu_num_sched_per_core ==
m_pipeline_reg[ID_OC_SP].get_size());
assert(m_config->gpgpu_num_sched_per_core ==
@@ -124,6 +138,11 @@ void shader_core_ctx::create_front_pipeline() {
if (m_config->gpgpu_num_int_units > 0)
assert(m_config->gpgpu_num_sched_per_core ==
m_pipeline_reg[ID_OC_INT].get_size());
+ for (int j = 0; j < m_config->m_specialized_unit.size(); j++) {
+ if (m_config->m_specialized_unit[j].num_units > 0)
+ assert(m_config->gpgpu_num_sched_per_core ==
+ m_config->m_specialized_unit[j].id_oc_spec_reg_width);
+ }
}
m_threadState = (thread_ctx_t *)calloc(sizeof(thread_ctx_t),
@@ -172,6 +191,8 @@ void shader_core_ctx::create_schedulers() {
? CONCRETE_SCHEDULER_TWO_LEVEL_ACTIVE
: sched_config.find("gto") != std::string::npos
? CONCRETE_SCHEDULER_GTO
+ : sched_config.find("rrr") != std::string::npos
+ ? CONCRETE_SCHEDULER_RRR
: sched_config.find("old") != std::string::npos
? CONCRETE_SCHEDULER_OLDEST_FIRST
: sched_config.find("warp_limiting") !=
@@ -206,6 +227,14 @@ void shader_core_ctx::create_schedulers() {
&m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg,
&m_pipeline_reg[ID_OC_MEM], i));
break;
+ case CONCRETE_SCHEDULER_RRR:
+ schedulers.push_back(new rrr_scheduler(
+ m_stats, this, m_scoreboard, m_simt_stack, &m_warp,
+ &m_pipeline_reg[ID_OC_SP], &m_pipeline_reg[ID_OC_DP],
+ &m_pipeline_reg[ID_OC_SFU], &m_pipeline_reg[ID_OC_INT],
+ &m_pipeline_reg[ID_OC_TENSOR_CORE], m_specilized_dispatch_reg,
+ &m_pipeline_reg[ID_OC_MEM], i));
+ break;
case CONCRETE_SCHEDULER_OLDEST_FIRST:
schedulers.push_back(new oldest_scheduler(
m_stats, this, m_scoreboard, m_simt_stack, &m_warp,
@@ -377,41 +406,41 @@ void shader_core_ctx::create_exec_pipeline() {
// m_fu = new simd_function_unit*[m_num_function_units];
- for (int k = 0; k < m_config->gpgpu_num_sp_units; k++) {
- m_fu.push_back(new sp_unit(&m_pipeline_reg[EX_WB], m_config, this));
+ for (unsigned k = 0; k < m_config->gpgpu_num_sp_units; k++) {
+ m_fu.push_back(new sp_unit(&m_pipeline_reg[EX_WB], m_config, this, k));
m_dispatch_port.push_back(ID_OC_SP);
m_issue_port.push_back(OC_EX_SP);
}
- for (int k = 0; k < m_config->gpgpu_num_dp_units; k++) {
- m_fu.push_back(new dp_unit(&m_pipeline_reg[EX_WB], m_config, this));
+ for (unsigned k = 0; k < m_config->gpgpu_num_dp_units; k++) {
+ m_fu.push_back(new dp_unit(&m_pipeline_reg[EX_WB], m_config, this, k));
m_dispatch_port.push_back(ID_OC_DP);
m_issue_port.push_back(OC_EX_DP);
}
- for (int k = 0; k < m_config->gpgpu_num_int_units; k++) {
- m_fu.push_back(new int_unit(&m_pipeline_reg[EX_WB], m_config, this));
+ for (unsigned k = 0; k < m_config->gpgpu_num_int_units; k++) {
+ m_fu.push_back(new int_unit(&m_pipeline_reg[EX_WB], m_config, this, k));
m_dispatch_port.push_back(ID_OC_INT);
m_issue_port.push_back(OC_EX_INT);
}
- for (int k = 0; k < m_config->gpgpu_num_sfu_units; k++) {
- m_fu.push_back(new sfu(&m_pipeline_reg[EX_WB], m_config, this));
+ for (unsigned k = 0; k < m_config->gpgpu_num_sfu_units; k++) {
+ m_fu.push_back(new sfu(&m_pipeline_reg[EX_WB], m_config, this, k));
m_dispatch_port.push_back(ID_OC_SFU);
m_issue_port.push_back(OC_EX_SFU);
}
- for (int k = 0; k < m_config->gpgpu_num_tensor_core_units; k++) {
- m_fu.push_back(new tensor_core(&m_pipeline_reg[EX_WB], m_config, this));
+ for (unsigned k = 0; k < m_config->gpgpu_num_tensor_core_units; k++) {
+ m_fu.push_back(new tensor_core(&m_pipeline_reg[EX_WB], m_config, this, k));
m_dispatch_port.push_back(ID_OC_TENSOR_CORE);
m_issue_port.push_back(OC_EX_TENSOR_CORE);
}
- for (int j = 0; j < m_config->m_specialized_unit.size(); j++) {
+ for (unsigned j = 0; j < m_config->m_specialized_unit.size(); j++) {
for (unsigned k = 0; k < m_config->m_specialized_unit[j].num_units; k++) {
m_fu.push_back(new specialized_unit(
&m_pipeline_reg[EX_WB], m_config, this, SPEC_UNIT_START_ID + j,
m_config->m_specialized_unit[j].name,
- m_config->m_specialized_unit[j].latency));
+ m_config->m_specialized_unit[j].latency, k));
m_dispatch_port.push_back(m_config->m_specialized_unit[j].ID_OC_SPEC_ID);
m_issue_port.push_back(m_config->m_specialized_unit[j].OC_EX_SPEC_ID);
}
@@ -1082,6 +1111,33 @@ void scheduler_unit::order_lrr(
}
}
+template <class T>
+void scheduler_unit::order_rrr(
+ std::vector<T> &result_list, const typename std::vector<T> &input_list,
+ const typename std::vector<T>::const_iterator &last_issued_from_input,
+ unsigned num_warps_to_add) {
+ result_list.clear();
+
+ if (m_num_issued_last_cycle > 0 || warp(m_current_turn_warp).done_exit() ||
+ warp(m_current_turn_warp).waiting()) {
+ std::vector<shd_warp_t *>::const_iterator iter =
+ (last_issued_from_input == input_list.end()) ?
+ input_list.begin() : last_issued_from_input + 1;
+ for (unsigned count = 0; count < num_warps_to_add; ++iter, ++count) {
+ if (iter == input_list.end()) {
+ iter = input_list.begin();
+ }
+ unsigned warp_id = (*iter)->get_warp_id();
+ if (!(*iter)->done_exit() && !(*iter)->waiting()) {
+ result_list.push_back(*iter);
+ m_current_turn_warp = warp_id;
+ break;
+ }
+ }
+ } else {
+ result_list.push_back(&warp(m_current_turn_warp));
+ }
+}
/**
* A general function to order things in an priority-based way.
* The core usage of the function is similar to order_lrr.
@@ -1228,29 +1284,21 @@ void scheduler_unit::cycle() {
previous_issued_inst_exec_type = exec_unit_type_t::MEM;
}
} else {
- bool sp_pipe_avail =
- (m_shader->m_config->gpgpu_num_sp_units > 0) &&
- m_sp_out->has_free(m_shader->m_config->sub_core_model, m_id);
- bool sfu_pipe_avail =
- (m_shader->m_config->gpgpu_num_sfu_units > 0) &&
- m_sfu_out->has_free(m_shader->m_config->sub_core_model, m_id);
- bool tensor_core_pipe_avail =
- (m_shader->m_config->gpgpu_num_tensor_core_units > 0) &&
- m_tensor_core_out->has_free(
- m_shader->m_config->sub_core_model, m_id);
- bool dp_pipe_avail =
- (m_shader->m_config->gpgpu_num_dp_units > 0) &&
- m_dp_out->has_free(m_shader->m_config->sub_core_model, m_id);
- bool int_pipe_avail =
- (m_shader->m_config->gpgpu_num_int_units > 0) &&
- m_int_out->has_free(m_shader->m_config->sub_core_model, m_id);
-
// This code need to be refactored
if (pI->op != TENSOR_CORE_OP && pI->op != SFU_OP &&
pI->op != DP_OP && !(pI->op >= SPEC_UNIT_START_ID)) {
bool execute_on_SP = false;
bool execute_on_INT = false;
+ bool sp_pipe_avail =
+ (m_shader->m_config->gpgpu_num_sp_units > 0) &&
+ m_sp_out->has_free(m_shader->m_config->sub_core_model,
+ m_id);
+ bool int_pipe_avail =
+ (m_shader->m_config->gpgpu_num_int_units > 0) &&
+ m_int_out->has_free(m_shader->m_config->sub_core_model,
+ m_id);
+
// if INT unit pipline exist, then execute ALU and INT
// operations on INT unit and SP-FPU on SP unit (like in Volta)
// if INT unit pipline does not exist, then execute all ALU, INT
@@ -1311,6 +1359,11 @@ void scheduler_unit::cycle() {
(pI->op == DP_OP) &&
!(diff_exec_units && previous_issued_inst_exec_type ==
exec_unit_type_t::DP)) {
+ bool dp_pipe_avail =
+ (m_shader->m_config->gpgpu_num_dp_units > 0) &&
+ m_dp_out->has_free(m_shader->m_config->sub_core_model,
+ m_id);
+
if (dp_pipe_avail) {
m_shader->issue_warp(*m_dp_out, pI, active_mask, warp_id,
m_id);
@@ -1326,6 +1379,11 @@ void scheduler_unit::cycle() {
(pI->op == SFU_OP) || (pI->op == ALU_SFU_OP)) &&
!(diff_exec_units && previous_issued_inst_exec_type ==
exec_unit_type_t::SFU)) {
+ bool sfu_pipe_avail =
+ (m_shader->m_config->gpgpu_num_sfu_units > 0) &&
+ m_sfu_out->has_free(m_shader->m_config->sub_core_model,
+ m_id);
+
if (sfu_pipe_avail) {
m_shader->issue_warp(*m_sfu_out, pI, active_mask, warp_id,
m_id);
@@ -1337,6 +1395,11 @@ void scheduler_unit::cycle() {
} else if ((pI->op == TENSOR_CORE_OP) &&
!(diff_exec_units && previous_issued_inst_exec_type ==
exec_unit_type_t::TENSOR)) {
+ bool tensor_core_pipe_avail =
+ (m_shader->m_config->gpgpu_num_tensor_core_units > 0) &&
+ m_tensor_core_out->has_free(
+ m_shader->m_config->sub_core_model, m_id);
+
if (tensor_core_pipe_avail) {
m_shader->issue_warp(*m_tensor_core_out, pI, active_mask,
warp_id, m_id);
@@ -1407,7 +1470,7 @@ void scheduler_unit::cycle() {
m_last_supervised_issued = supervised_iter;
}
}
-
+ m_num_issued_last_cycle = issued;
if (issued == 1)
m_stats->single_issue_nums[m_id]++;
else if (issued > 1)
@@ -1456,6 +1519,10 @@ void lrr_scheduler::order_warps() {
order_lrr(m_next_cycle_prioritized_warps, m_supervised_warps,
m_last_supervised_issued, m_supervised_warps.size());
}
+void rrr_scheduler::order_warps() {
+ order_rrr(m_next_cycle_prioritized_warps, m_supervised_warps,
+ m_last_supervised_issued, m_supervised_warps.size());
+}
void gto_scheduler::order_warps() {
order_by_priority(m_next_cycle_prioritized_warps, m_supervised_warps,
@@ -1569,7 +1636,10 @@ void swl_scheduler::order_warps() {
}
}
-void shader_core_ctx::read_operands() {}
+void shader_core_ctx::read_operands() {
+ for (int i = 0; i < m_config->reg_file_port_throughput; ++i)
+ m_operand_collector.step();
+}
address_type coalesced_segment(address_type addr,
unsigned segment_size_lg2bytes) {
@@ -1669,8 +1739,15 @@ void shader_core_ctx::execute() {
m_fu[n]->active_lanes_in_pipeline();
unsigned issue_port = m_issue_port[n];
register_set &issue_inst = m_pipeline_reg[issue_port];
- warp_inst_t **ready_reg = issue_inst.get_ready();
- if (issue_inst.has_ready() && m_fu[n]->can_issue(**ready_reg)) {
+ unsigned reg_id;
+ bool partition_issue =
+ m_config->sub_core_model && m_fu[n]->is_issue_partitioned();
+ if (partition_issue) {
+ reg_id = m_fu[n]->get_issue_reg_id();
+ }
+ warp_inst_t **ready_reg = issue_inst.get_ready(partition_issue, reg_id);
+ if (issue_inst.has_ready(partition_issue, reg_id) &&
+ m_fu[n]->can_issue(**ready_reg)) {
bool schedule_wb_now = !m_fu[n]->stallable();
int resbus = -1;
if (schedule_wb_now &&
@@ -1970,6 +2047,21 @@ void ldst_unit::L1_latency_queue_cycle() {
} else {
assert(status == MISS || status == HIT_RESERVED);
l1_latency_queue[j][0] = NULL;
+ if (m_config->m_L1D_config.get_write_policy() != WRITE_THROUGH &&
+ mf_next->get_inst().is_store() &&
+ (m_config->m_L1D_config.get_write_allocate_policy() ==
+ FETCH_ON_WRITE ||
+ m_config->m_L1D_config.get_write_allocate_policy() ==
+ LAZY_FETCH_ON_READ) &&
+ !was_writeallocate_sent(events)) {
+ unsigned dec_ack =
+ (m_config->m_L1D_config.get_mshr_type() == SECTOR_ASSOC)
+ ? (mf_next->get_data_size() / SECTOR_SIZE)
+ : 1;
+ mf_next->set_reply();
+ for (unsigned i = 0; i < dec_ack; ++i) m_core->store_ack(mf_next);
+ if (!write_sent && !read_sent) delete mf_next;
+ }
}
}
@@ -2112,22 +2204,32 @@ simd_function_unit::simd_function_unit(const shader_core_config *config) {
m_dispatch_reg = new warp_inst_t(config);
}
+void simd_function_unit::issue(register_set &source_reg) {
+ bool partition_issue =
+ m_config->sub_core_model && this->is_issue_partitioned();
+ source_reg.move_out_to(partition_issue, this->get_issue_reg_id(),
+ m_dispatch_reg);
+ occupied.set(m_dispatch_reg->latency);
+}
+
sfu::sfu(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core)
- : pipelined_simd_unit(result_port, config, config->max_sfu_latency, core) {
+ shader_core_ctx *core, unsigned issue_reg_id)
+ : pipelined_simd_unit(result_port, config, config->max_sfu_latency, core,
+ issue_reg_id) {
m_name = "SFU";
}
tensor_core::tensor_core(register_set *result_port,
const shader_core_config *config,
- shader_core_ctx *core)
+ shader_core_ctx *core, unsigned issue_reg_id)
: pipelined_simd_unit(result_port, config, config->max_tensor_core_latency,
- core) {
+ core, issue_reg_id) {
m_name = "TENSOR_CORE";
}
void sfu::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = SFU__OP;
@@ -2136,7 +2238,8 @@ void sfu::issue(register_set &source_reg) {
}
void tensor_core::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = TENSOR_CORE__OP;
@@ -2208,34 +2311,39 @@ void tensor_core::active_lanes_in_pipeline() {
}
sp_unit::sp_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core)
- : pipelined_simd_unit(result_port, config, config->max_sp_latency, core) {
+ shader_core_ctx *core, unsigned issue_reg_id)
+ : pipelined_simd_unit(result_port, config, config->max_sp_latency, core,
+ issue_reg_id) {
m_name = "SP ";
}
specialized_unit::specialized_unit(register_set *result_port,
const shader_core_config *config,
shader_core_ctx *core, unsigned supported_op,
- char *unit_name, unsigned latency)
- : pipelined_simd_unit(result_port, config, latency, core) {
+ char *unit_name, unsigned latency,
+ unsigned issue_reg_id)
+ : pipelined_simd_unit(result_port, config, latency, core, issue_reg_id) {
m_name = unit_name;
m_supported_op = supported_op;
}
dp_unit::dp_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core)
- : pipelined_simd_unit(result_port, config, config->max_dp_latency, core) {
+ shader_core_ctx *core, unsigned issue_reg_id)
+ : pipelined_simd_unit(result_port, config, config->max_dp_latency, core,
+ issue_reg_id) {
m_name = "DP ";
}
int_unit::int_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core)
- : pipelined_simd_unit(result_port, config, config->max_int_latency, core) {
+ shader_core_ctx *core, unsigned issue_reg_id)
+ : pipelined_simd_unit(result_port, config, config->max_int_latency, core,
+ issue_reg_id) {
m_name = "INT ";
}
void sp_unit ::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = SP__OP;
m_core->incsp_stat(m_core->get_config()->warp_size, (*ready_reg)->latency);
@@ -2243,7 +2351,8 @@ void sp_unit ::issue(register_set &source_reg) {
}
void dp_unit ::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = DP__OP;
m_core->incsp_stat(m_core->get_config()->warp_size, (*ready_reg)->latency);
@@ -2251,7 +2360,8 @@ void dp_unit ::issue(register_set &source_reg) {
}
void specialized_unit ::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = SPECIALIZED__OP;
m_core->incsp_stat(m_core->get_config()->warp_size, (*ready_reg)->latency);
@@ -2259,7 +2369,8 @@ void specialized_unit ::issue(register_set &source_reg) {
}
void int_unit ::issue(register_set &source_reg) {
- warp_inst_t **ready_reg = source_reg.get_ready();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(m_config->sub_core_model, m_issue_reg_id);
// m_core->incexecstat((*ready_reg));
(*ready_reg)->op_pipe = INTP__OP;
m_core->incsp_stat(m_core->get_config()->warp_size, (*ready_reg)->latency);
@@ -2269,7 +2380,8 @@ void int_unit ::issue(register_set &source_reg) {
pipelined_simd_unit::pipelined_simd_unit(register_set *result_port,
const shader_core_config *config,
unsigned max_latency,
- shader_core_ctx *core)
+ shader_core_ctx *core,
+ unsigned issue_reg_id)
: simd_function_unit(config) {
m_result_port = result_port;
m_pipeline_depth = max_latency;
@@ -2277,6 +2389,7 @@ pipelined_simd_unit::pipelined_simd_unit(register_set *result_port,
for (unsigned i = 0; i < m_pipeline_depth; i++)
m_pipeline_reg[i] = new warp_inst_t(config);
m_core = core;
+ m_issue_reg_id = issue_reg_id;
active_insts_in_pipeline = 0;
}
@@ -2303,7 +2416,10 @@ void pipelined_simd_unit::cycle() {
void pipelined_simd_unit::issue(register_set &source_reg) {
// move_warp(m_dispatch_reg,source_reg);
- warp_inst_t **ready_reg = source_reg.get_ready();
+ bool partition_issue =
+ m_config->sub_core_model && this->is_issue_partitioned();
+ warp_inst_t **ready_reg =
+ source_reg.get_ready(partition_issue, m_issue_reg_id);
m_core->incexecstat((*ready_reg));
// source_reg.move_out_to(m_dispatch_reg);
simd_function_unit::issue(source_reg);
@@ -2360,7 +2476,7 @@ ldst_unit::ldst_unit(mem_fetch_interface *icnt,
Scoreboard *scoreboard, const shader_core_config *config,
const memory_config *mem_config, shader_core_stats *stats,
unsigned sid, unsigned tpc)
- : pipelined_simd_unit(NULL, config, config->smem_latency, core),
+ : pipelined_simd_unit(NULL, config, config->smem_latency, core, 0),
m_next_wb(config) {
assert(config->smem_latency > 1);
init(icnt, mf_allocator, core, operand_collector, scoreboard, config,
@@ -2388,7 +2504,7 @@ ldst_unit::ldst_unit(mem_fetch_interface *icnt,
Scoreboard *scoreboard, const shader_core_config *config,
const memory_config *mem_config, shader_core_stats *stats,
unsigned sid, unsigned tpc, l1_cache *new_l1d_cache)
- : pipelined_simd_unit(NULL, config, 3, core),
+ : pipelined_simd_unit(NULL, config, 3, core, 0),
m_L1D(new_l1d_cache),
m_next_wb(config) {
init(icnt, mf_allocator, core, operand_collector, scoreboard, config,
@@ -2550,8 +2666,7 @@ inst->space.get_type() != shared_space) { unsigned warp_id = inst->warp_id();
*/
void ldst_unit::cycle() {
writeback();
- for (int i = 0; i < m_config->reg_file_port_throughput; ++i)
- m_operand_collector->step();
+
for (unsigned stage = 0; (stage + 1) < m_pipeline_depth; stage++)
if (m_pipeline_reg[stage]->empty() && !m_pipeline_reg[stage + 1]->empty())
move_warp(m_pipeline_reg[stage], m_pipeline_reg[stage + 1]);
@@ -3264,49 +3379,46 @@ unsigned int shader_core_config::max_cta(const kernel_info_t &k) const {
if (adaptive_cache_config && !k.cache_config_set) {
// For more info about adaptive cache, see
// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x
- unsigned total_shmed = kernel_info->smem * result;
- assert(total_shmed >= 0 && total_shmed <= gpgpu_shmem_size);
- // assert(gpgpu_shmem_size == 98304); //Volta has 96 KB shared
- // assert(m_L1D_config.get_nset() == 4); //Volta L1 has four sets
- if (total_shmed < gpgpu_shmem_size) {
- switch (adaptive_cache_config) {
- case FIXED:
- break;
- case ADAPTIVE_VOLTA: {
- // For Volta, we assign the remaining shared memory to L1 cache
- // For more info about adaptive cache, see
- // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#shared-memory-7-x
- // assert(gpgpu_shmem_size == 98304); //Volta has 96 KB shared
+ unsigned total_shmem = kernel_info->smem * result;
+ assert(total_shmem >= 0 && total_shmem <= shmem_opt_list.back());
- // To Do: make it flexible and not tuned to 9KB share memory
- unsigned max_assoc = m_L1D_config.get_max_assoc();
- if (total_shmed == 0)
- m_L1D_config.set_assoc(max_assoc); // L1 is 128KB and shd=0
- else if (total_shmed > 0 && total_shmed <= 8192)
- m_L1D_config.set_assoc(0.9375 *
- max_assoc); // L1 is 120KB and shd=8KB
- else if (total_shmed > 8192 && total_shmed <= 16384)
- m_L1D_config.set_assoc(0.875 *
- max_assoc); // L1 is 112KB and shd=16KB
- else if (total_shmed > 16384 && total_shmed <= 32768)
- m_L1D_config.set_assoc(0.75 * max_assoc); // L1 is 96KB and
- // shd=32KB
- else if (total_shmed > 32768 && total_shmed <= 65536)
- m_L1D_config.set_assoc(0.5 * max_assoc); // L1 is 64KB and shd=64KB
- else if (total_shmed > 65536 && total_shmed <= gpgpu_shmem_size)
- m_L1D_config.set_assoc(0.25 * max_assoc); // L1 is 32KB and
- // shd=96KB
- else
- assert(0);
- break;
- }
- default:
- assert(0);
+ // Unified cache config is in KB. Converting to B
+ unsigned total_unified = m_L1D_config.m_unified_cache_size * 1024;
+
+ bool l1d_configured = false;
+ unsigned max_assoc = m_L1D_config.get_max_assoc();
+
+ for (std::vector<unsigned>::const_iterator it = shmem_opt_list.begin();
+ it < shmem_opt_list.end(); it++) {
+ if (total_shmem <= *it) {
+ float l1_ratio = 1 - ((float)*(it) / total_unified);
+ // make sure the ratio is between 0 and 1
+ assert(0 <= l1_ratio && l1_ratio <= 1);
+ // round to nearest instead of round down
+ m_L1D_config.set_assoc(max_assoc * l1_ratio + 0.5f);
+ l1d_configured = true;
+ break;
}
+ }
- printf("GPGPU-Sim: Reconfigure L1 cache to %uKB\n",
- m_L1D_config.get_total_size_inKB());
+ assert(l1d_configured && "no shared memory option found");
+
+ if (m_L1D_config.is_streaming()) {
+ // for streaming cache, if the whole memory is allocated
+ // to the L1 cache, then make the allocation to be on_MISS
+ // otherwise, make it ON_FILL to eliminate line allocation fails
+ // i.e. MSHR throughput is the same, independent on the L1 cache
+ // size/associativity
+ if (total_shmem == 0) {
+ m_L1D_config.set_allocation_policy(ON_MISS);
+ printf("GPGPU-Sim: Reconfigure L1 allocation to ON_MISS\n");
+ } else {
+ m_L1D_config.set_allocation_policy(ON_FILL);
+ printf("GPGPU-Sim: Reconfigure L1 allocation to ON_FILL\n");
+ }
}
+ printf("GPGPU-Sim: Reconfigure L1 cache to %uKB\n",
+ m_L1D_config.get_total_size_inKB());
k.cache_config_set = true;
}
@@ -3867,15 +3979,26 @@ void opndcoll_rfu_t::init(unsigned num_banks, shader_core_ctx *shader) {
assert((m_bank_warp_shift == 5) || (m_warp_size != 32));
sub_core_model = shader->get_config()->sub_core_model;
- m_num_warp_sceds = shader->get_config()->gpgpu_num_sched_per_core;
- if (sub_core_model)
+ m_num_warp_scheds = shader->get_config()->gpgpu_num_sched_per_core;
+ unsigned reg_id;
+ if (sub_core_model) {
assert(num_banks % shader->get_config()->gpgpu_num_sched_per_core == 0);
+ assert(m_num_warp_scheds <= m_cu.size() &&
+ m_cu.size() % m_num_warp_scheds == 0);
+ }
m_num_banks_per_sched =
num_banks / shader->get_config()->gpgpu_num_sched_per_core;
for (unsigned j = 0; j < m_cu.size(); j++) {
+ if (sub_core_model) {
+ unsigned cusPerSched = m_cu.size() / m_num_warp_scheds;
+ reg_id = j / cusPerSched;
+ }
m_cu[j]->init(j, num_banks, m_bank_warp_shift, shader->get_config(), this,
- sub_core_model, m_num_banks_per_sched);
+ sub_core_model, reg_id, m_num_banks_per_sched);
+ }
+ for (unsigned j = 0; j < m_dispatch_units.size(); j++) {
+ m_dispatch_units[j].init(sub_core_model,m_num_warp_scheds);
}
m_initialized = true;
}
@@ -3974,7 +4097,22 @@ void opndcoll_rfu_t::allocate_cu(unsigned port_num) {
for (unsigned j = 0; j < inp.m_cu_sets.size(); j++) {
std::vector<collector_unit_t> &cu_set = m_cus[inp.m_cu_sets[j]];
bool allocated = false;
- for (unsigned k = 0; k < cu_set.size(); k++) {
+ unsigned cuLowerBound = 0;
+ unsigned cuUpperBound = cu_set.size();
+ unsigned schd_id;
+ if (sub_core_model) {
+ // Sub core model only allocates on the subset of CUs assigned to the
+ // scheduler that issued
+ unsigned reg_id = (*inp.m_in[i]).get_ready_reg_id();
+ schd_id = (*inp.m_in[i]).get_schd_id(reg_id);
+ assert(cu_set.size() % m_num_warp_scheds == 0 &&
+ cu_set.size() >= m_num_warp_scheds);
+ unsigned cusPerSched = cu_set.size() / m_num_warp_scheds;
+ cuLowerBound = schd_id * cusPerSched;
+ cuUpperBound = cuLowerBound + cusPerSched;
+ assert(0 <= cuLowerBound && cuUpperBound <= cu_set.size());
+ }
+ for (unsigned k = cuLowerBound; k < cuUpperBound; k++) {
if (cu_set[k].is_free()) {
collector_unit_t *cu = &cu_set[k];
allocated = cu->allocate(inp.m_in[i], inp.m_out[i]);
@@ -3984,8 +4122,9 @@ void opndcoll_rfu_t::allocate_cu(unsigned port_num) {
}
if (allocated) break; // cu has been allocated, no need to search more.
}
- break; // can only service a single input, if it failed it will fail for
- // others.
+ // break; // can only service a single input, if it failed it will fail
+ // for
+ // others.
}
}
}
@@ -4032,7 +4171,8 @@ void opndcoll_rfu_t::allocate_reads() {
}
bool opndcoll_rfu_t::collector_unit_t::ready() const {
- return (!m_free) && m_not_ready.none() && (*m_output_register).has_free();
+ return (!m_free) && m_not_ready.none() &&
+ (*m_output_register).has_free(m_sub_core_model, m_reg_id);
}
void opndcoll_rfu_t::collector_unit_t::dump(
@@ -4050,12 +4190,10 @@ void opndcoll_rfu_t::collector_unit_t::dump(
}
}
-void opndcoll_rfu_t::collector_unit_t::init(unsigned n, unsigned num_banks,
- unsigned log2_warp_size,
- const core_config *config,
- opndcoll_rfu_t *rfu,
- bool sub_core_model,
- unsigned banks_per_sched) {
+void opndcoll_rfu_t::collector_unit_t::init(
+ unsigned n, unsigned num_banks, unsigned log2_warp_size,
+ const core_config *config, opndcoll_rfu_t *rfu, bool sub_core_model,
+ unsigned reg_id, unsigned banks_per_sched) {
m_rfu = rfu;
m_cuid = n;
m_num_banks = num_banks;
@@ -4063,6 +4201,7 @@ void opndcoll_rfu_t::collector_unit_t::init(unsigned n, unsigned num_banks,
m_warp = new warp_inst_t(config);
m_bank_warp_shift = log2_warp_size;
m_sub_core_model = sub_core_model;
+ m_reg_id = reg_id;
m_num_banks_per_sched = banks_per_sched;
}
@@ -4097,8 +4236,7 @@ bool opndcoll_rfu_t::collector_unit_t::allocate(register_set *pipeline_reg_set,
void opndcoll_rfu_t::collector_unit_t::dispatch() {
assert(m_not_ready.none());
- // move_warp(*m_output_register,m_warp);
- m_output_register->move_in(m_warp);
+ m_output_register->move_in(m_sub_core_model, m_reg_id, m_warp);
m_free = true;
m_output_register = NULL;
for (unsigned i = 0; i < MAX_REG_OPERANDS * 2; i++) m_src_op[i].reset();
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 6481790..f2fac12 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -238,7 +238,10 @@ class shd_warp_t {
unsigned get_dynamic_warp_id() const { return m_dynamic_warp_id; }
unsigned get_warp_id() const { return m_warp_id; }
- class shader_core_ctx * get_shader() { return m_shader; }
+ class shader_core_ctx *get_shader() {
+ return m_shader;
+ }
+
private:
static const unsigned IBUFFER_SIZE = 2;
class shader_core_ctx *m_shader;
@@ -318,6 +321,7 @@ enum concrete_scheduler {
CONCRETE_SCHEDULER_LRR = 0,
CONCRETE_SCHEDULER_GTO,
CONCRETE_SCHEDULER_TWO_LEVEL_ACTIVE,
+ CONCRETE_SCHEDULER_RRR,
CONCRETE_SCHEDULER_WARP_LIMITING,
CONCRETE_SCHEDULER_OLDEST_FIRST,
NUM_CONCRETE_SCHEDULERS
@@ -369,6 +373,12 @@ class scheduler_unit { // this can be copied freely, so can be used in std
const typename std::vector<T> &input_list,
const typename std::vector<T>::const_iterator &last_issued_from_input,
unsigned num_warps_to_add);
+ template <typename T>
+ void order_rrr(
+ typename std::vector<T> &result_list,
+ const typename std::vector<T> &input_list,
+ const typename std::vector<T>::const_iterator &last_issued_from_input,
+ unsigned num_warps_to_add);
enum OrderingType {
// The item that issued last is prioritized first then the sorted result
@@ -427,6 +437,8 @@ class scheduler_unit { // this can be copied freely, so can be used in std
register_set *m_tensor_core_out;
register_set *m_mem_out;
std::vector<register_set *> &m_spec_cores_out;
+ unsigned m_num_issued_last_cycle;
+ unsigned m_current_turn_warp;
int m_id;
};
@@ -450,6 +462,25 @@ class lrr_scheduler : public scheduler_unit {
}
};
+class rrr_scheduler : public scheduler_unit {
+ public:
+ rrr_scheduler(shader_core_stats *stats, shader_core_ctx *shader,
+ Scoreboard *scoreboard, simt_stack **simt,
+ std::vector<shd_warp_t *> *warp, register_set *sp_out,
+ register_set *dp_out, register_set *sfu_out,
+ register_set *int_out, register_set *tensor_core_out,
+ std::vector<register_set *> &spec_cores_out,
+ register_set *mem_out, int id)
+ : scheduler_unit(stats, shader, scoreboard, simt, warp, sp_out, dp_out,
+ sfu_out, int_out, tensor_core_out, spec_cores_out,
+ mem_out, id) {}
+ virtual ~rrr_scheduler() {}
+ virtual void order_warps();
+ virtual void done_adding_supervised_warps() {
+ m_last_supervised_issued = m_supervised_warps.end();
+ }
+};
+
class gto_scheduler : public scheduler_unit {
public:
gto_scheduler(shader_core_stats *stats, shader_core_ctx *shader,
@@ -878,11 +909,13 @@ class opndcoll_rfu_t { // operand collector based register file unit
}
unsigned get_sp_op() const { return m_warp->sp_op; }
unsigned get_id() const { return m_cuid; } // returns CU hw id
+ unsigned get_reg_id() const { return m_reg_id; }
// modifiers
void init(unsigned n, unsigned num_banks, unsigned log2_warp_size,
const core_config *config, opndcoll_rfu_t *rfu,
- bool m_sub_core_model, unsigned num_banks_per_sched);
+ bool m_sub_core_model, unsigned reg_id,
+ unsigned num_banks_per_sched);
bool allocate(register_set *pipeline_reg, register_set *output_reg);
void collect_operand(unsigned op) { m_not_ready.reset(op); }
@@ -906,6 +939,7 @@ class opndcoll_rfu_t { // operand collector based register file unit
unsigned m_num_banks_per_sched;
bool m_sub_core_model;
+ unsigned m_reg_id; // if sub_core_model enabled, limit regs this cu can r/w
};
class dispatch_unit_t {
@@ -916,13 +950,44 @@ class opndcoll_rfu_t { // operand collector based register file unit
m_num_collectors = (*cus).size();
m_next_cu = 0;
}
+ void init(bool sub_core_model, unsigned num_warp_scheds) {
+ m_sub_core_model = sub_core_model;
+ m_num_warp_scheds = num_warp_scheds;
+ if (m_sub_core_model) {
+ m_last_cu_set = new unsigned(m_num_warp_scheds);
+ for (unsigned i = 0; i < m_num_warp_scheds; i++)
+ {
+ m_last_cu_set[i] = i * m_num_collectors / m_num_warp_scheds;
+ }
+ }
+
+ }
collector_unit_t *find_ready() {
- for (unsigned n = 0; n < m_num_collectors; n++) {
- unsigned c = (m_last_cu + n + 1) % m_num_collectors;
- if ((*m_collector_units)[c].ready()) {
- m_last_cu = c;
- return &((*m_collector_units)[c]);
+ if (m_sub_core_model) {
+ assert(m_num_collectors % m_num_warp_scheds == 0 &&
+ m_num_collectors >= m_num_warp_scheds);
+ unsigned cusPerSched = m_num_collectors / m_num_warp_scheds;
+ for (unsigned i = 0; i < m_num_warp_scheds; i++) {
+ unsigned cuLowerBound = i * cusPerSched;
+ unsigned cuUpperBound = cuLowerBound + cusPerSched;
+ assert(0 <= cuLowerBound && cuUpperBound <= m_num_collectors);
+ assert(cuLowerBound <= m_last_cu_set[i] && m_last_cu_set[i] <= cuUpperBound);
+ for (unsigned j = cuLowerBound; j < cuUpperBound; j++) {
+ unsigned c = cuLowerBound + (m_last_cu_set[i] + j + 1) % cusPerSched;
+ if ((*m_collector_units)[c].ready()) {
+ m_last_cu_set[i] = c;
+ return &((*m_collector_units)[c]);
+ }
+ }
+ }
+ } else {
+ for (unsigned n = 0; n < m_num_collectors; n++) {
+ unsigned c = (m_last_cu + n + 1) % m_num_collectors;
+ if ((*m_collector_units)[c].ready()) {
+ m_last_cu = c;
+ return &((*m_collector_units)[c]);
+ }
}
}
return NULL;
@@ -932,7 +997,11 @@ class opndcoll_rfu_t { // operand collector based register file unit
unsigned m_num_collectors;
std::vector<collector_unit_t> *m_collector_units;
unsigned m_last_cu; // dispatch ready cu's rr
+ unsigned *m_last_cu_set;
unsigned m_next_cu; // for initialization
+
+ bool m_sub_core_model;
+ unsigned m_num_warp_scheds;
};
// opndcoll_rfu_t data members
@@ -947,7 +1016,7 @@ class opndcoll_rfu_t { // operand collector based register file unit
arbiter_t m_arbiter;
unsigned m_num_banks_per_sched;
- unsigned m_num_warp_sceds;
+ unsigned m_num_warp_scheds;
bool sub_core_model;
// unsigned m_num_ports;
@@ -1039,10 +1108,7 @@ class simd_function_unit {
~simd_function_unit() { delete m_dispatch_reg; }
// modifiers
- virtual void issue(register_set &source_reg) {
- source_reg.move_out_to(m_dispatch_reg);
- occupied.set(m_dispatch_reg->latency);
- }
+ virtual void issue(register_set &source_reg);
virtual void cycle() = 0;
virtual void active_lanes_in_pipeline() = 0;
@@ -1051,6 +1117,8 @@ class simd_function_unit {
virtual bool can_issue(const warp_inst_t &inst) const {
return m_dispatch_reg->empty() && !occupied.test(inst.latency);
}
+ virtual bool is_issue_partitioned() = 0;
+ virtual unsigned get_issue_reg_id() = 0;
virtual bool stallable() const = 0;
virtual void print(FILE *fp) const {
fprintf(fp, "%s dispatch= ", m_name.c_str());
@@ -1070,7 +1138,7 @@ class pipelined_simd_unit : public simd_function_unit {
public:
pipelined_simd_unit(register_set *result_port,
const shader_core_config *config, unsigned max_latency,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
// modifiers
virtual void cycle();
@@ -1091,6 +1159,8 @@ class pipelined_simd_unit : public simd_function_unit {
virtual bool can_issue(const warp_inst_t &inst) const {
return simd_function_unit::can_issue(inst);
}
+ virtual bool is_issue_partitioned() = 0;
+ unsigned get_issue_reg_id() { return m_issue_reg_id; }
virtual void print(FILE *fp) const {
simd_function_unit::print(fp);
for (int s = m_pipeline_depth - 1; s >= 0; s--) {
@@ -1106,6 +1176,8 @@ class pipelined_simd_unit : public simd_function_unit {
warp_inst_t **m_pipeline_reg;
register_set *m_result_port;
class shader_core_ctx *m_core;
+ unsigned m_issue_reg_id; // if sub_core_model is enabled we can only issue
+ // from a subset of operand collectors
unsigned active_insts_in_pipeline;
};
@@ -1113,7 +1185,7 @@ class pipelined_simd_unit : public simd_function_unit {
class sfu : public pipelined_simd_unit {
public:
sfu(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
switch (inst.op) {
case SFU_OP:
@@ -1129,12 +1201,13 @@ class sfu : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
};
class dp_unit : public pipelined_simd_unit {
public:
dp_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
switch (inst.op) {
case DP_OP:
@@ -1146,12 +1219,13 @@ class dp_unit : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
};
class tensor_core : public pipelined_simd_unit {
public:
tensor_core(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
switch (inst.op) {
case TENSOR_CORE_OP:
@@ -1163,12 +1237,13 @@ class tensor_core : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
};
class int_unit : public pipelined_simd_unit {
public:
int_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
switch (inst.op) {
case SFU_OP:
@@ -1194,12 +1269,13 @@ class int_unit : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
};
class sp_unit : public pipelined_simd_unit {
public:
sp_unit(register_set *result_port, const shader_core_config *config,
- shader_core_ctx *core);
+ shader_core_ctx *core, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
switch (inst.op) {
case SFU_OP:
@@ -1223,13 +1299,14 @@ class sp_unit : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
};
class specialized_unit : public pipelined_simd_unit {
public:
specialized_unit(register_set *result_port, const shader_core_config *config,
shader_core_ctx *core, unsigned supported_op,
- char *unit_name, unsigned latency);
+ char *unit_name, unsigned latency, unsigned issue_reg_id);
virtual bool can_issue(const warp_inst_t &inst) const {
if (inst.op != m_supported_op) {
return false;
@@ -1238,6 +1315,7 @@ class specialized_unit : public pipelined_simd_unit {
}
virtual void active_lanes_in_pipeline();
virtual void issue(register_set &source_reg);
+ bool is_issue_partitioned() { return true; }
private:
unsigned m_supported_op;
@@ -1259,6 +1337,7 @@ class ldst_unit : public pipelined_simd_unit {
// modifiers
virtual void issue(register_set &inst);
+ bool is_issue_partitioned() { return false; }
virtual void cycle();
void fill(mem_fetch *mf);
@@ -1479,6 +1558,17 @@ class shader_core_config : public core_config {
} else
break; // we only accept continuous specialized_units, i.e., 1,2,3,4
}
+
+ // parse gpgpu_shmem_option for adpative cache config
+ if (adaptive_cache_config) {
+ std::stringstream ss(gpgpu_shmem_option);
+ while (ss.good()) {
+ std::string option;
+ std::getline(ss, option, ',');
+ shmem_opt_list.push_back((unsigned)std::stoi(option) * 1024);
+ }
+ std::sort(shmem_opt_list.begin(), shmem_opt_list.end());
+ }
}
void reg_options(class OptionParser *opp);
unsigned max_cta(const kernel_info_t &k) const;
@@ -1856,6 +1946,12 @@ class shader_core_mem_fetch_allocator : public mem_fetch_allocator {
}
mem_fetch *alloc(new_addr_type addr, mem_access_type type, unsigned size,
bool wr, unsigned long long cycle) const;
+ mem_fetch *alloc(new_addr_type addr, mem_access_type type,
+ const active_mask_t &active_mask,
+ const mem_access_byte_mask_t &byte_mask,
+ const mem_access_sector_mask_t &sector_mask, unsigned size,
+ bool wr, unsigned long long cycle, unsigned wid,
+ unsigned sid, unsigned tpc, mem_fetch *original_mf) const;
mem_fetch *alloc(const warp_inst_t &inst, const mem_access_t &access,
unsigned long long cycle) const {
warp_inst_t inst_copy = inst;
@@ -2133,8 +2229,8 @@ class shader_core_ctx : public core_t {
friend class TwoLevelScheduler;
friend class LooseRoundRobbinScheduler;
virtual void issue_warp(register_set &warp, const warp_inst_t *pI,
- const active_mask_t &active_mask, unsigned warp_id,
- unsigned sch_id);
+ const active_mask_t &active_mask, unsigned warp_id,
+ unsigned sch_id);
void create_front_pipeline();
void create_schedulers();