summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormkhairy <[email protected]>2021-05-19 17:47:56 -0400
committerGitHub <[email protected]>2021-05-19 17:47:56 -0400
commit0e4f12ae3fefd6bad6175014411a6587a3898ac8 (patch)
treebd35fe5e86be921cdf5658a9abee72fb7622816c /src
parent585dcf5dc05d6343314600114ebcea8c719e7423 (diff)
parent4c354ebda2c92bb5866c20f03a254743c8ec85a3 (diff)
Merge pull request #14 from JRPan/spring-2021-all
Byte Mask + Dirty Counter + Store ACK + Cache total access fix + check sector readable only on read + rewrite L2 breakdown function
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.h6
-rw-r--r--src/gpgpu-sim/gpu-cache.cc193
-rw-r--r--src/gpgpu-sim/gpu-cache.h101
-rw-r--r--src/gpgpu-sim/l2cache.cc129
-rw-r--r--src/gpgpu-sim/l2cache.h6
-rw-r--r--src/gpgpu-sim/shader.cc28
-rw-r--r--src/gpgpu-sim/shader.h6
7 files changed, 355 insertions, 114 deletions
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 982e416..e09acdb 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -869,6 +869,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 1c36d22..98951ca 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;
+ }
}
}
}
@@ -340,7 +349,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 +362,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 +378,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 +400,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
@@ -416,10 +442,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 +458,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;
}
@@ -773,7 +802,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];
}
}
@@ -1059,7 +1090,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());
if (m_config.is_streaming()) m_tag_array->remove_pending_line(mf);
} else
abort();
@@ -1068,9 +1099,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);
@@ -1176,7 +1211,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;
}
@@ -1195,7 +1234,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);
@@ -1305,8 +1348,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);
@@ -1343,7 +1388,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());
@@ -1352,8 +1401,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);
@@ -1414,6 +1465,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));
@@ -1422,8 +1474,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);
@@ -1441,16 +1495,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;
@@ -1458,11 +1535,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()) {
@@ -1478,8 +1559,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);
@@ -1522,8 +1605,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;
}
@@ -1554,8 +1641,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);
@@ -1578,7 +1667,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) {
@@ -1665,7 +1754,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 00c09ae..dc3b39a 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);
@@ -498,10 +562,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")) {
@@ -754,6 +818,12 @@ class cache_config {
char *m_config_stringPrefL1;
char *m_config_stringPrefShared;
FuncCache cache_status;
+ 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() {
@@ -801,6 +871,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;
@@ -846,9 +917,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,
@@ -857,9 +930,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]; }
@@ -877,6 +951,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
@@ -897,6 +974,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
@@ -1242,7 +1320,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/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 14d9044..22bd8e9 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 {
@@ -1974,6 +1989,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;
+ }
}
}
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;