From ddde26b916c99078421992100849101455756415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Wed, 23 May 2018 20:23:10 +0200 Subject: Add cache statistics --- qtmips_gui/NewDialog.ui | 20 +++++++++++-- qtmips_gui/cachedock.cpp | 16 ++++++++++ qtmips_gui/cachedock.h | 3 +- qtmips_machine/cache.cpp | 65 ++++++++++++++++++++++++++++++++-------- qtmips_machine/cache.h | 10 +++++-- qtmips_machine/machineconfig.cpp | 4 +-- qtmips_machine/qtmipsmachine.cpp | 4 +-- 7 files changed, 99 insertions(+), 23 deletions(-) diff --git a/qtmips_gui/NewDialog.ui b/qtmips_gui/NewDialog.ui index 135ac83..6e6a3ec 100644 --- a/qtmips_gui/NewDialog.ui +++ b/qtmips_gui/NewDialog.ui @@ -29,7 +29,7 @@ - 0 + 2 @@ -225,7 +225,14 @@ - + + + 1 + + + 999999999 + + @@ -235,7 +242,14 @@ - + + + 1 + + + 999999999 + + diff --git a/qtmips_gui/cachedock.cpp b/qtmips_gui/cachedock.cpp index 79097b3..8e63565 100644 --- a/qtmips_gui/cachedock.cpp +++ b/qtmips_gui/cachedock.cpp @@ -17,6 +17,12 @@ CacheDock::CacheDock(QWidget *parent, const QString &type) : QDockWidget(parent) layout_top_form->addRow("Hit:", l_hit); l_miss = new QLabel("0", top_form); layout_top_form->addRow("Miss:", l_miss); + l_stalled = new QLabel("0", top_form); + layout_top_form->addRow("Memory stall cycles:", l_stalled); + l_usage = new QLabel("0.000%", top_form); + layout_top_form->addRow("Usage effectiveness:", l_usage); + l_speed = new QLabel("100%", top_form); + layout_top_form->addRow("Speed improvement:", l_speed); graphicsview = new GraphicsView(top_widget); graphicsview->setVisible(false); @@ -30,9 +36,13 @@ CacheDock::CacheDock(QWidget *parent, const QString &type) : QDockWidget(parent) void CacheDock::setup(const machine::Cache *cache) { l_hit->setText("0"); l_miss->setText("0"); + l_stalled->setText("0"); + l_usage->setText("0.000%"); + l_speed->setText("100%"); if (cache->config().enabled()) { connect(cache, SIGNAL(hit_update(uint)), this, SLOT(hit_update(uint))); connect(cache, SIGNAL(miss_update(uint)), this, SLOT(miss_update(uint))); + connect(cache, SIGNAL(statistics_update(uint,double,double)), this, SLOT(statistics_update(uint,double,double))); } top_form->setVisible(cache->config().enabled()); no_cache->setVisible(!cache->config().enabled()); @@ -51,3 +61,9 @@ void CacheDock::hit_update(unsigned val) { void CacheDock::miss_update(unsigned val) { l_miss->setText(QString::number(val)); } + +void CacheDock::statistics_update(unsigned stalled_cycles, double speed_improv, double usage_effic) { + l_stalled->setText(QString::number(stalled_cycles)); + l_usage->setText(QString::number(usage_effic, 'f', 3) + QString("%")); + l_speed->setText(QString::number(speed_improv, 'f', 0) + QString("%")); +} diff --git a/qtmips_gui/cachedock.h b/qtmips_gui/cachedock.h index 598a9c7..7e5ac44 100644 --- a/qtmips_gui/cachedock.h +++ b/qtmips_gui/cachedock.h @@ -18,12 +18,13 @@ public: private slots: void hit_update(unsigned); void miss_update(unsigned); + void statistics_update(unsigned stalled_cycles, double speed_improv, double usage_effic); private: QVBoxLayout *layout_box; QWidget *top_widget, *top_form; QFormLayout *layout_top_form; - QLabel *l_hit, *l_miss, *no_cache; + QLabel *l_hit, *l_miss, *l_stalled, *l_speed, *l_usage, *no_cache; GraphicsView *graphicsview; CacheViewScene *cachescene; }; diff --git a/qtmips_machine/cache.cpp b/qtmips_machine/cache.cpp index 753027a..acc48b1 100644 --- a/qtmips_machine/cache.cpp +++ b/qtmips_machine/cache.cpp @@ -2,11 +2,15 @@ using namespace machine; -Cache::Cache(Memory *m, const MachineConfigCache *cc) : cnf(cc) { +Cache::Cache(Memory *m, const MachineConfigCache *cc, unsigned memory_access_penalty_r, unsigned memory_access_penalty_w) : cnf(cc) { mem = m; + access_pen_r = memory_access_penalty_r; + access_pen_w = memory_access_penalty_w; // Zero hit and miss rate - hitc = 0; - missc = 0; + hit_read = 0; + hit_write = 0; + miss_read = 0; + miss_write = 0; // Skip any other initialization if cache is disabled if (!cc->enabled()) return; @@ -73,11 +77,31 @@ void Cache::sync() { } unsigned Cache::hit() const { - return hitc; + return hit_read + hit_write; } unsigned Cache::miss() const { - return missc; + return miss_read + miss_write; +} + +unsigned Cache::stalled_cycles() const { + return miss_read * (access_pen_r - 1) + miss_write * (access_pen_w - 1); +} + +double Cache::speed_improvement() const { + unsigned comp = hit_read + hit_write + miss_read + miss_write; + if (comp == 0) + return 100.0; + 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) \ + * 100; +} + +double Cache::usage_efficiency() const { + unsigned comp = hit_read + hit_write + miss_read + miss_write; + if (comp == 0) + return 0.0; + return (double)(hit_read + hit_write) / (double)comp * 100.0; } void Cache::reset() { @@ -90,11 +114,14 @@ void Cache::reset() { 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 - hitc = 0; - missc = 0; + hit_read = 0; + hit_write = 0; + miss_read = 0; + miss_write = 0; // Trigger signals - emit hit_update(hitc); - emit miss_update(missc); + emit hit_update(hit()); + emit miss_update(miss()); + 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); @@ -157,11 +184,19 @@ void Cache::access(std::uint32_t address, std::uint32_t *data, bool write, std:: // Update statistics and otherwise read from memory if (cd.valid) { - hitc++; - emit hit_update(hitc); + if (write) + hit_write++; + else + hit_read++; + emit hit_update(hit()); + update_statistics(); } else { - missc++; - emit miss_update(missc); + if (write) + miss_write++; + else + miss_read++; + emit miss_update(miss()); + update_statistics(); for (unsigned i = 0; i < cnf.blocks(); i++) cd.data[i] = mem->rword(base_address(tag, row) + (4*i)); } @@ -209,3 +244,7 @@ void Cache::kick(unsigned associat_indx, unsigned row) const { std::uint32_t Cache::base_address(std::uint32_t tag, unsigned row) const { return ((tag * cnf.blocks() * cnf.sets()) + (row * cnf.blocks())) << 2; } + +void Cache::update_statistics() const { + emit statistics_update(stalled_cycles(), speed_improvement(), usage_efficiency()); +} diff --git a/qtmips_machine/cache.h b/qtmips_machine/cache.h index d7bd967..6cf3a2c 100644 --- a/qtmips_machine/cache.h +++ b/qtmips_machine/cache.h @@ -11,7 +11,7 @@ namespace machine { class Cache : public MemoryAccess { Q_OBJECT public: - Cache(Memory *m, const MachineConfigCache *c); + Cache(Memory *m, const MachineConfigCache *c, unsigned memory_access_penalty_r = 1, unsigned memory_access_penalty_w = 1); void wword(std::uint32_t address, std::uint32_t value); std::uint32_t rword(std::uint32_t address) const; @@ -21,6 +21,9 @@ public: unsigned hit() const; // Number of recorded hits unsigned miss() const; // Number of recorded misses + 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 void reset(); // Reset whole state of cache @@ -29,11 +32,13 @@ 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 cache_update(unsigned associat, unsigned set, bool valid, bool dirty, std::uint32_t tag, const std::uint32_t *data) const; private: MachineConfigCache cnf; Memory *mem; + unsigned access_pen_r, access_pen_w; struct cache_data { bool valid, dirty; @@ -47,11 +52,12 @@ private: unsigned **lfu; // Access count } replc; // Data used for replacement policy - mutable unsigned hitc, missc; // Hit and miss counters + mutable unsigned hit_read, miss_read, hit_write, miss_write; // Hit and miss counters void access(std::uint32_t address, std::uint32_t *data, bool write, std::uint32_t value = 0) const; void kick(unsigned associat_indx, unsigned row) const; std::uint32_t base_address(std::uint32_t tag, unsigned row) const; + void update_statistics() const; }; } diff --git a/qtmips_machine/machineconfig.cpp b/qtmips_machine/machineconfig.cpp index 13a1ff2..9329795 100644 --- a/qtmips_machine/machineconfig.cpp +++ b/qtmips_machine/machineconfig.cpp @@ -284,11 +284,11 @@ bool MachineConfig::memory_write_protection() const { } unsigned MachineConfig::memory_access_time_read() const { - return mem_acc_read; + return mem_acc_read > 1 ? mem_acc_read : 1; } unsigned MachineConfig::memory_access_time_write() const { - return mem_acc_write; + return mem_acc_write > 1 ? mem_acc_write : 1; } QString MachineConfig::elf() const { diff --git a/qtmips_machine/qtmipsmachine.cpp b/qtmips_machine/qtmipsmachine.cpp index 4a2b0f2..da4516a 100644 --- a/qtmips_machine/qtmipsmachine.cpp +++ b/qtmips_machine/qtmipsmachine.cpp @@ -13,8 +13,8 @@ QtMipsMachine::QtMipsMachine(const MachineConfig &cc) : QObject(), mcnf(&cc) { regs = new Registers(); mem = new Memory(*mem_program_only); - cch_program = new Cache(mem, &cc.cache_program()); - cch_data = new Cache(mem, &cc.cache_data()); + cch_program = new Cache(mem, &cc.cache_program(), cc.memory_access_time_read(), cc.memory_access_time_write()); + cch_data = new Cache(mem, &cc.cache_data(), cc.memory_access_time_read(), cc.memory_access_time_write()); if (cc.pipelined()) cr = new CorePipelined(regs, cch_program, cch_data, cc.hazard_unit()); -- cgit v1.2.3