summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavit Grigoryan <[email protected]>2026-04-27 02:10:06 +0000
committerDavit Grigoryan <[email protected]>2026-04-27 02:10:06 +0000
commit2f190971f5f952f55197d385c688667439bc6649 (patch)
tree5f9945497f9ac36ee1cbb35d6aca1dea39e6a08b
parent13d5fae1ac28988d071b4459af169e53361921d8 (diff)
add debug scoreboard stats counting
-rw-r--r--src/abstract_hardware_model.cc1
-rw-r--r--src/gpgpu-sim/gpu-sim.cc8
-rw-r--r--src/gpgpu-sim/scoreboard.cc90
-rw-r--r--src/gpgpu-sim/scoreboard.h31
-rw-r--r--src/gpgpu-sim/shader.cc10
-rw-r--r--src/gpgpu-sim/shader.h2
6 files changed, 140 insertions, 2 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index efe0e36..f8746e6 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -2493,6 +2493,7 @@ const simt_mask_t &simt_reconvergence_table::get_active_mask(unsigned num) {
return m_recvg_table[num].m_active_mask;
}
+
simt_reconvergence_table_entry simt_reconvergence_table::get_recvg_entry(
unsigned num) {
return m_recvg_table[num];
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index ca51c50..c858c50 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -1585,6 +1585,14 @@ void gpgpu_sim::gpu_print_stat(unsigned long long streamID) {
// shader_print_l1_miss_stat( stdout );
shader_print_cache_stats(stdout);
+ // Scoreboard reserve/release accounting (one line per shader). Used to
+ // detect leaks (reserves != releases or remaining > 0) and average
+ // reservation duration vs. expected memory/FU latency.
+ fprintf(statfout, "\nScoreboard accounting:\n");
+ for (unsigned i = 0; i < m_config.num_cluster(); i++) {
+ m_cluster[i]->print_scoreboard_accounting(statfout);
+ }
+
cache_stats core_cache_stats;
core_cache_stats.clear();
for (unsigned i = 0; i < m_config.num_cluster(); i++) {
diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc
index de71807..bcaea56 100644
--- a/src/gpgpu-sim/scoreboard.cc
+++ b/src/gpgpu-sim/scoreboard.cc
@@ -28,6 +28,7 @@
#include "scoreboard.h"
#include "../cuda-sim/ptx_sim.h"
+#include "gpu-sim.h"
#include "shader.h"
#include "shader_trace.h"
@@ -41,6 +42,19 @@ Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu)
sec_reg_table.resize(n_warps);
m_gpu = gpu;
+
+ m_primary_reserve_calls = 0;
+ m_primary_release_calls = 0;
+ m_sec_reserve_calls = 0;
+ m_sec_release_calls = 0;
+ m_sec_clear_calls = 0;
+ m_sec_clear_regs_dropped = 0;
+ m_primary_total_duration_cycles = 0;
+ m_primary_completed_reservations = 0;
+ m_primary_max_duration_cycles = 0;
+ m_sec_total_duration_cycles = 0;
+ m_sec_completed_reservations = 0;
+ m_sec_max_duration_cycles = 0;
}
// Print scoreboard contents
@@ -67,6 +81,9 @@ void Scoreboard::reserveRegister(unsigned wid, unsigned regnum) {
SHADER_DPRINTF(SCOREBOARD, "Reserved Register - warp:%d, reg: %d\n", wid,
regnum);
reg_table[wid].insert(regnum);
+ m_primary_reserve_calls++;
+ m_primary_resv_cycle[std::make_pair(wid, regnum)] =
+ m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
}
// Unmark register as write-pending
@@ -75,6 +92,18 @@ void Scoreboard::releaseRegister(unsigned wid, unsigned regnum) {
SHADER_DPRINTF(SCOREBOARD, "Release register - warp:%d, reg: %d\n", wid,
regnum);
reg_table[wid].erase(regnum);
+ m_primary_release_calls++;
+ auto key = std::make_pair(wid, regnum);
+ auto it = m_primary_resv_cycle.find(key);
+ if (it != m_primary_resv_cycle.end()) {
+ unsigned long long now = m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
+ unsigned long long dur = now - it->second;
+ m_primary_total_duration_cycles += dur;
+ m_primary_completed_reservations++;
+ if (dur > m_primary_max_duration_cycles)
+ m_primary_max_duration_cycles = dur;
+ m_primary_resv_cycle.erase(it);
+ }
}
const bool Scoreboard::islongop(unsigned warp_id, unsigned regnum) {
@@ -158,11 +187,28 @@ bool Scoreboard::pendingWrites(unsigned wid) const {
void Scoreboard::reserveRegisterSecondary(unsigned wid, unsigned regnum) {
// No abort on duplicate — secondary may share register names with primary
- sec_reg_table[wid].insert(regnum);
+ bool inserted = sec_reg_table[wid].insert(regnum).second;
+ if (inserted) {
+ m_sec_reserve_calls++;
+ m_sec_resv_cycle[std::make_pair(wid, regnum)] =
+ m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
+ }
}
void Scoreboard::releaseRegisterSecondary(unsigned wid, unsigned regnum) {
- sec_reg_table[wid].erase(regnum);
+ size_t n = sec_reg_table[wid].erase(regnum);
+ if (n == 0) return;
+ m_sec_release_calls++;
+ auto key = std::make_pair(wid, regnum);
+ auto it = m_sec_resv_cycle.find(key);
+ if (it != m_sec_resv_cycle.end()) {
+ unsigned long long now = m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
+ unsigned long long dur = now - it->second;
+ m_sec_total_duration_cycles += dur;
+ m_sec_completed_reservations++;
+ if (dur > m_sec_max_duration_cycles) m_sec_max_duration_cycles = dur;
+ m_sec_resv_cycle.erase(it);
+ }
}
bool Scoreboard::checkCollisionSecondary(unsigned wid,
@@ -181,5 +227,45 @@ bool Scoreboard::checkCollisionSecondary(unsigned wid,
}
void Scoreboard::clearSecondary(unsigned wid) {
+ m_sec_clear_calls++;
+ m_sec_clear_regs_dropped += sec_reg_table[wid].size();
+ // Drop in-flight duration timestamps for any regs we are dropping —
+ // these are abandoned reservations (e.g. warp completed, pipeline flush)
+ // and counting their duration would skew the histogram.
+ for (auto reg : sec_reg_table[wid])
+ m_sec_resv_cycle.erase(std::make_pair(wid, reg));
sec_reg_table[wid].clear();
}
+
+// End-of-run accounting dump.
+void Scoreboard::dumpAccounting(FILE* out) const {
+ unsigned long long primary_remaining = 0;
+ unsigned long long sec_remaining = 0;
+ for (unsigned w = 0; w < reg_table.size(); w++)
+ primary_remaining += reg_table[w].size();
+ for (unsigned w = 0; w < sec_reg_table.size(); w++)
+ sec_remaining += sec_reg_table[w].size();
+ double primary_avg_dur =
+ m_primary_completed_reservations
+ ? (double)m_primary_total_duration_cycles /
+ (double)m_primary_completed_reservations
+ : 0.0;
+ double sec_avg_dur =
+ m_sec_completed_reservations
+ ? (double)m_sec_total_duration_cycles /
+ (double)m_sec_completed_reservations
+ : 0.0;
+ fprintf(out,
+ "scoreboard_accounting sid=%u "
+ "primary: reserves=%llu releases=%llu remaining=%llu "
+ "completed=%llu avg_cycles=%.2f max_cycles=%llu "
+ "| secondary: reserves=%llu releases=%llu remaining=%llu "
+ "completed=%llu avg_cycles=%.2f max_cycles=%llu "
+ "clearSecondary=%llu regs_dropped_by_clear=%llu\n",
+ m_sid, m_primary_reserve_calls, m_primary_release_calls,
+ primary_remaining, m_primary_completed_reservations, primary_avg_dur,
+ m_primary_max_duration_cycles, m_sec_reserve_calls,
+ m_sec_release_calls, sec_remaining, m_sec_completed_reservations,
+ sec_avg_dur, m_sec_max_duration_cycles, m_sec_clear_calls,
+ m_sec_clear_regs_dropped);
+}
diff --git a/src/gpgpu-sim/scoreboard.h b/src/gpgpu-sim/scoreboard.h
index 9bf51e6..1de81dd 100644
--- a/src/gpgpu-sim/scoreboard.h
+++ b/src/gpgpu-sim/scoreboard.h
@@ -28,7 +28,9 @@
#include <stdio.h>
#include <stdlib.h>
+#include <map>
#include <set>
+#include <utility>
#include <vector>
#include "assert.h"
@@ -56,6 +58,12 @@ class Scoreboard {
bool checkCollisionSecondary(unsigned wid, const inst_t *inst) const;
void clearSecondary(unsigned wid);
+ public:
+ // Accounting / leak-detection (called from gpu-sim end-of-run dump).
+ // Aggregates reserve/release counts, reservation-duration histogram,
+ // and any registers still reserved at the end of simulation.
+ void dumpAccounting(FILE *out) const;
+
private:
void reserveRegister(unsigned wid, unsigned regnum);
int get_sid() const { return m_sid; }
@@ -72,6 +80,29 @@ class Scoreboard {
std::vector<std::set<unsigned> > sec_reg_table;
class gpgpu_t *m_gpu;
+
+ // ---- Accounting (per-shader, scalar; cheap to update) ----
+ // primary reg_table activity
+ unsigned long long m_primary_reserve_calls; // reserveRegister insertions
+ unsigned long long m_primary_release_calls; // releaseRegister erases
+ // secondary sec_reg_table activity
+ unsigned long long m_sec_reserve_calls;
+ unsigned long long m_sec_release_calls;
+ unsigned long long m_sec_clear_calls; // clearSecondary invocations
+ unsigned long long m_sec_clear_regs_dropped; // total regs cleared by clearSecondary
+ // duration tracking — sum of (release_cycle - reserve_cycle) over all completed reservations
+ unsigned long long m_primary_total_duration_cycles;
+ unsigned long long m_primary_completed_reservations;
+ unsigned long long m_primary_max_duration_cycles;
+ unsigned long long m_sec_total_duration_cycles;
+ unsigned long long m_sec_completed_reservations;
+ unsigned long long m_sec_max_duration_cycles;
+ // reservation timestamp lookup: (wid,reg) -> cycle_reserved
+ // typedef std::map<std::pair<unsigned,unsigned>, unsigned long long> resv_map_t;
+ std::map<std::pair<unsigned, unsigned>, unsigned long long>
+ m_primary_resv_cycle;
+ std::map<std::pair<unsigned, unsigned>, unsigned long long>
+ m_sec_resv_cycle;
};
#endif /* SCOREBOARD_H_ */
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 8eb3f28..a113ddb 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -6384,6 +6384,10 @@ void shader_core_ctx::print_cache_stats(FILE *fp, unsigned &dl1_accesses,
m_ldst_unit->print_cache_stats(fp, dl1_accesses, dl1_misses);
}
+void shader_core_ctx::print_scoreboard_accounting(FILE *fp) const {
+ if (m_scoreboard) m_scoreboard->dumpAccounting(fp);
+}
+
void shader_core_ctx::get_cache_stats(cache_stats &cs) {
// Adds stats from each cache to 'cs'
cs += m_L1I->get_stats(); // Get L1I stats
@@ -7363,6 +7367,12 @@ void simt_core_cluster::print_cache_stats(FILE *fp, unsigned &dl1_accesses,
}
}
+void simt_core_cluster::print_scoreboard_accounting(FILE *fp) const {
+ for (unsigned i = 0; i < m_config->n_simt_cores_per_cluster; ++i) {
+ m_core[i]->print_scoreboard_accounting(fp);
+ }
+}
+
void simt_core_cluster::get_icnt_stats(long &n_simt_to_mem,
long &n_mem_to_simt) const {
long simt_to_mem = 0;
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 1fff5e5..ce0c8c4 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -2566,6 +2566,7 @@ class shader_core_ctx : public core_t {
const shader_core_config *get_config() const { return m_config; }
void print_cache_stats(FILE *fp, unsigned &dl1_accesses,
unsigned &dl1_misses);
+ void print_scoreboard_accounting(FILE *fp) const;
void get_cache_stats(cache_stats &cs);
void get_L1I_sub_stats(struct cache_sub_stats &css) const;
@@ -3113,6 +3114,7 @@ class simt_core_cluster {
void display_pipeline(unsigned sid, FILE *fout, int print_mem, int mask);
void print_cache_stats(FILE *fp, unsigned &dl1_accesses,
unsigned &dl1_misses) const;
+ void print_scoreboard_accounting(FILE *fp) const;
void get_cache_stats(cache_stats &cs) const;
void get_L1I_sub_stats(struct cache_sub_stats &css) const;