diff options
| -rw-r--r-- | src/abstract_hardware_model.h | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 193 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.h | 101 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 129 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.h | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 28 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 6 |
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 §or_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 §or_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 §or_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 §or_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 §or_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; |
