summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/scoreboard.h
blob: da34af5503ccb5bb8b2232d7f84e993103804d96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright (c) 2009-2011, Tor M. Aamodt, Inderpreet Singh
// The University of British Columbia
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution. Neither the name of
// The University of British Columbia nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <stdio.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <utility>
#include <vector>
#include <array>
#include "assert.h"

#ifndef SCOREBOARD_H_
#define SCOREBOARD_H_

#include "../abstract_hardware_model.h"

class Scoreboard {
 public:
  // mode: 0 = legacy (primary + secondary tables), 1 = mask-aware,
  // 2 = slot-pinned. See scoreboard_redesign_plan.md.
  Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t *gpu,
             unsigned mode = 0);

  unsigned mode() const { return m_mode; }

  void reserveRegisters(const warp_inst_t *inst);
  void releaseRegisters(const warp_inst_t *inst);
  void releaseRegister(unsigned wid, unsigned regnum);

  bool checkCollision(unsigned wid, const inst_t *inst) const;
  bool pendingWrites(unsigned wid) const;
  void printContents() const;
  const bool islongop(unsigned warp_id, unsigned regnum);

  // Secondary scoreboard for intra-warp co-issue (split-level tracking).
  // Mode 0 (legacy) only — bypassed under modes 1 and 2.
  void reserveRegisterSecondary(unsigned wid, unsigned regnum);
  void releaseRegisterSecondary(unsigned wid, unsigned regnum);
  bool checkCollisionSecondary(unsigned wid, const inst_t *inst) const;
  void clearSecondary(unsigned wid);

  // Mode 1: mask-aware single scoreboard.
  // Each reservation entry tracks (reg, active_mask, ref_count). Hazard
  // checks return true iff any of the inst's read/written regs has an
  // entry whose mask overlaps the candidate's active_mask. See
  // for_claude/docs/scoreboard_redesign_plan.md for design.
  void reserveRegisterMask(unsigned wid, unsigned reg,
                           const active_mask_t &mask);
  void releaseRegisterMask(unsigned wid, unsigned reg,
                           const active_mask_t &mask);
  bool checkCollisionMask(unsigned wid, const inst_t *inst,
                          const active_mask_t &mask) const;
  // Mask-agnostic helper: any in-flight writes for this warp under the
  // active scoreboard table. In mode 1 this checks mask_reg_table; in
  // mode 0 it falls through to legacy reg_table emptiness.
  bool pendingWritesAny(unsigned wid) const;

  // Per-set release dispatcher used at writeback. In mode 0, picks
  // primary vs secondary release based on `is_intra_legacy`. In mode 1,
  // releases (reg, mask) from mask_reg_table; `is_intra_legacy` ignored.
  // In mode 2, releases (reg) from slot_reg_table[wid][slot_id].
  void releaseSetReg(unsigned wid, unsigned reg, const active_mask_t &mask,
                     bool is_intra_legacy, unsigned slot_id = 0);

  // Mode 2: slot-pinned per-half scoreboards. Each warp has two
  // independent scoreboards (one per ibuffer half). Hazard tracking
  // ignores masks since slot ownership guarantees lane-disjoint
  // operation between the two halves. See
  // for_claude/docs/scoreboard_redesign_plan.md.
  static const unsigned NUM_SLOTS = 2;
  void reserveRegisterSlot(unsigned wid, unsigned slot, unsigned regnum);
  void releaseRegisterSlot(unsigned wid, unsigned slot, unsigned regnum);
  bool checkCollisionSlot(unsigned wid, unsigned slot,
                          const inst_t *inst) const;
  bool pendingWritesSlot(unsigned wid, unsigned slot) const {
    return !slot_reg_table[wid][slot].empty();
  }
  bool slotClean(unsigned wid, unsigned slot) const {
    return slot_reg_table[wid][slot].empty();
  }
  bool bothSlotsClean(unsigned wid) const {
    return slot_reg_table[wid][0].empty() && slot_reg_table[wid][1].empty();
  }

 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;

  // Read-only inspector — dumps the primary and secondary reg sets for one
  // warp. Called from the deadlock-detection path under MEMCO_DBG_DEADLOCK
  // env var. No state mutation.
  void dump_warp_state(FILE *out, unsigned wid) const;

 private:
  void reserveRegister(unsigned wid, unsigned regnum);
  int get_sid() const { return m_sid; }

  unsigned m_sid;
  unsigned m_mode;  // 0=legacy, 1=mask-aware, 2=slot-pinned

  // keeps track of pending writes to registers
  // indexed by warp id, reg_id => pending write count
  std::vector<std::set<unsigned> > reg_table;
  // Register that depend on a long operation (global, local or tex memory)
  std::vector<std::set<unsigned> > longopregs;

  // Secondary path register tracking (for I-Buffer half 1, intra-warp co-issue)
  std::vector<std::set<unsigned> > sec_reg_table;

  // Mode 2: per-warp, per-slot register sets.
  // slot_reg_table[wid][slot] = set of reserved register numbers.
  std::vector<std::array<std::set<unsigned>, NUM_SLOTS> > slot_reg_table;

  // Mode 1: per-warp list of mask-aware reservations.
  struct mask_resv {
    unsigned reg;
    active_mask_t mask;
    unsigned ref_count;
    unsigned long long resv_cycle;
  };
  std::vector<std::vector<mask_resv> > mask_reg_table;

  // Mode 1 accounting (used by dumpAccounting + dump_warp_state for leak
  // detection on the deadlock path).
  unsigned long long m_mask_reserve_inserts;       // new entry pushes
  unsigned long long m_mask_reserve_inc_refcount;  // ref_count++ on existing
  unsigned long long m_mask_release_match;          // found and decremented
  unsigned long long m_mask_release_nomatch;        // no matching entry
  unsigned long long m_mask_release_erase;          // ref_count hit 0 + erased

  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_ */