summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/tested-cfgs/SM75_RTX2060/gpgpusim.config2
-rw-r--r--configs/tested-cfgs/SM7_QV100/gpgpusim.config6
-rw-r--r--configs/tested-cfgs/SM7_TITANV/gpgpusim.config3
-rw-r--r--src/abstract_hardware_model.h9
-rw-r--r--src/gpgpu-sim/gpu-cache.cc193
-rw-r--r--src/gpgpu-sim/gpu-cache.h120
-rw-r--r--src/gpgpu-sim/gpu-sim.cc7
-rw-r--r--src/gpgpu-sim/l2cache.cc129
-rw-r--r--src/gpgpu-sim/l2cache.h6
-rw-r--r--src/gpgpu-sim/shader.cc124
-rw-r--r--src/gpgpu-sim/shader.h6
11 files changed, 447 insertions, 158 deletions
diff --git a/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config b/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config
index 6189dca..d7573ab 100644
--- a/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config
+++ b/configs/tested-cfgs/SM75_RTX2060/gpgpusim.config
@@ -100,6 +100,8 @@
# <nsets>:<bsize>:<assoc>,<rep>:<wr>:<alloc>:<wr_alloc>:<set_index_fn>,<mshr>:<N>:<merge>,<mq>:**<fifo_entry>
# ** Optional parameter - Required when mshr_type==Texture Fifo
-gpgpu_adaptive_cache_config 0
+-gpgpu_shmem_option 0,8,16,32,64,100
+-gpgpu_unified_l1d_size 128
-gpgpu_l1_banks 4
-gpgpu_cache:dl1 S:1:128:512,L:L:m:N:L,A:512:8,16:0,32
-gpgpu_shmem_size 65536
diff --git a/configs/tested-cfgs/SM7_QV100/gpgpusim.config b/configs/tested-cfgs/SM7_QV100/gpgpusim.config
index bc5677c..59c7f43 100644
--- a/configs/tested-cfgs/SM7_QV100/gpgpusim.config
+++ b/configs/tested-cfgs/SM7_QV100/gpgpusim.config
@@ -124,6 +124,9 @@
-gpgpu_l1_latency 20
-gpgpu_smem_latency 20
-gpgpu_flush_l1_cache 1
+-gpgpu_l1_cache_write_ratio 25
+-gpgpu_shmem_option 0,12,24,48,96
+-gpgpu_unified_l1d_size 128
# 32 sets, each 128 bytes 24-way for each memory sub partition (96 KB per memory sub partition). This gives us 6MB L2 cache
-gpgpu_cache:dl2 S:32:128:24,L:B:m:L:P,A:192:4,32:0,32
@@ -201,5 +204,4 @@
# tracing functionality
#-trace_enabled 1
#-trace_components WARP_SCHEDULER,SCOREBOARD
-#-trace_sampling_core 0
-
+#-trace_sampling_core 0 \ No newline at end of file
diff --git a/configs/tested-cfgs/SM7_TITANV/gpgpusim.config b/configs/tested-cfgs/SM7_TITANV/gpgpusim.config
index 3af314c..32245d7 100644
--- a/configs/tested-cfgs/SM7_TITANV/gpgpusim.config
+++ b/configs/tested-cfgs/SM7_TITANV/gpgpusim.config
@@ -125,6 +125,9 @@
-gpgpu_l1_latency 20
-gpgpu_smem_latency 20
-gpgpu_flush_l1_cache 1
+-gpgpu_l1_cache_write_ratio 25
+-gpgpu_shmem_option 0,12,24,48,96
+-gpgpu_unified_l1d_size 128
# 32 sets, each 128 bytes 24-way for each memory sub partition (96 KB per memory sub partition). This gives us 4.5MB L2 cache
-gpgpu_cache:dl2 S:32:128:24,L:B:m:L:P,A:192:4,32:0,32
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 982e416..17a1cec 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
@@ -373,6 +373,7 @@ class core_config {
}
unsigned mem_warp_parts;
mutable unsigned gpgpu_shmem_size;
+ char *gpgpu_shmem_option;
unsigned gpgpu_shmem_sizeDefault;
unsigned gpgpu_shmem_sizePrefL1;
unsigned gpgpu_shmem_sizePrefShared;
@@ -869,6 +870,12 @@ 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) const = 0;
};
// the maximum number of destination, source, or address uarch operands in a
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index c6a125d..297a94c 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -210,6 +210,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 +232,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 +251,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 +263,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 +279,29 @@ 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 (!line->is_modified_line() ||
+ dirty_line_percentage >= m_config.m_wr_percent) {
+ // if number of dirty lines in the cache is greater than
+ // a specific value
+ 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;
+ }
}
}
}
@@ -331,7 +340,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++;
@@ -344,8 +353,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());
@@ -356,8 +369,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:
@@ -374,31 +391,40 @@ 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());
+ m_lines[index]->fill(time, mf->get_access_sector_mask(), mf->get_access_byte_mask());
+ m_dirty++;
}
// TODO: we need write back the flushed data to the upper level
@@ -407,10 +433,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;
}
@@ -421,6 +449,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;
}
@@ -764,7 +793,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];
}
}
@@ -1050,7 +1081,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);
+ m_tag_array->fill(e->second.m_block_addr, time, mf, mf->is_write());
} else
abort();
bool has_atomic = false;
@@ -1058,9 +1089,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);
@@ -1163,7 +1198,11 @@ 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);
return HIT;
}
@@ -1182,7 +1221,11 @@ 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);
// generate a write-through
send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
@@ -1292,8 +1335,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);
// 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);
@@ -1330,7 +1375,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());
@@ -1339,8 +1388,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);
// 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);
@@ -1401,6 +1452,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));
@@ -1409,8 +1461,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);
// 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);
@@ -1428,16 +1482,39 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read(
new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time,
std::list<cache_event> &events, enum cache_request_status status) {
new_addr_type block_addr = m_config.block_addr(addr);
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
// if the request writes to the whole cache line/sector, then, write and set
// cache line Modified. and no need to send read request to memory or reserve
// mshr
- if (miss_queue_full(0)) {
- m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
- return RESERVATION_FAIL; // cannot handle request this cycle
+ // Write allocate, maximum 2 requests (write miss, write back request)
+ // Conservatively ensure the worst-case request can be handled this
+ // cycle
+ if (m_config.m_write_policy == WRITE_THROUGH) {
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
+ if (miss_queue_full(1) ||
+ (!(mshr_hit && mshr_avail) &&
+ !(!mshr_hit && mshr_avail &&
+ (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
+ // check what is the exactly the failure reason
+ if (miss_queue_full(1))
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ else if (mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
+
+ return RESERVATION_FAIL;
+ }
+
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
}
+
bool wb = false;
evicted_block_info evicted;
@@ -1445,11 +1522,15 @@ 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());
- } else {
- block->set_status(MODIFIED, mf->get_access_sector_mask());
+ block->set_byte_mask_on_fill(true);
}
if (mf->get_access_byte_mask().count() == m_config.get_atom_sz()) {
@@ -1465,8 +1546,10 @@ enum cache_request_status data_cache::wr_miss_wa_lazy_fetch_on_read(
// (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);
// 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);
@@ -1509,8 +1592,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;
}
@@ -1541,8 +1628,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);
// 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);
@@ -1565,7 +1654,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) {
@@ -1652,7 +1741,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 b2db1c5..75dce40 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -72,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 {
@@ -109,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;
@@ -120,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;
@@ -131,6 +147,7 @@ struct cache_block_t {
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;
@@ -164,8 +181,10 @@ struct line_cache_block : public cache_block_t {
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 );
@@ -173,6 +192,7 @@ struct line_cache_block : public cache_block_t {
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;
}
@@ -189,6 +209,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_byte_mask = m_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_byte_mask = m_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_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;
}
@@ -209,6 +243,9 @@ struct line_cache_block : public cache_block_t {
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
}
@@ -231,7 +268,9 @@ struct line_cache_block : public cache_block_t {
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_byte_mask;
};
struct sector_cache_block : public cache_block_t {
@@ -251,6 +290,7 @@ struct sector_cache_block : public cache_block_t {
m_line_alloc_time = 0;
m_line_last_access_time = 0;
m_line_fill_time = 0;
+ m_byte_mask.reset();
}
virtual void allocate(new_addr_type tag, new_addr_type block_addr,
@@ -276,6 +316,7 @@ struct sector_cache_block : public cache_block_t {
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
@@ -310,18 +351,19 @@ 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;
@@ -362,6 +404,23 @@ struct sector_cache_block : public cache_block_t {
m_status[sidx] = status;
}
+ virtual void set_byte_mask(mem_fetch *mf) {
+ m_byte_mask = m_byte_mask | mf->get_access_byte_mask();
+ }
+ virtual void set_byte_mask(mem_access_byte_mask_t byte_mask) {
+ m_byte_mask = m_byte_mask | byte_mask;
+ }
+ virtual mem_access_byte_mask_t get_dirty_byte_mask() {
+ return m_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;
}
@@ -387,6 +446,9 @@ 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) {
@@ -428,7 +490,9 @@ struct sector_cache_block : public cache_block_t {
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_byte_mask;
unsigned get_sector_index(mem_access_sector_mask_t sector_mask) {
assert(sector_mask.count() == 1);
@@ -491,6 +555,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;
@@ -498,10 +563,10 @@ class cache_config {
char ct, rp, wp, ap, mshr_type, wap, sif;
int ntok =
- sscanf(config, "%c:%u:%u:%u,%c:%c:%c:%c:%c,%c:%u:%u,%u:%u,%u", &ct,
+ sscanf(config, "%c:%u:%u:%u,%c:%c:%c:%c:%c,%c:%u:%u,%u:%u,%u,%u", &ct,
&m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, &wap, &sif,
&mshr_type, &m_mshr_entries, &m_mshr_max_merge,
- &m_miss_queue_size, &m_result_fifo_entries, &m_data_port_width);
+ &m_miss_queue_size, &m_result_fifo_entries, &m_data_port_width, &m_wr_percent);
if (ntok < 12) {
if (!strcmp(config, "none")) {
@@ -511,6 +576,14 @@ class cache_config {
exit_parse_error();
}
+ // set * assoc * cacheline size. Then convert Byte to KB
+ unsigned original_size = m_nset * m_assoc * m_line_sz / 1024;
+ if (m_unified_cache_size > 0) {
+ max_cache_multiplier = m_unified_cache_size / original_size;
+ } else {
+ max_cache_multiplier = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER;
+ }
+
switch (ct) {
case 'N':
m_cache_type = NORMAL;
@@ -620,6 +693,7 @@ class cache_config {
m_sector_sz_log2 = LOGB2(SECTOR_SIZE);
original_m_assoc = m_assoc;
+
// For more details about difference between FETCH_ON_WRITE and WRITE
// VALIDAE policies Read: Jouppi, Norman P. "Cache write policies and
// performance". ISCA 93. WRITE_ALLOCATE is the old write policy in
@@ -711,11 +785,13 @@ class cache_config {
}
unsigned get_max_num_lines() const {
assert(m_valid);
- return MAX_DEFAULT_CACHE_SIZE_MULTIBLIER * m_nset * original_m_assoc;
+ // gpgpu_unified_cache_size is in KB while original_sz is in B
+ return 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;
+ // gpgpu_unified_cache_size is in KB while original_sz is in B
+ return 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",
@@ -765,6 +841,14 @@ class cache_config {
char *m_config_stringPrefL1;
char *m_config_stringPrefShared;
FuncCache cache_status;
+ unsigned m_wr_percent;
+ unsigned m_unified_cache_size;
+ 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() {
@@ -784,6 +868,7 @@ class cache_config {
unsigned m_sector_sz_log2;
unsigned original_m_assoc;
bool m_is_streaming;
+ unsigned max_cache_multiplier;
enum replacement_policy_t m_replacement_policy; // 'L' = LRU, 'F' = FIFO
enum write_policy_t
@@ -812,6 +897,7 @@ class cache_config {
unsigned m_data_port_width; //< number of byte the cache can access per cycle
enum set_index_function
m_set_index_function; // Hash, linear, or custom set index function
+ unsigned m_wr_percent;
friend class tag_array;
friend class baseline_cache;
@@ -857,9 +943,11 @@ 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,
+ bool is_write,
bool probe_mode = false,
mem_fetch *mf = NULL) const;
enum cache_request_status access(new_addr_type addr, unsigned time,
@@ -868,9 +956,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]; }
@@ -888,6 +977,9 @@ 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
@@ -908,6 +1000,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
@@ -1253,7 +1346,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:
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index fd36e00..df30047 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -249,6 +249,7 @@ 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,6 +327,12 @@ 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_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(
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index ab6e5c2..00b14d7 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -57,6 +57,20 @@ 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) 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, -1,
+ -1, -1, m_memory_config, cycle);
+ return mf;
+}
memory_partition_unit::memory_partition_unit(unsigned partition_id,
const memory_config *config,
class memory_stats_t *stats,
@@ -541,10 +555,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,53 +713,48 @@ 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) {
- start = 0;
- end = 3;
- } else if (mf->get_data_size() == 64 &&
- mf->get_access_sector_mask().to_string() == "1100") {
- 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;
+ } else if (mf->get_data_size() == 128) {
+ // 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);
}
- } 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");
- }
+ 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() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), m_gpu->gpgpu_ctx);
- 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);
+ 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);
- for (unsigned j = start, i = 0; j <= end; ++j, ++i) {
+ result.push_back(n_mf);
+ }
+ } else if (mf->get_data_size() == 64 &&
+ (mf->get_access_sector_mask().to_string() == "1111" ||
+ mf->get_access_sector_mask().to_string() == "0000")) {
+ unsigned start;
+ if (mf->get_addr() % 128 == 0)
+ start = 0;
+ else
+ start = 2;
+ 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);
+ }
const mem_access_t *ma = new mem_access_t(
- mf->get_access_type(), mf->get_addr() + SECTOR_SIZE * i, SECTOR_SIZE,
+ mf->get_access_type(), mf->get_addr(), 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);
+ mf->get_access_byte_mask() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), m_gpu->gpgpu_ctx);
mem_fetch *n_mf =
new mem_fetch(*ma, NULL, mf->get_ctrl_size(), mf->get_wid(),
@@ -748,17 +762,30 @@ memory_sub_partition::breakdown_request_to_sector_requests(mem_fetch *mf) {
m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, 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);
+ }
+ 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() & mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(i), 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);
+
+ 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..1f5d7c4 100644
--- a/src/gpgpu-sim/l2cache.h
+++ b/src/gpgpu-sim/l2cache.h
@@ -51,6 +51,12 @@ 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) const;
private:
const memory_config *m_memory_config;
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 2513dde..db53fca 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -61,6 +61,21 @@ 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) 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, -1,
+ m_core_id, m_cluster_id, m_memory_config, cycle);
+ return mf;
+ }
/////////////////////////////////////////////////////////////////////////////
std::list<unsigned> shader_core_ctx::get_regs_written(const inst_t &fvt) const {
@@ -1989,6 +2004,19 @@ 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;
+ }
}
}
@@ -3306,50 +3334,64 @@ 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
-
- // 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;
+ std::vector<unsigned> shmem_list;
+ for (unsigned i = 0; i < strlen(gpgpu_shmem_option); i++) {
+ char option[4];
+ int j = 0;
+ while (gpgpu_shmem_option[i] != ',' && i < strlen(gpgpu_shmem_option)) {
+ if (gpgpu_shmem_option[i] == ' ') {
+ // skip spaces
+ i++;
+ } else {
+ if (!isdigit(gpgpu_shmem_option[i])) {
+ // check for non digits, which should not be here
+ assert(0 && "invalid config: -gpgpu_shmem_option");
+ }
+ option[j] = gpgpu_shmem_option[i];
+ j++;
+ i++;
}
- default:
- assert(0);
}
+ // convert KB -> B
+ shmem_list.push_back((unsigned)atoi(option) * 1024);
+ }
+
+ unsigned total_shmem = kernel_info->smem * result;
+ // Unified cache config is in KB. Converting to B
+ unsigned total_unified = m_L1D_config.m_unified_cache_size * 1024;
+ std::sort(shmem_list.begin(), shmem_list.end());
+
+ assert(total_shmem >= 0 && total_shmem <= shmem_list.back());
+ switch (adaptive_cache_config) {
+ case FIXED:
+ break;
+ case ADAPTIVE_CACHE: {
+ // For more info about adaptive cache, see
+ bool l1d_configured = false;
+ unsigned max_assoc = m_L1D_config.get_max_assoc();
- printf("GPGPU-Sim: Reconfigure L1 cache to %uKB\n",
- m_L1D_config.get_total_size_inKB());
+ if (total_shmem == 0) {
+ m_L1D_config.set_assoc(max_assoc);
+ l1d_configured = true;
+ } else {
+ for (std::vector<unsigned>::iterator it = shmem_list.begin();
+ it < shmem_list.end() - 1; it++) {
+ if (total_shmem > *it && total_shmem <= *(it + 1)) {
+ float l1_ratio = 1 - (float) *(it + 1) / total_unified;
+ m_L1D_config.set_assoc(max_assoc * l1_ratio);
+ l1d_configured = true;
+ break;
+ }
+ }
+ }
+ assert(l1d_configured && "no shared memory option found");
+ break;
+ }
+ default:
+ assert(0);
}
+<<<<<<< HEAD
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
@@ -3364,6 +3406,10 @@ unsigned int shader_core_config::max_cta(const kernel_info_t &k) const {
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());
+>>>>>>> 2b2b6a2916e4ed833c707be887bf927167a71fa6
k.cache_config_set = true;
}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 8c02fd7..a7a2c02 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -1872,6 +1872,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) 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;