From adb9f147e358f687b37f5bf14c68f559c7c86a79 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 20 Feb 2019 14:17:32 +0100 Subject: Distinguish between write-through cache with allocate and update only if hit. Add into cache statistic number of backing/main memory accesses. Correction of meaning and computation of the cache statistic. Signed-off-by: Pavel Pisa --- qtmips_machine/cache.cpp | 72 +++++++++++++++++++++++++++++--------- qtmips_machine/cache.h | 9 +++-- qtmips_machine/machineconfig.cpp | 4 +-- qtmips_machine/machineconfig.h | 3 +- qtmips_machine/tests/testcache.cpp | 2 +- qtmips_machine/tests/testcore.cpp | 29 +++++++++++++-- qtmips_machine/tests/tst_machine.h | 6 ++-- 7 files changed, 98 insertions(+), 27 deletions(-) (limited to 'qtmips_machine') diff --git a/qtmips_machine/cache.cpp b/qtmips_machine/cache.cpp index f32e0e5..c1e4e7b 100644 --- a/qtmips_machine/cache.cpp +++ b/qtmips_machine/cache.cpp @@ -48,6 +48,8 @@ Cache::Cache(MemoryAccess *m, const MachineConfigCache *cc, unsigned memory_acc hit_write = 0; miss_read = 0; miss_write = 0; + mem_reads = 0; + mem_writes = 0; dt = nullptr; replc.lfu = nullptr; replc.lru = nullptr; @@ -128,20 +130,27 @@ bool Cache::wword(std::uint32_t address, std::uint32_t value) { if (!cnf.enabled() || (address >= uncached_start && address <= uncached_last)) { + mem_writes++; + emit memory_writes_update(mem_writes); return mem->write_word(address, value); } std::uint32_t data; changed = access(address, &data, true, value); - if (cnf.write_policy() == MachineConfigCache::WP_TROUGH) + if (cnf.write_policy() != MachineConfigCache::WP_BACK) { + mem_writes++; + emit memory_writes_update(mem_writes); return mem->write_word(address, value); + } return changed; } std::uint32_t Cache::rword(std::uint32_t address, bool debug_access) const { if (!cnf.enabled() || (address >= uncached_start && address <= uncached_last)) { + mem_reads++; + emit memory_reads_update(mem_reads); return mem->read_word(address, debug_access); } @@ -177,20 +186,32 @@ unsigned Cache::miss() const { return miss_read + miss_write; } +unsigned Cache::memory_reads() const { + return mem_reads; +} + +unsigned Cache::memory_writes() const { + return mem_writes; +} + unsigned Cache::stalled_cycles() const { return miss_read * (access_pen_r - 1) + miss_write * (access_pen_w - 1); } double Cache::speed_improvement() const { + unsigned lookup_time; unsigned comp = hit_read + hit_write + miss_read + miss_write; if (comp == 0) return 100.0; + lookup_time = hit_read + miss_read; + if (cnf.write_policy() == MachineConfigCache::WP_BACK) + lookup_time += hit_write + miss_write; return (double)((miss_read + hit_read) * access_pen_r + (miss_write + hit_write) * access_pen_w) \ - / (double)(hit_write + hit_read + miss_read * access_pen_r + miss_write * access_pen_w) \ + / (double)(lookup_time + mem_reads * access_pen_r + mem_writes * access_pen_w) \ * 100; } -double Cache::usage_efficiency() const { +double Cache::hit_rate() const { unsigned comp = hit_read + hit_write + miss_read + miss_write; if (comp == 0) return 0.0; @@ -198,26 +219,31 @@ double Cache::usage_efficiency() const { } void Cache::reset() { - if (!cnf.enabled()) - return; - - // Set all cells to ne invalid - for (unsigned as = 0; as < cnf.associativity(); as++) - for (unsigned st = 0; st < cnf.sets(); st++) - dt[as][st].valid = false; + // Set all cells to invalid + if (cnf.enabled()) { + for (unsigned as = 0; as < cnf.associativity(); as++) + for (unsigned st = 0; st < cnf.sets(); st++) + dt[as][st].valid = false; + } // Note: we don't have to zero replacement policy data as those are zeroed when first used on invalid cell // Zero hit and miss rate hit_read = 0; hit_write = 0; miss_read = 0; miss_write = 0; + mem_reads = 0; + mem_writes = 0; // Trigger signals emit hit_update(hit()); emit miss_update(miss()); + emit memory_reads_update(memory_reads()); + emit memory_writes_update(memory_writes()); update_statistics(); - for (unsigned as = 0; as < cnf.associativity(); as++) - for (unsigned st = 0; st < cnf.sets(); st++) - emit cache_update(as, st, false, false, 0, 0); + if (cnf.enabled()) { + for (unsigned as = 0; as < cnf.associativity(); as++) + for (unsigned st = 0; st < cnf.sets(); st++) + emit cache_update(as, st, false, false, 0, 0); + } } const MachineConfigCache &Cache::config() const { @@ -262,6 +288,12 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std:: indx++; // Need to find new block if (indx >= cnf.associativity()) { + // if write through we do not need to alloecate cache line does not allocate + if (write && cnf.write_policy() == MachineConfigCache::WP_TROUGH_NOALLOC) { + miss_write++; + emit miss_update(miss()); + return false; + } // We have to kick something switch (cnf.replacement_policy()) { case MachineConfigCache::RP_RAND: @@ -319,6 +351,8 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std:: cd.data[i] = mem->read_word(base_address(tag, row) + (4*i)); change_counter++; } + mem_reads += cnf.blocks(); + emit memory_reads_update(mem_reads); } // Update replcement data @@ -338,7 +372,10 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std:: break; } case MachineConfigCache::RP_LFU: - replc.lfu[row][indx]++; + if (cd.valid) + replc.lfu[row][indx]++; + else + replc.lfu[row][indx] = 0; break; default: break; @@ -362,9 +399,12 @@ bool Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std:: void Cache::kick(unsigned associat_indx, unsigned row) const { struct cache_data &cd = dt[associat_indx][row]; - if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK) + if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK) { for (unsigned i = 0; i < cnf.blocks(); i++) mem->write_word(base_address(cd.tag, row) + (4*i), cd.data[i]); + mem_writes += cnf.blocks(); + emit memory_writes_update(mem_writes); + } cd.valid = false; cd.dirty = false; @@ -396,5 +436,5 @@ std::uint32_t Cache::base_address(std::uint32_t tag, unsigned row) const { } void Cache::update_statistics() const { - emit statistics_update(stalled_cycles(), speed_improvement(), usage_efficiency()); + emit statistics_update(stalled_cycles(), speed_improvement(), hit_rate()); } diff --git a/qtmips_machine/cache.h b/qtmips_machine/cache.h index 827631b..1500aae 100644 --- a/qtmips_machine/cache.h +++ b/qtmips_machine/cache.h @@ -57,9 +57,11 @@ public: unsigned hit() const; // Number of recorded hits unsigned miss() const; // Number of recorded misses + unsigned memory_reads() const; // Number backing/main memory reads + unsigned memory_writes() const; // Number backing/main memory writes unsigned stalled_cycles() const; // Number of wasted cycles in memory waitin statistic double speed_improvement() const; // Speed improvement in percents in comare with no used cache - double usage_efficiency() const; // Usage efficiency in percents + double hit_rate() const; // Usage efficiency in percents void reset(); // Reset whole state of cache @@ -72,8 +74,10 @@ public: signals: void hit_update(unsigned) const; void miss_update(unsigned) const; - void statistics_update(unsigned stalled_cycles, double speed_improv, double usage_effic) const; + void statistics_update(unsigned stalled_cycles, double speed_improv, double hit_rate) const; void cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data) const; + void memory_writes_update(unsigned) const; + void memory_reads_update(unsigned) const; private: MachineConfigCache cnf; @@ -95,6 +99,7 @@ private: } replc; // Data used for replacement policy mutable unsigned hit_read, miss_read, hit_write, miss_write; // Hit and miss counters + mutable unsigned mem_reads, mem_writes; // Dirrect access to memory mutable std::uint32_t change_counter; std::uint32_t debug_rword(std::uint32_t address) const; diff --git a/qtmips_machine/machineconfig.cpp b/qtmips_machine/machineconfig.cpp index 9cd6465..8a48ce1 100644 --- a/qtmips_machine/machineconfig.cpp +++ b/qtmips_machine/machineconfig.cpp @@ -54,7 +54,7 @@ using namespace machine; #define DFC_BLOCKS 1 #define DFC_ASSOC 1 #define DFC_REPLAC RP_RAND -#define DFC_WRITE WP_TROUGH +#define DFC_WRITE WP_TROUGH_NOALLOC ////////////////////////////////////////////////////////////////////////////// MachineConfigCache::MachineConfigCache() { @@ -106,7 +106,7 @@ void MachineConfigCache::preset(enum ConfigPresets p) { set_blocks(2); set_associativity(2); set_replacement_policy(RP_RAND); - set_write_policy(WP_TROUGH); + set_write_policy(WP_TROUGH_NOALLOC); break; case CP_SINGLE: case CP_PIPE_NO_HAZARD: diff --git a/qtmips_machine/machineconfig.h b/qtmips_machine/machineconfig.h index 1858a25..14676ff 100644 --- a/qtmips_machine/machineconfig.h +++ b/qtmips_machine/machineconfig.h @@ -65,7 +65,8 @@ public: }; enum WritePolicy { - WP_TROUGH, // Write trough + WP_TROUGH_NOALLOC, // Write trough + WP_TROUGH_ALLOC, // Write trough WP_BACK // Write back }; diff --git a/qtmips_machine/tests/testcache.cpp b/qtmips_machine/tests/testcache.cpp index bbe1e62..92af45f 100644 --- a/qtmips_machine/tests/testcache.cpp +++ b/qtmips_machine/tests/testcache.cpp @@ -44,7 +44,7 @@ void MachineTests::cache_data() { QTest::addColumn("miss"); MachineConfigCache cache_c; - cache_c.set_write_policy(MachineConfigCache::WP_TROUGH); + cache_c.set_write_policy(MachineConfigCache::WP_TROUGH_ALLOC); cache_c.set_enabled(true); cache_c.set_sets(8); cache_c.set_blocks(1); diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp index 65b529a..01307a5 100644 --- a/qtmips_machine/tests/testcore.cpp +++ b/qtmips_machine/tests/testcore.cpp @@ -835,7 +835,11 @@ void MachineTests::pipecore_nc_memory_tests_data() { core_memory_tests_data(); } -void MachineTests::pipecore_wt_memory_tests_data() { +void MachineTests::pipecore_wt_na_memory_tests_data() { + core_memory_tests_data(); +} + +void MachineTests::pipecore_wt_a_memory_tests_data() { core_memory_tests_data(); } @@ -863,7 +867,26 @@ void MachineTests::pipecore_nc_memory_tests() { run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); } -void MachineTests::pipecore_wt_memory_tests() { +void MachineTests::pipecore_wt_na_memory_tests() { + QFETCH(QVector, code); + QFETCH(Registers, reg_init); + QFETCH(Registers, reg_res); + QFETCH(Memory, mem_init); + QFETCH(Memory, mem_res); + MachineConfigCache cache_conf; + cache_conf.set_enabled(true); + cache_conf.set_sets(2); // Number of sets + cache_conf.set_blocks(1); // Number of blocks + cache_conf.set_associativity(2); // Degree of associativity + cache_conf.set_replacement_policy(MachineConfigCache::RP_LRU); + cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH_NOALLOC); + Cache i_cache(&mem_init, &cache_conf); + Cache d_cache(&mem_init, &cache_conf); + CorePipelined core(®_init, &i_cache, &d_cache, MachineConfig::HU_STALL_FORWARD); + run_code_fragment(core, reg_init, reg_res, mem_init, mem_res, code); +} + +void MachineTests::pipecore_wt_a_memory_tests() { QFETCH(QVector, code); QFETCH(Registers, reg_init); QFETCH(Registers, reg_res); @@ -875,7 +898,7 @@ void MachineTests::pipecore_wt_memory_tests() { cache_conf.set_blocks(1); // Number of blocks cache_conf.set_associativity(2); // Degree of associativity cache_conf.set_replacement_policy(MachineConfigCache::RP_LRU); - cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH); + cache_conf.set_write_policy(MachineConfigCache::WP_TROUGH_ALLOC); Cache i_cache(&mem_init, &cache_conf); Cache d_cache(&mem_init, &cache_conf); CorePipelined core(®_init, &i_cache, &d_cache, MachineConfig::HU_STALL_FORWARD); diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h index 0f9d753..938a9a8 100644 --- a/qtmips_machine/tests/tst_machine.h +++ b/qtmips_machine/tests/tst_machine.h @@ -91,11 +91,13 @@ private Q_SLOTS: void pipecorestall_alu_forward_data(); void singlecore_memory_tests_data(); void pipecore_nc_memory_tests_data(); - void pipecore_wt_memory_tests_data(); + void pipecore_wt_na_memory_tests_data(); + void pipecore_wt_a_memory_tests_data(); void pipecore_wb_memory_tests_data(); void singlecore_memory_tests(); void pipecore_nc_memory_tests(); - void pipecore_wt_memory_tests(); + void pipecore_wt_na_memory_tests(); + void pipecore_wt_a_memory_tests(); void pipecore_wb_memory_tests(); // Cache void cache_data(); -- cgit v1.2.3