summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/dwf.cc
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-10-05 13:34:47 -0800
committerTor Aamodt <[email protected]>2010-10-05 13:34:47 -0800
commite0f1b4359832ba2952ddcff3a400cd7e1e3d02b5 (patch)
tree12f3dbd8366e15b4a9a299b0368df6fafea11847 /src/gpgpu-sim/dwf.cc
parentd859e08188eb5863888a9b018cf4aec6d0419c40 (diff)
broken change list: builds, but does not run, yet
refactoring: create warp_inst_t that provides notion of a group of scalar instructions traveling down the pipeline. delete DWF delete MIMD delete warp_tracker delete old writeback stage, replace it with a stub that just writes back everything delete old pipeline model current status: MSHR's need to change to deal with the new structure [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7814]
Diffstat (limited to 'src/gpgpu-sim/dwf.cc')
-rw-r--r--src/gpgpu-sim/dwf.cc2606
1 files changed, 0 insertions, 2606 deletions
diff --git a/src/gpgpu-sim/dwf.cc b/src/gpgpu-sim/dwf.cc
deleted file mode 100644
index 7c5305c..0000000
--- a/src/gpgpu-sim/dwf.cc
+++ /dev/null
@@ -1,2606 +0,0 @@
-/*
- * dwf.cc
- *
- * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, and the
- * University of British Columbia
- * Vancouver, BC V6T 1Z4
- * All Rights Reserved.
- *
- * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE
- * TERMS AND CONDITIONS.
- *
- * 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 OWNERS 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.
- *
- * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h
- * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda
- * (property of NVIDIA). The files benchmarks/BlackScholes/ and
- * benchmarks/template/ are derived from the CUDA SDK available from
- * http://www.nvidia.com/cuda (also property of NVIDIA). The files from
- * src/intersim/ are derived from Booksim (a simulator provided with the
- * textbook "Principles and Practices of Interconnection Networks" available
- * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by
- * the corresponding legal terms and conditions set forth separately (original
- * copyright notices are left in files from these sources and where we have
- * modified a file our copyright notice appears before the original copyright
- * notice).
- *
- * Using this version of GPGPU-Sim requires a complete installation of CUDA
- * which is distributed seperately by NVIDIA under separate terms and
- * conditions. To use this version of GPGPU-Sim with OpenCL requires a
- * recent version of NVIDIA's drivers which support OpenCL.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 3. 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.
- *
- * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only.
- *
- * 5. No nonprofit user may place any restrictions on the use of this software,
- * including as modified by the user, by any other authorized user.
- *
- * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung,
- * Ali Bakhoda, George L. Yuan, at the University of British Columbia,
- * Vancouver, BC V6T 1Z4
- */
-
-
-#include "dwf.h"
-#include "histogram.h"
-#include <map>
-#include <set>
-#include <deque>
-#include <queue>
-#include <string.h>
-
-using namespace std;
-
-bool gpgpu_dwf_regbk;
-unsigned int gpgpu_dwf_heuristic;
-enum {
- MAJORITY = 0,
- MINORITY = 1,
- FIFO = 2,
- PDOMPRIO = 3,
- PC = 4,
- MAJORITY_MAXHEAP = 5,
- N_DWFMODE
-};
-
-typedef struct warp_entry {
- address_type pc;
- int* tid; // thread id's
- int occ; // occupancy vector
- int pdom_prio; // pdom_priority
- int pdom_occ; // pdom_priority's aux data
- int next_warp; // index to next warp in an implicit queue
- void* lut_ptr; // pointer to the warp lut entry that last update this warp (a hack), done to decouple warp lut and warp pool
- int uid; // unique id of a warp
-} warp_entry_t;
-
-class issue_warp_majority {
-public:
-
- virtual void add_threads( address_type pc, int *tid) = 0;
- virtual void push_warp( address_type pc, int idx) = 0;
- virtual int pop_warp( ) = 0;
- virtual void print( FILE *fout ) = 0;
- virtual ~issue_warp_majority( ) {}
-};
-
-typedef struct maxheap_lut_entry {
- address_type pc; // pc of the warps
- int maxheap_idx; // index to the max heap
-} maxheap_lut_entry_t;
-
-typedef struct maxheap_entry {
- address_type pc; // pc of the warps
- int n_thds; // number of threads with this pc (from lut)
- int wpool_head; // the first warp with this pc
- int wpool_tail; // the last warp with this pc
- int lut_idx; // reverse index to the lut (for update in entry movement)
-} maxheap_entry_t;
-
-class mh_lut_class {
-private:
-
- maxheap_lut_entry_t *lut_data;
- list<int> *lru_stack; // front = LRU
- int n_set;
- int insn_size_lgb2;
-
-public:
-
- int size;
- int assoc;
- int n_read;
- int n_write;
- int n_read_per_cycle;
- int n_write_per_cycle;
-
- int n_aliased;
- static maxheap_lut_entry_t clean_entry;
-
- mh_lut_class (int size, int assoc, int n_read_per_cycle, int n_write_per_cycle ) {
- int i;
-
- this->size = size;
- this->assoc = assoc;
- lut_data = new maxheap_lut_entry_t[size];
-
- for (i=0; i<size; i++) {
- lut_data[i] = clean_entry;
- }
-
- n_set = size/assoc;
- assert(n_set && !((n_set - 1) & n_set)); // make sure n_set is a power of 2
-
- insn_size_lgb2 = 0;
-
- lru_stack = new list<int>[n_set];
- for (i=0; i<n_set; i++) {
- int j;
- for (j=0; j<assoc; j++) {
- lru_stack[i].push_back(i * assoc + j);
- }
- }
-
- this->n_read_per_cycle = n_read_per_cycle;
- this->n_write_per_cycle = n_write_per_cycle;
- this->n_read = 0;
- this->n_write = 0;
- this->n_aliased = 0;
- }
-
- ~mh_lut_class ( ) {
- delete[] lut_data;
- }
-
- // obtain entry at a known location
- maxheap_lut_entry_t get( int lut_idx ) {
- assert(lut_idx < size);
- n_read++;
- return lut_data[lut_idx];
- }
-
- // modify an entry at a known location
- void set( int lut_idx, maxheap_lut_entry_t lut_entry ) {
- n_write++;
- lut_data[lut_idx] = lut_entry;
- }
-
- // update a lut entry with a new index
- void update_mh_idx( int lut_idx, int mh_idx ) {
- n_write++;
- lut_data[lut_idx].maxheap_idx = mh_idx;
- }
-
- // lookup an entry with a pc
- int lookup( address_type pc ) {
- int i;
- int lut_idx = -1;
- int set_start_idx = get_set(pc) * assoc;
-
- // look for the matched entry within the set
- for (i = set_start_idx; i < (set_start_idx + assoc); i++) {
- if (lut_data[i].pc == pc) {
- lut_idx = i;
- }
- }
-
- // update lru stack if hit
- if (lut_idx != -1) {
- int set_idx = set_start_idx / assoc;
- list<int>::iterator it;
- it = find(lru_stack[set_idx].begin(), lru_stack[set_idx].end(), lut_idx);
-
- if (it != lru_stack[set_idx].end()) {
- lru_stack[set_idx].erase(it);
- lru_stack[set_idx].push_back(lut_idx);
- }
- }
-
- return lut_idx;
- }
-
- void free(int lut_idx) {
- set(lut_idx, clean_entry);
-
- int set_idx = lut_idx / assoc;
- list<int>::iterator it;
- it = find(lru_stack[set_idx].begin(), lru_stack[set_idx].end(), lut_idx);
-
- if (it != lru_stack[set_idx].end()) {
- lru_stack[set_idx].erase(it);
- lru_stack[set_idx].push_front(lut_idx);
- }
- }
-
- // find the LRU entry to be replaced
- int find_lru( maxheap_lut_entry_t lut_entry ) {
- int set_idx = get_set(lut_entry.pc);
- int lru_idx = lru_stack[set_idx].front();
-
- return lru_idx;
- }
-
- // actually replacing the LRU entry
- int replace_lru( maxheap_lut_entry_t lut_entry ) {
- int set_idx = get_set(lut_entry.pc);
- int lru_idx = lru_stack[set_idx].front();
- lru_stack[set_idx].pop_front();
-
- // counting the number of overwritten entries
- if (lut_data[lru_idx].maxheap_idx != 0) n_aliased++;
-
- set(lru_idx, lut_entry);
- lru_stack[set_idx].push_back(lru_idx);
-
- return lru_idx;
- }
-
- // reset the number of accesses to zero
- void reset_access( ) {
- n_read = 0;
- n_write = 0;
- }
-
- // clear the number of accesses - done at the end of scheduler cycle
- void clear_access( ) {
- n_read -= n_read_per_cycle;
- n_read = (n_read >= 0)? n_read : 0;
- n_write -= n_write_per_cycle;
- n_write = (n_write >= 0)? n_write : 0;
- }
-
- // test if the structure is done with all the required accesses
- int all_access_done( ) {
- return(n_read == 0 && n_write == 0);
- }
-
- void print_lut_e(FILE *fout, maxheap_lut_entry_t lut_e) {
- fprintf(fout, "[%08x]mh%02d",
- lut_e.pc, lut_e.maxheap_idx);
- }
-
- void print(FILE *fout) {
- int i, j;
- for (i=0; i<n_set; i++) {
- fprintf(fout, "S%02d", i);
- for (j=0; j<assoc; j++) {
- fprintf(fout, " |%02d:", i * assoc + j);
- print_lut_e(fout, lut_data[i * assoc + j]);
- }
- fprintf(fout, " ");
- list<int>::iterator it = lru_stack[i].begin();
- for (; it != lru_stack[i].end(); it++) {
- fprintf(fout, "%02d-", *it);
- }
- fprintf(fout, "\n");
- }
- }
-
-private:
-
- inline int get_set(address_type pc) {
- return((pc >> insn_size_lgb2) & (n_set - 1));
- }
-};
-
-maxheap_lut_entry_t mh_lut_class::clean_entry = {0xDEADBEEF, 0};
-
-// A class tracking the number of accesses done to the maxheap structure
-// and the index ranges from 1..n_entries with 1 being the root
-class maxheap_class {
-private:
-
- maxheap_entry_t *maxheap_data;
- mh_lut_class *lut;
-
-public:
-
- int n_read;
- int n_write;
- int n_entries;
- int size;
- int n_read_per_cycle;
- int n_write_per_cycle;
-
- int max_n_entries;
- static maxheap_entry_t clean_entry;
-
- maxheap_class( int size, mh_lut_class *lut, int n_read_per_cycle, int n_write_per_cycle ) {
- n_read = 0;
- n_write = 0;
- n_entries = 0; // index to the last element
- this->size = size;
- maxheap_data = new maxheap_entry_t[size];
-
- for (int i=0; i<size; i++) {
- maxheap_data[i] = clean_entry;
- }
-
- this->lut = lut;
-
- this->n_read_per_cycle = n_read_per_cycle;
- this->n_write_per_cycle = n_write_per_cycle;
- this->n_read = 0;
- this->n_write = 0;
- this->max_n_entries = 0;
- }
-
- ~maxheap_class( ) {
- delete[] maxheap_data;
- }
-
- // insert a new entry into the maxheap
- // return: the index to the new entry
- int insert( maxheap_entry_t mh_entry ) {
- assert(n_entries + 1 < size);
- n_write++;
- n_entries++;
- maxheap_data[n_entries] = mh_entry;
- max_n_entries = (max_n_entries >= n_entries)? max_n_entries : n_entries;
- return n_entries;
- }
-
- // retrieve the max heap entry at index [mh_idx]
- maxheap_entry_t get( int mh_idx ) {
- assert(mh_idx > 0);
- assert(mh_idx <= n_entries);
- n_read++;
- return maxheap_data[mh_idx];
- }
-
- // replace the max heap entry at index [mh_idx]
- void set( int mh_idx, maxheap_entry_t mh_entry ) {
- assert(mh_idx > 0);
- assert(mh_idx <= n_entries);
- n_write++;
- maxheap_data[mh_idx] = mh_entry;
- }
-
- // a special version of set that only reset the lut_idx
- void remove_lut_idx( int mh_idx ) {
- assert(mh_idx > 0);
- assert(mh_idx <= n_entries);
- n_write++;
- maxheap_data[mh_idx].lut_idx = -1;
- }
-
- // read both childrens of a given node, count as one read
- // return the number of child read
- int get_childof(int mh_idx, maxheap_entry_t *child) {
- int child_idx = childof(mh_idx);
- int child_read = 0;
-
- if (child_idx <= n_entries) {
- n_read++;
- child[0] = maxheap_data[child_idx];
- child_read++;
- }
- if (child_idx + 1 <= n_entries) {
- child[1] = maxheap_data[child_idx + 1];
- child_read++;
- }
-
- return child_read;
- }
-
- // pop the root entry of max heap
- maxheap_entry_t pop_root( ) {
- maxheap_entry_t old_root = get(1);
- maxheap_entry_t curr_mhe[3];
- curr_mhe[0] = get(n_entries);
-
- set(1, curr_mhe[0]);
- if (curr_mhe[0].lut_idx >= 0)
- lut->update_mh_idx(curr_mhe[0].lut_idx, 1);
-
- n_entries--;
-
- int curr_node = 1;
- int n_child = 0;
-
- n_child = get_childof(curr_node, curr_mhe + 1);
- while (n_child > 0) {
- int max_child = 0;
- int i;
- for (i = 1; i < n_child + 1; i++) {
- if (cmp_mh(curr_mhe[i], curr_mhe[max_child])) {
- max_child = i;
- }
- }
-
- n_child = 0;
- if (max_child > 0) {
- int max_child_node = childof(curr_node) + max_child - 1;
- set(curr_node, curr_mhe[max_child]);
- set(max_child_node, curr_mhe[0]);
-
- // update the lut for this swap
- if (curr_mhe[max_child].lut_idx >= 0)
- lut->update_mh_idx(curr_mhe[max_child].lut_idx, curr_node);
- if (curr_mhe[0].lut_idx >= 0)
- lut->update_mh_idx(curr_mhe[0].lut_idx, max_child_node);
-
- // get the next child
- curr_node = max_child_node;
- n_child = get_childof(curr_node, curr_mhe + 1);
- }
- }
-
- return old_root;
- }
-
- // probe if the maxheap is empty
- int empty( ) {
- return(n_entries == 0);
- }
-
- // reset the number of accesses to zero
- void reset_access( ) {
- n_read = 0;
- n_write = 0;
- }
-
- // clear the number of accesses - done at the end of scheduler cycle
- void clear_access( ) {
- n_read -= n_read_per_cycle;
- n_read = (n_read >= 0)? n_read : 0;
- n_write -= n_write_per_cycle;
- n_write = (n_write >= 0)? n_write : 0;
- }
-
- // test if the structure is done with all the required accesses
- int all_access_done( ) {
- return(n_read == 0 && n_write == 0);
- }
-
- // sort the max heap again starting from start_idx
- // (this entry can only go up in the tree to the root)
- void sort_bottomup(int start_idx) {
- maxheap_entry_t mh_entry;
- maxheap_entry_t mh_parent;
-
- if (start_idx == 1) return; // no need to resort if the root is incremented
-
- int curr_idx = start_idx;
- int parent_idx = parentof(start_idx);
-
- int continue_sort = 1;
- while (curr_idx > 1 && continue_sort) {
- mh_entry = get(curr_idx);
- mh_parent = get(parent_idx);
-
- // swap the entries if it is now larger than it's parent
- if (cmp_mh(mh_entry, mh_parent)) {
- set(parent_idx, mh_entry);
- set(curr_idx, mh_parent);
-
- // update the lut for this swap
- if (mh_entry.lut_idx >= 0)
- lut->update_mh_idx(mh_entry.lut_idx, parent_idx);
- if (mh_parent.lut_idx >= 0)
- lut->update_mh_idx(mh_parent.lut_idx, curr_idx);
-
- // update index for next iteration
- curr_idx = parent_idx;
- parent_idx = parentof(curr_idx);
- } else {
- // swap did not happen, no need to sort anymore
- continue_sort = 0;
- }
- }
- }
-
- void print_mh_e(FILE *fout, maxheap_entry_t mh_e) {
- fprintf(fout, "[%08x]%03d(H%03dT%03d)p%02d | ",
- mh_e.pc, mh_e.n_thds, mh_e.wpool_head, mh_e.wpool_tail, mh_e.lut_idx);
- }
-
- void print(FILE *fout) {
- fprintf(fout, "MaxHeap: ");
- fprintf(fout, "N_entries = %d\n", n_entries);
- for (int i=0; i<n_entries; i++) {
- print_mh_e(fout, maxheap_data[i + 1]);
- if (!((i + 2) & (i + 1))) fprintf(fout, "\n");
- }
- fprintf(fout, "\n");
- }
-
-private:
-
- static inline int parentof(int mh_idx) {
- assert(mh_idx > 0);
- return(mh_idx / 2);
- }
-
- static inline int childof(int mh_idx) {
- return(mh_idx * 2);
- }
-
- static inline int cmp_mh(maxheap_entry_t &a, maxheap_entry_t &b) {
- if (a.n_thds > b.n_thds) return 1;
- if (a.n_thds == b.n_thds) {
- if (a.pc < b.pc) return 1;
- }
- return 0;
- }
-
-};
-
-maxheap_entry_t maxheap_class::clean_entry = {0, 0, -1, -1, -1};
-
-typedef struct mh_update_struct {
- int n_maxheap_read;
- int n_maxheap_write;
- int n_mhlut_read;
- int n_mhlut_write;
-} mh_update;
-
-// heap implementation of majority policy
-class issue_warp_majority_heap : public issue_warp_majority {
-public:
-
- mh_lut_class mh_lut;
- maxheap_class maxheap;
-
- maxheap_lut_entry_t major_lut_e;
- maxheap_entry_t major_mh_e;
-
- vector<warp_entry_t> *warp_pool;
- int simd_width;
-
- int n_stall_on_maxheap;
-
- queue<mh_update> update_queue;
- static pow2_histogram n_pending_updates_histo;
-
- issue_warp_majority_heap (int simd_width = 0, vector<warp_entry_t> *bp = NULL,
- int lut_size = 32, int lut_assoc = 4, int maxheap_size = 128,
- int n_read_lut = 4, int n_write_lut = 4,
- int n_read_mh = 4, int n_write_mh = 4)
- : mh_lut(lut_size, lut_assoc, n_read_lut, n_write_lut),
- maxheap(maxheap_size, &mh_lut, n_read_mh, n_write_mh)
- {
- this->simd_width = simd_width;
- this->warp_pool = bp;
-
- this->major_lut_e = mh_lut_class::clean_entry;
- this->major_mh_e = maxheap_class::clean_entry;
-
- this->n_stall_on_maxheap = 0;
- }
-
- // adding more threads to a specify pc
- // these threads may end up in different warpes
- void add_threads( address_type pc, int *tid) {
- int i;
- int n_thds = 0;
- for (i=0; i<simd_width; i++) {
- if (tid[i] >= 0) n_thds++;
- }
-
- // handle special case with adding threads to current majority pc
- if (major_lut_e.pc == pc) {
- assert(major_mh_e.pc == pc);
- major_mh_e.n_thds += n_thds;
- return;
- }
-
- maxheap_lut_entry_t lut_e;
- maxheap_entry_t mh_entry;
-
- // snapshot the current maxheap read/write demand
- mh_update new_mh_update;
- new_mh_update.n_maxheap_read = maxheap.n_read;
- new_mh_update.n_maxheap_write = maxheap.n_write;
- new_mh_update.n_mhlut_read = mh_lut.n_read;
- new_mh_update.n_mhlut_write = mh_lut.n_write;
-
- int lut_idx = mh_lut.lookup(pc);
-
- int sort_from_idx = 0;
-
- if (lut_idx >= 0) {
- // obtain the entry
- lut_e = mh_lut.get(lut_idx);
-
- // get the maxheap entry and update its number of threads
- mh_entry = maxheap.get(lut_e.maxheap_idx);
- mh_entry.n_thds += n_thds;
- maxheap.set(lut_e.maxheap_idx, mh_entry);
-
- // sort from this specific entry
- sort_from_idx = lut_e.maxheap_idx;
- } else {
- // create a new lut entry
- lut_e = mh_lut_class::clean_entry;
- lut_e.pc = pc;
-
- // get index to the LRU lut entry in this set
- lut_idx = mh_lut.find_lru(lut_e);
-
- // get the replaced lut entry and remove its link with the maxheap entry
- maxheap_lut_entry_t lut_old = mh_lut.get(lut_idx);
- if (lut_old.maxheap_idx > 0) maxheap.remove_lut_idx(lut_old.maxheap_idx);
-
- // create a new maxheap entry
- mh_entry = maxheap_class::clean_entry;
- mh_entry.pc = pc;
- mh_entry.n_thds = n_thds;
- mh_entry.lut_idx = lut_idx;
-
- // push the new entry into the maxheap and lut respectively
- lut_e.maxheap_idx = maxheap.insert(mh_entry);
- mh_lut.replace_lru(lut_e);
-
- // start sorting from the bottom?
- sort_from_idx = lut_e.maxheap_idx;
- }
-
- maxheap.sort_bottomup(sort_from_idx);
-
- // record the newly generated maxheap read/write demand from this update
- new_mh_update.n_maxheap_read = maxheap.n_read - new_mh_update.n_maxheap_read;
- new_mh_update.n_maxheap_write = maxheap.n_write - new_mh_update.n_maxheap_write;
- new_mh_update.n_mhlut_read = mh_lut.n_read - new_mh_update.n_mhlut_read;
- new_mh_update.n_mhlut_write = mh_lut.n_write - new_mh_update.n_mhlut_write;
-
- update_queue.push(new_mh_update);
- }
-
- // call this when a new warp allocated for a specific pc
- void push_warp( address_type pc, int idx) {
- maxheap_entry_t *p_mh_e = NULL;
- maxheap_entry_t mh_e;
- maxheap_lut_entry_t lut_e = mh_lut_class::clean_entry;
- int lut_idx = -1;
-
- if (major_mh_e.pc == pc) {
- p_mh_e = &major_mh_e;
- } else {
- lut_idx = mh_lut.lookup(pc);
- assert(lut_idx >= 0); // if it is a miss, a new entry should have been created already
- lut_e = mh_lut.get(lut_idx);
- mh_e = maxheap.get(lut_e.maxheap_idx);
- p_mh_e = &mh_e;
-
- // discounting these 'gets'
- // because they should be combined with the 'gets' in add_threads()
- mh_lut.n_read--;
- maxheap.n_read--;
- }
-
- if (p_mh_e->wpool_head == -1) {
- p_mh_e->wpool_head = idx;
- p_mh_e->wpool_tail = idx;
- } else {
- (*warp_pool)[p_mh_e->wpool_tail].next_warp = idx;
- p_mh_e->wpool_tail = idx;
- }
-
- if (major_mh_e.pc == pc) {
- } else {
- maxheap.set(lut_e.maxheap_idx, mh_e);
- // discounting this 'set'
- // because it should be combined with the 'set' in add_threads()
- maxheap.n_write--;
- }
- }
-
- // obtain a warp index from this issue logic
- int pop_warp( ) {
- int bidx = -1;
- if (major_mh_e.wpool_head == -1 && !maxheap.empty()) {
- if (this->all_access_done( )) {
- // pop the majority PC from max heap
- major_mh_e = maxheap.pop_root();
-
- // pop its corresponding entry from the lut as well (if it exists)
- if (major_mh_e.lut_idx >= 0) {
- major_lut_e = mh_lut.get(major_mh_e.lut_idx);
- mh_lut.free(major_mh_e.lut_idx);
- } else {
- major_lut_e = mh_lut_class::clean_entry;
- }
- } else {
- n_stall_on_maxheap += 1;
- bidx = -1;
- return bidx;
- }
- }
-
- // just pop and entry to from the virtual queue (and set the head pointer to next warp)
- bidx = major_mh_e.wpool_head;
- if (bidx >= 0) {
- major_mh_e.wpool_head = (*warp_pool)[major_mh_e.wpool_head].next_warp;
- }
-
- return bidx;
- }
-
- void reset_access( ) {
- maxheap.reset_access();
- mh_lut.reset_access();
-
- while (!update_queue.empty()) {
- update_queue.pop();
- }
- }
-
- inline void consume_access( int &req_acc, int &avl_acc) {
- if (req_acc > avl_acc) {
- req_acc -= avl_acc;
- avl_acc = 0;
- } else {
- avl_acc -= req_acc;
- req_acc = 0;
- }
- }
-
- void clear_access( ) {
- maxheap.clear_access();
- mh_lut.clear_access();
-
- int n_maxheap_read_bw = maxheap.n_read_per_cycle;
- int n_maxheap_write_bw = maxheap.n_write_per_cycle;
- int n_mhlut_read_bw = mh_lut.n_read_per_cycle;
- int n_mhlut_write_bw = mh_lut.n_write_per_cycle;
-
- while ((n_maxheap_read_bw > 0 || n_maxheap_read_bw > 0 ||
- n_mhlut_read_bw > 0 || n_mhlut_write_bw > 0) && !update_queue.empty()) {
- mh_update &c_update = update_queue.front();
-
- consume_access (c_update.n_maxheap_read, n_maxheap_read_bw);
- consume_access (c_update.n_maxheap_write, n_maxheap_write_bw);
- consume_access (c_update.n_mhlut_read, n_mhlut_read_bw);
- consume_access (c_update.n_mhlut_write, n_mhlut_write_bw);
-
- if (c_update.n_maxheap_read == 0 && c_update.n_maxheap_write == 0 &&
- c_update.n_mhlut_read == 0 && c_update.n_mhlut_write == 0) {
- update_queue.pop();
- } else {
- break;
- }
- }
-
- n_pending_updates_histo.add2bin(update_queue.size());
- }
-
- void print( FILE *fout ) {
- fprintf(fout, "LUT: ");
- mh_lut.print_lut_e(fout, major_lut_e);
- fprintf(fout, " \tMH: ");
- maxheap.print_mh_e(fout, major_mh_e);
- fprintf(fout, "\n");
- mh_lut.print(fout);
- maxheap.print(fout);
- }
-
- static void print_stat( FILE *fout) {
- fprintf(fout, "n_pending_maxheap_updates = ");
- n_pending_updates_histo.fprint(fout);
- fprintf(fout, "\n");
- }
-
-private:
-
- int all_access_done( ) {
- return(maxheap.all_access_done() && mh_lut.all_access_done());
-
- }
-};
-pow2_histogram issue_warp_majority_heap::n_pending_updates_histo;
-
-class warp_queue {
-public:
- int m_pc;
- int n_thds;
- int simd_width;
- deque<int> idx_queue;
-
- warp_queue( address_type pc, int simd_width) {
- this->m_pc = pc;
- this->n_thds = 0;
- this->simd_width = simd_width;
- }
-
- // called right after a lut_entry is looked up
- void add_threads( int *tid ) {
- for (int i=0; i<simd_width; i++) {
- if (tid[i] >= 0) this->n_thds++;
- }
- }
-
- // called right after a warp is issued
- void sub_threads( int *tid ) {
- for (int i=0; i<simd_width; i++) {
- if (tid[i] >= 0) this->n_thds--;
- }
- }
-
- // if other warp queue should be ahead
- bool operator<(const warp_queue& other) const {
- if (n_thds == other.n_thds) {
- return(m_pc > other.m_pc); // smaller pc first
- } else {
- return(n_thds < other.n_thds);
- }
- }
- bool operator>(const warp_queue& other) const {
- if (n_thds == other.n_thds) {
- return(m_pc > other.m_pc); // smaller pc first
- } else {
- return(n_thds > other.n_thds);
- }
- }
-
- void print( FILE *fout ) {
- fprintf(fout, "0x%08x(%03d)=[", m_pc, n_thds);
- deque<int>::iterator dit = idx_queue.begin();
- for (; dit != idx_queue.end(); dit++) {
- fprintf(fout, "%03d ", *dit);
- }
- fprintf(fout, "]\n");
- }
-};
-
-bool minor_warp( const warp_queue* a, const warp_queue* b ) {
- return(*a<*b);
-}
-
-// queue implementation of majority scheduling policy
-class issue_warp_majority_queue : public issue_warp_majority {
-public:
- map<address_type, warp_queue* > majority_map;
- set<warp_queue*> warpq_set;
- warp_queue* maj_warp;
-
- vector<warp_entry_t> *warp_pool;
- int simd_width;
-
- issue_warp_majority_queue(int simd_width = 0, vector<warp_entry_t> *bp = NULL) {
- this->maj_warp = NULL;
- this->simd_width = simd_width;
- this->warp_pool = bp;
- }
-
- // adding more threads to a specify pc
- // these threads may end up in different warps
- void add_threads( address_type pc, int *tid) {
- warp_queue* bq = majority_map[pc];
- if (bq == NULL) {
- bq = new warp_queue(pc,simd_width);
- warpq_set.insert(bq);
- majority_map[pc] = bq;
- }
- bq->add_threads(tid);
- }
-
- // call this when a new warp allocated for a specific pc
- void push_warp( address_type pc, int idx) {
- warp_queue* bq = majority_map[pc];
- assert(bq != NULL);
- bool check_redundant_idx = false;
- if (check_redundant_idx) {
- deque<int>::iterator dit = find(bq->idx_queue.begin(), bq->idx_queue.end(), idx);
- assert(dit == bq->idx_queue.end());
- }
- bq->idx_queue.push_back(idx);
- }
-
- // obtain a warp index from this issue logic
- int pop_warp( ) {
- int bidx = -1;
-
- // find the new majority pc if it didn't exist
- if (maj_warp == NULL && warpq_set.size()) {
- maj_warp = *max_element(warpq_set.begin(), warpq_set.end(), minor_warp);
- }
-
- // if a majority pc indeed exist
- if (maj_warp) {
- assert(!maj_warp->idx_queue.empty());
- bidx = maj_warp->idx_queue.front();
- maj_warp->idx_queue.pop_front();
- maj_warp->sub_threads((*warp_pool)[bidx].tid);
-
- // when the majority pc runs out of thread
- if (maj_warp->n_thds == 0) {
- // remove that warp queue
- warpq_set.erase(maj_warp);
- majority_map.erase(maj_warp->m_pc);
- delete maj_warp;
- maj_warp = NULL;
- }
- }
-
- return bidx;
- }
-
- void print( FILE *fout ) {
- fprintf(fout, "issue_warp_majority:\n");
- set<warp_queue*>::iterator dit = warpq_set.begin();
- for (; dit != warpq_set.end(); dit++) {
- fprintf(fout, " %c ", ((*dit)==maj_warp)? 'M':' ');
- (*dit)->print(fout);
- }
- }
-
- void check_consistency( ) {
- set<warp_queue*>::iterator set_it = warpq_set.begin();
- for (; set_it != warpq_set.end(); set_it++) {
- warp_queue* bq = (*set_it);
-
- int real_nthds = 0;
- deque<int>::iterator dit = bq->idx_queue.begin();
- for (; dit != bq->idx_queue.end(); dit++) {
- int *tid = (*warp_pool)[*dit].tid;
- for (int i = 0; i < simd_width; i++) {
- real_nthds += (tid[i] >= 0)? 1 : 0;
- }
- }
-
- assert(real_nthds == bq->n_thds);
- }
- }
-};
-
-// pdom priority
-class lesspdom_first {
-public:
- vector<warp_entry_t> *warp_pool;
- lesspdom_first( vector<warp_entry_t> *bp=NULL ) {
- this->warp_pool = bp;
- }
- bool operator() (const int &idx_a, const int &idx_b) const {
- if ((*warp_pool)[idx_a].pdom_prio != (*warp_pool)[idx_b].pdom_prio) {
- return((*warp_pool)[idx_a].pdom_prio < (*warp_pool)[idx_b].pdom_prio);
- } else {
- return((*warp_pool)[idx_a].occ > (*warp_pool)[idx_b].occ);
- }
- }
-};
-
-
-class issue_warp_pdom_prio {
-public:
- vector<warp_entry_t> *warp_pool;
- int* thd_pdom_prio;
- int simd_width;
- int n_threads;
-
- int resort_needed;
- list<int> pdom_pqueue; //the queue holding all index
-
- lesspdom_first lesspdom_cmp;
-
- static set<address_type> reconvgence_pt; //table holding all recvg pt
-
- issue_warp_pdom_prio (int simd_width = 0, vector<warp_entry_t> *bp = NULL,
- int n_threads = 0)
- : lesspdom_cmp(bp)
- {
- this->simd_width = simd_width;
- this->warp_pool = bp;
- this->n_threads = n_threads;
- this->thd_pdom_prio = new int[n_threads];
- memset(this->thd_pdom_prio, 0, sizeof(int)*n_threads);
- this->resort_needed = 0;
- }
-
- ~issue_warp_pdom_prio( ) {
- delete[] this->thd_pdom_prio;
- }
-
- void reinit( ) {
- memset(this->thd_pdom_prio, 0, sizeof(int)*n_threads);
- }
-
- // adding more threads to a warp
- void add_threads( int idx, address_type pc) {
- assert((*warp_pool)[idx].pc == pc);
-
- // check to see if this is a newly allocated warp
- bool check_pdom = false;
- if ((*warp_pool)[idx].pdom_prio == -1) {
- check_pdom = true;
- }
-
- // check for newly assigned threads to the warp
- int pdom_occ = (*warp_pool)[idx].pdom_occ;
- int *tid = (*warp_pool)[idx].tid;
- for (int i=0; i<simd_width; i++) {
- if (tid[i] >= 0 && !(pdom_occ & (1<<i))) {
- if ((*warp_pool)[idx].pdom_prio < thd_pdom_prio[tid[i]]) {
- (*warp_pool)[idx].pdom_prio = thd_pdom_prio[tid[i]];
- resort_needed = 1;
- }
- pdom_occ |= (1<<i);
- }
- }
- if (check_pdom) {
- if (reconvgence_pt.find(pc) != reconvgence_pt.end()) {
- (*warp_pool)[idx].pdom_prio += 1;
- }
- }
- }
-
- // call this when a new warp allocated for a specific pc
- void push_warp( address_type pc, int idx ) {
- assert((*warp_pool)[idx].pc == pc);
- // initialize the pdom_prio for this newly allocated warp
- (*warp_pool)[idx].pdom_prio = -1;
- (*warp_pool)[idx].pdom_occ = 0;
- pdom_pqueue.push_back(idx);
- }
-
- // obtain a warp index from this issue logic
- int front_warp( ) {
- int bidx = -1;
-
- if (!pdom_pqueue.empty()) {
- if (resort_needed) {
- pdom_pqueue.sort(lesspdom_cmp);
- resort_needed = 0;
- }
-
- bidx = pdom_pqueue.front();
- }
-
- return bidx;
- }
-
- int size( ) {
- return pdom_pqueue.size();
- }
-
- void enforce_resort( ) {
- resort_needed = 1;
- }
-
- int pop_warp( ) {
- int bidx = -1;
-
- if (!pdom_pqueue.empty()) {
- if (resort_needed) {
- pdom_pqueue.sort(lesspdom_cmp);
- resort_needed = 0;
- }
-
- bidx = pdom_pqueue.front();
- pdom_pqueue.pop_front();
-
- // update the pdom prio of each thread inside a warp
- for (int i=0; i<simd_width; i++) {
- if ((*warp_pool)[bidx].tid[i] >= 0) {
- thd_pdom_prio[(*warp_pool)[bidx].tid[i]] = (*warp_pool)[bidx].pdom_prio;
- }
- }
- }
-
- return bidx;
- }
-
-};
-
-set<address_type> issue_warp_pdom_prio::reconvgence_pt = set<address_type>();
-//*/
-
-
-class npc_tracker_class {
-public:
- map<address_type, unsigned> pc_count;
- unsigned* acc_pc_count;
- int simd_width;
- static map<unsigned, unsigned> histogram;
-
- npc_tracker_class( ) {
- this->acc_pc_count = NULL;
- this->simd_width = 0;
- }
-
- npc_tracker_class(unsigned* acc_pc_count, int simd_width) {
- this->acc_pc_count = acc_pc_count;
- this->simd_width = simd_width;
- }
-
- void add_threads( int *tid, address_type pc ) {
- for (int i=0; i<simd_width; i++) {
- if (tid[i] != -1) pc_count[pc] += 1; // automatically create a new entry if not exist
- }
- }
-
- void sub_threads( int *tid, address_type pc ) {
- for (int i=0; i<simd_width; i++) {
- if (tid[i] != -1) {
- pc_count[pc] -= 1;
- assert((int)pc_count[pc] >= 0);
- if (pc_count[pc] == 0) pc_count.erase(pc); // manually erasing entries with 0 count
- }
- }
- }
-
- void update_acc_count( ) {
- (*acc_pc_count) += pc_count.size();
- histogram[pc_count.size()] += 1;
- }
-
- unsigned count( ) { return pc_count.size();}
-
- static void histo_print( FILE* fout ) {
- map<unsigned, unsigned>::iterator i;
- fprintf(fout, "DYHW nPC Histogram: ");
- for (i = histogram.begin(); i != histogram.end(); i++) {
- fprintf(fout, "%d:%d ", i->first, i->second);
- }
- fprintf(fout, "\n");
- }
-};
-
-map<unsigned, unsigned> npc_tracker_class::histogram;
-
-class pc_tag {
-private:
-
- address_type m_pc;
-
-public:
-
- pc_tag () {
- this->reset();
- }
-
- pc_tag (const pc_tag& p) { this->m_pc = p.m_pc;}
- pc_tag (const address_type& other_pc) { this->m_pc = other_pc;}
-
- pc_tag& operator=(const pc_tag& p) { m_pc = p.m_pc; return *this;}
- pc_tag& operator=(const address_type& other_pc) { m_pc = other_pc; return *this;}
-
- inline bool operator==(const pc_tag& p) const { return(m_pc == p.m_pc);}
- inline bool operator==(const address_type& other_pc) const { return(m_pc == other_pc);}
-
- inline bool operator!=(const pc_tag& p) const { return(m_pc != p.m_pc);}
- inline bool operator!=(const address_type& other_pc) const { return(m_pc != other_pc);}
-
- inline bool operator<(const pc_tag& p) const { return(m_pc < p.m_pc);}
-
- inline void reset() {
- m_pc = -1;
- }
-
- inline address_type get_pc() const { return m_pc;}
-
- // the hash function to warp LUT
- inline unsigned lut_hash( int insn_size_lgb2, int lut_nsets ) const {
- return(m_pc >> insn_size_lgb2) & (lut_nsets - 1);
- }
-
- inline void to_print(char *buffer, unsigned length) {
- snprintf(buffer, length, "0x%08x", m_pc);
- }
-};
-
-template <class Tag>
-class tag2warp_entry_t {
-public:
-
- Tag tag;
- int idx; // pointing to warp pool
- int occ; // occupancy vector
- int accessed; // is the entry accessed this cycle
-
- tag2warp_entry_t () {
- this->reset();
- }
-
- ~tag2warp_entry_t () {}
-
- tag2warp_entry_t (const tag2warp_entry_t& p) {
- this->tag = p.tag;
- this->idx = p.idx;
- this->occ = p.occ;
- this->accessed = p.accessed;
- }
-
- tag2warp_entry_t& operator=(const tag2warp_entry_t& p) {
- if (this != &p) {
- tag = p.tag;
- idx = p.idx;
- occ = p.occ;
- accessed = p.accessed;
- }
- return *this;
- }
-
- inline bool operator==(const tag2warp_entry_t& p) const {
- return(tag == p.tag);
- }
-
- inline bool operator==(const Tag& test_tag) const {
- return(tag == test_tag);
- }
-
- inline bool operator()(const tag2warp_entry_t& p) const {
- return(tag == p.tag);
- }
-
- inline void reset() {
- tag.reset();
- idx = 0;
- occ = 0;
- accessed = 0;
- }
-
- void print( FILE *fout ) {
- static char buffer[20];
- tag.to_print(buffer,20);
- fprintf(fout, "\t%s->%03d (%02x)\n", buffer, idx, occ);
- }
-
-};
-
-template <class Tag>
-class tag2warp_set {
-public:
- vector< tag2warp_entry_t<Tag> > entry;
- list< tag2warp_entry_t<Tag>* > lru_stack;
-
- tag2warp_set(int assoc = 0) : entry(assoc) {
- for (unsigned j=0; j<this->entry.size(); j++) {
- this->lru_stack.push_back(&(this->entry[j]));
- }
- }
-
- tag2warp_set(const tag2warp_set& other) : entry(other.entry.size()) {
- for (unsigned j=0; j<this->entry.size(); j++) {
- this->lru_stack.push_back(&(this->entry[j]));
- }
- }
-
- tag2warp_set& operator=(const tag2warp_set& p) {
- printf("tag2warp_set assignment operator called!\n");
- return *this;
- }
-
- ~tag2warp_set() {}
-};
-
-template <class Tag>
-class warp_lut {
-public:
- virtual ~warp_lut() {}
- virtual tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed ) = 0;
- virtual void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) = 0;
- virtual void clear_accessed( ) = 0;
- virtual void print( FILE* fout) = 0;
-};
-
-template <class Tag>
-class warp_lut_sa : public warp_lut<Tag> {
-private:
- int lut_size;
- int lut_assoc;
- vector< tag2warp_set<Tag> > tag2warp_lut;
- int insn_size_lgb2;
-
- queue< tag2warp_entry_t<Tag>* > lut_accessed_q; // store accessed lut entry for clear
-
- struct same_tag {
- Tag tag;
- bool operator()(tag2warp_entry_t<Tag>* a) {
- return(a->tag == tag);
- }
- };
-
- static unsigned int lut_aliased;
-
-public:
- warp_lut_sa(int lut_size, int lut_assoc, int insn_size) {
- this->lut_size = lut_size;
- this->lut_assoc = lut_assoc;
-
- // optimize for LUT hash function
- insn_size_lgb2 = 0;
- while ( (1 << insn_size_lgb2) < insn_size ) insn_size_lgb2++;
-
- // initialize the pc2warp LUT
- // note: lut_size is the absolute size of LUT regardless of assoc.
- this->tag2warp_lut.assign(lut_size/lut_assoc, tag2warp_set<Tag>(lut_assoc));
-
- // assert on #set in LUT to be power of 2
- int lut_nset_pow2 = 1;
- while ( lut_nset_pow2 < (int)tag2warp_lut.size() ) lut_nset_pow2 <<= 1;
- assert((int)tag2warp_lut.size() == lut_nset_pow2);
- }
-
- tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed );
- void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) {
- if (lut_entry != NULL) { // check for warp lut entry invalidation
- if (lut_entry->idx == warp_idx) {
- lut_entry->reset();
- }
- }
- }
-
- void clear_accessed( );
-
- void print( FILE* fout) {
- for (unsigned i=0; i< tag2warp_lut.size(); i++) {
- for (unsigned j=0; j< tag2warp_lut[i].entry.size(); j++) {
- fprintf(fout, "lut%03d-%02d:", i, j);
- tag2warp_lut[i].entry[j].print(fout);
- }
- }
- }
-
- static void print_stats ( FILE* fout ) {
- fprintf( fout, "lut_aliased = %d\n", lut_aliased);
- }
-};
-template <class Tag> unsigned int warp_lut_sa<Tag>::lut_aliased = 0;
-
-
-// lookup function in LUT
-// may return an entry that has different PC for replacement
-// or return a NULL pointer to indicate that the entry is accessed by another port
-template <class Tag>
-tag2warp_entry_t<Tag>* warp_lut_sa<Tag>::lookup_pc2warp( const Tag &tag, bool &lut_missed )
-{
- tag2warp_entry_t<Tag>* lut_entry = NULL;
- unsigned hashed_pc = tag.lut_hash(insn_size_lgb2, tag2warp_lut.size());
- list< tag2warp_entry_t<Tag>* > &hashed_lru_stack = tag2warp_lut.at(hashed_pc).lru_stack;
- struct same_tag same_tag_f;
-
- same_tag_f.tag = tag;
- typename list< tag2warp_entry_t<Tag>* >::iterator lut_it;
- lut_it = find_if(hashed_lru_stack.begin(),
- hashed_lru_stack.end(),
- same_tag_f);
- if (lut_it != hashed_lru_stack.end()) {
- lut_entry = *lut_it;
- lut_entry->accessed = 1;
- lut_accessed_q.push(lut_entry);
- hashed_lru_stack.splice(hashed_lru_stack.end(), hashed_lru_stack, lut_it);
- assert(lut_entry == hashed_lru_stack.back());
- lut_missed = false;
- } else {
- assert(!hashed_lru_stack.empty());
- lut_entry = hashed_lru_stack.front();
- if (lut_entry->accessed) {
- lut_entry = NULL;
- } else {
- lut_entry->accessed = 1;
- lut_accessed_q.push(lut_entry);
- hashed_lru_stack.splice(hashed_lru_stack.end(), hashed_lru_stack, hashed_lru_stack.begin());
- assert(lut_entry == hashed_lru_stack.back());
- lut_aliased++;
- }
- lut_missed = true;
- }
- assert(hashed_lru_stack.size() == tag2warp_lut[hashed_pc].entry.size());
-
- return lut_entry;
-}
-
-template <class Tag>
-void warp_lut_sa<Tag>::clear_accessed( ) {
- while ( !lut_accessed_q.empty() ) {
- lut_accessed_q.front()->accessed = 0;
- lut_accessed_q.pop();
- }
-}
-
-// a perfect warp lut that never misses.
-template <class Tag>
-class warp_lut_perfect : public warp_lut<Tag> {
-private:
- typedef map< Tag, tag2warp_entry_t<Tag>* > warp_map_t;
- warp_map_t m_tag2entry_map;
-
- static unsigned int lut_max_size;
-public:
- warp_lut_perfect() {}
- ~warp_lut_perfect() {
- typename warp_map_t::iterator mit = m_tag2entry_map.begin();
- for (; mit != m_tag2entry_map.end(); mit++) {
- delete mit->second;
- }
- }
-
- // idealistic implementation of lookup: the entry is never aliased,
- // and a new one is created automatically if it does not exist
- tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed ) {
- typename warp_map_t::iterator mit = m_tag2entry_map.find(tag);
-
- tag2warp_entry_t<Tag>* lut_entry = NULL;
- if (mit != m_tag2entry_map.end()) {
- lut_entry = mit->second;
- assert(lut_entry->tag == tag);
- } else {
- lut_entry = new tag2warp_entry_t<Tag>();
- m_tag2entry_map.insert(make_pair(tag, lut_entry));
- }
-
- lut_missed = false;
- lut_max_size = (lut_max_size < m_tag2entry_map.size())? m_tag2entry_map.size() : lut_max_size;
-
- return lut_entry;
- }
-
- void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) {
- if (lut_entry == NULL) return;
- if (lut_entry->idx != warp_idx) return;
-
- typename warp_map_t::iterator mit = m_tag2entry_map.find(lut_entry->tag);
- if (mit != m_tag2entry_map.end()) {
- assert(mit->second == lut_entry);
- mit->second->reset();
- delete mit->second;
- m_tag2entry_map.erase(mit);
- }
- }
-
- void clear_accessed( ) {}
-
- void print( FILE* fout) {
- typename warp_map_t::iterator mit = m_tag2entry_map.begin();
- for (; mit != m_tag2entry_map.end(); mit++) {
- mit->second->print(fout);
- }
- }
-
- static void print_stats ( FILE* fout ) {
- fprintf( fout, "lut_max_size = %d\n", lut_max_size);
- }
-};
-template <class Tag> unsigned int warp_lut_perfect<Tag>::lut_max_size = 0;
-
-
-typedef tag2warp_entry_t<pc_tag> warplut_entry_t;
-typedef pc_tag warp_tag_t;
-
-class dwf_hw_sche_class {
-public:
- int m_id;
- warp_lut<pc_tag> *warp_lut_pc;
- vector<warp_entry_t> warp_pool;
- deque<int> free_warp_q; // the warp allocator
- int simd_width;
- int regf_width;
- int insn_size_lgb2;
- bool just_resume;
-
- vector<char> m_req; // request vector from incoming warp
- vector<char> m_occ_new; // occupancy vector of the new warp, double as conflict vector
- vector<char> m_occ_upd; // occupancy vector of the updated existing warp
- vector<char> m_occ_ext; // occupancy vector of the existing warp
-
- dwf_hw_sche_class( int lut_size, int lut_assoc,
- int simd_width, int regf_width,
- int n_threads, int insn_size,
- int heuristic, int id,
- char *policy_opt = NULL );
- ~dwf_hw_sche_class();
-
- warplut_entry_t* lookup_pc2warp( const warp_tag_t& lookup_tag );
- int update_warp( int* tid, address_type pc );
-
- // barrier handling
- int m_nbarriers;
- class dwf_barrier {
- public:
- bool m_release; // see if a barrier is to be released (ie. all warp in cta hit already)
- deque<int> m_queue; // queue storing warps currently hitting a barrier, skipping warplut and scheduler
-
- dwf_barrier() : m_release(false) {}
- dwf_barrier(const dwf_barrier& that)
- : m_release(that.m_release), m_queue(that.m_queue) {}
- bool ready_to_issue() {
- return(m_release && !m_queue.empty());
- }
- };
- set< int > m_cta_released_barrier; // set of cta with released barrier
- map< int, dwf_barrier > m_barrier; // map <barrier id == cta id, barrier>
- int update_warp_at_barrier( int* tid, address_type pc, int cta_id, int barrier_num = 0 );
- void hit_barrier( int cta_id, int barrier_num = 0 );
- void release_barrier( int cta_id, int barrier_num = 0 );
-
- int allocate_warp( address_type pc, bool update_scheduler = true );
- void free_warp( int idx, bool update_warplut = true );
-
- void issue_warp( int *tid, address_type *pc );
-
- void clear_accessed( ) {
- warp_lut_pc->clear_accessed();
- }
-
- void init_cta(int start_thread, int cta_size, address_type start_pc);
-
- void print_pc2warp_lut( FILE *fout );
- void print_warp_pool( FILE *fout );
- void print_free_warp_q( FILE *fout );
-
- int heuristic;
-
- // FIFO warp issue logic
- queue<int> issue_warp_FIFO_q;
-
- // PC warp issue logic
- class pc_first {
- public:
- vector<warp_entry_t> &warp_pool;
- pc_first( vector<warp_entry_t> &bp ) : warp_pool(bp) {}
- bool operator() (const int &idx_a, const int &idx_b) const {
- if (warp_pool[idx_a].pc != warp_pool[idx_b].pc) {
- return(warp_pool[idx_a].pc > warp_pool[idx_b].pc);
- } else {
- return(warp_pool[idx_a].occ < warp_pool[idx_b].occ);
- }
- }
- };
- pc_first mypc_first;
- priority_queue<int, vector<int>, pc_first > issue_warp_PC_q;
-
- // Majority warp issue logic
- issue_warp_majority *issue_warp_MAJ;
- void clear_policy_access( );
- void reset_policy_access( );
-
- // PDOM Priority issue logic
- issue_warp_pdom_prio issue_warp_pdom;
-
- // statistics
- npc_tracker_class npc_tracker;
- int max_warppool_occ;
- int *warppool_occ_histo; // histogram of warppool occupancy
- static unsigned int lut_realmiss;
- static unsigned int uid_cnt;
- static unsigned int warp_fragmentation;
- static unsigned int warp_merge_conflict;
- static void print_stats ( FILE* fout ) {
- warp_lut_perfect<warp_tag_t>::print_stats( fout );
- warp_lut_sa<warp_tag_t>::print_stats( fout );
- fprintf( fout, "lut_realmiss = %d\n", lut_realmiss);
- fprintf( fout, "warp_fragmentation = %d\n", warp_fragmentation);
- fprintf( fout, "warp_merge_conflict = %d\n", warp_merge_conflict);
- }
-};
-
-unsigned int dwf_hw_sche_class::lut_realmiss = 0;
-unsigned int dwf_hw_sche_class::uid_cnt = 0;
-unsigned int dwf_hw_sche_class::warp_fragmentation = 0;
-unsigned int dwf_hw_sche_class::warp_merge_conflict = 0;
-
-
-dwf_hw_sche_class::dwf_hw_sche_class( int lut_size, int lut_assoc,
- int simd_width, int regf_width,
- int n_threads, int insn_size,
- int heuristic, int id,
- char *policy_opt )
-: m_id(id),
-// WarpLUT w/ pc tag
-warp_lut_pc( (lut_size == 0)? (warp_lut<pc_tag> *) new warp_lut_perfect<pc_tag>() :
- (warp_lut<pc_tag> *) new warp_lut_sa<pc_tag>(lut_size, lut_assoc, insn_size) ),
-m_nbarriers(1), // for barrier
-mypc_first( warp_pool ), issue_warp_PC_q( mypc_first ), // DPC
-issue_warp_pdom(simd_width, &warp_pool, n_threads), // DPdPri
-npc_tracker( NULL, simd_width )
-{
- unsigned i;
-
- this->simd_width = simd_width;
- this->regf_width = regf_width;
- this->m_req.resize(regf_width);
- this->m_occ_new.resize(regf_width);
- this->m_occ_upd.resize(regf_width);
- this->m_occ_ext.resize(regf_width);
-
- // initialize the warp pool
- // (make sure the thread id's are init to -1)
- this->warp_pool.resize(n_threads);
- for (i=0; i<warp_pool.size(); i++) {
- warp_pool[i].pc = -1;
- warp_pool[i].tid = new int[simd_width];
- memset(warp_pool[i].tid, -1, sizeof(int)*simd_width);
- warp_pool[i].occ = 0;
- warp_pool[i].next_warp = -1;
-
- // push the index to the warp allocator
- free_warp_q.push_back(i);
- }
-
- // setup for various heuristics
- this->heuristic = heuristic;
- switch (heuristic) {
- case MAJORITY:
- issue_warp_MAJ = new issue_warp_majority_queue(simd_width, &warp_pool);
- break;
- case MAJORITY_MAXHEAP: {
- int mh_lut_size = 32;
- int mh_lut_assoc = 4;
- int n_reads_per_cycle_lut = 4;
- int n_writes_per_cycle_lut = 4;
- int mh_size = 128;
- int n_reads_per_cycle_mh = 4;
- int n_writes_per_cycle_mh = 4;
- if (policy_opt != NULL) {
- sscanf(policy_opt, ";LUT=%d:%dr%dw%d;MH=%dr%dw%d",
- &mh_lut_size, &mh_lut_assoc, &n_reads_per_cycle_lut, &n_writes_per_cycle_lut,
- &mh_size, &n_reads_per_cycle_mh, &n_writes_per_cycle_mh);
- }
- issue_warp_MAJ = new issue_warp_majority_heap(simd_width, &warp_pool,
- mh_lut_size, mh_lut_assoc, mh_size,
- n_reads_per_cycle_lut, n_writes_per_cycle_lut,
- n_reads_per_cycle_mh, n_writes_per_cycle_mh);
- }
- break;
- }
-
- this->just_resume = false;
-
- this->max_warppool_occ = 0;
- this->warppool_occ_histo = new int[n_threads];
- memset(this->warppool_occ_histo, 0, n_threads*sizeof(int));
-}
-
-// should never be called (only at exit?)
-dwf_hw_sche_class::~dwf_hw_sche_class( )
-{
- unsigned i;
-
- for (i=0; i<warp_pool.size(); i++) {
- free(warp_pool[i].tid);
- }
-
- delete[] this->warppool_occ_histo;
-
- delete warp_lut_pc;
-}
-
-// allocate a new warp in warp pool
-int dwf_hw_sche_class::allocate_warp( address_type pc, bool update_scheduler )
-{
- int idx;
- assert(!free_warp_q.empty());
- idx = free_warp_q.front();
- free_warp_q.pop_front();
- warp_pool[idx].uid = uid_cnt;
- uid_cnt++;
- warp_pool[idx].pc = pc;
- warp_pool[idx].next_warp = -1;
- warp_pool[idx].lut_ptr = NULL;
-
- if (update_scheduler) {
- if (heuristic == FIFO) issue_warp_FIFO_q.push(idx);
- if (heuristic == PC) issue_warp_PC_q.push(idx);
- if (heuristic == MAJORITY || heuristic == MAJORITY_MAXHEAP)
- issue_warp_MAJ->push_warp(pc, idx);
- if (heuristic == PDOMPRIO) issue_warp_pdom.push_warp(pc, idx);
- }
-
- return idx;
-}
-
-// free a warp in warp pool
-// it will reset the content of the warp entry as well
-void dwf_hw_sche_class::free_warp( int idx, bool update_warplut )
-{
- bool redundant_idx_check = false;
- if (redundant_idx_check) {
- deque<int>::iterator dit = find(free_warp_q.begin(), free_warp_q.end(), idx);
- assert(dit == free_warp_q.end());
- }
-
- warp_pool[idx].pc = -1;
- memset(warp_pool[idx].tid, -1, sizeof(int)*simd_width);
- warp_pool[idx].occ = 0;
- warp_pool[idx].next_warp = -1;
- if (update_warplut) {
- warp_lut_pc->invalidate_entry( (warplut_entry_t*)warp_pool[idx].lut_ptr, idx );
- }
-
- free_warp_q.push_back(idx);
- assert(free_warp_q.size() <= warp_pool.size());
-}
-
-warplut_entry_t* dwf_hw_sche_class::lookup_pc2warp( const warp_tag_t& lookup_tag )
-{
- bool lut_missed = false;
-
- warplut_entry_t* lut_entry;
- lut_entry = warp_lut_pc->lookup_pc2warp( lookup_tag, lut_missed );
-
- if (!lut_missed) {
- if (lut_entry->tag != warp_pool[lut_entry->idx].pc) lut_missed = true;
- }
-
- if (lut_missed) {
- if (npc_tracker.pc_count.find(lookup_tag.get_pc()) != npc_tracker.pc_count.end()) {
- lut_realmiss++; // ie. the incoming warp lost an opportunity to merge
- }
- }
-
- return lut_entry;
-}
-
-
-void fill_all (vector<char>& container, const char& value)
-{
- fill(container.begin(), container.end(), value);
-}
-
-int regfile_hash(signed istream_number, unsigned simd_size, unsigned n_banks);
-int dwf_hw_sche_class::update_warp( int *tid, address_type pc )
-{
- int i;
- bool newwarp = false;
- bool newwarp_alloc = false;
- warplut_entry_t* lut_entry;
- warp_tag_t warp_tag(pc);
- lut_entry = lookup_pc2warp(warp_tag);
-
- // no LUT entry returned, stall
- if (!lut_entry) {
- assert(0);
- }
-
- if (heuristic == MAJORITY || heuristic == MAJORITY_MAXHEAP) {
- issue_warp_MAJ->add_threads(pc, tid);
- }
-
- npc_tracker.add_threads( tid, pc );
-
- // if the pc of the LUT entry does not match,
- // allocate a new entry
- if (lut_entry->tag != warp_tag) {
- lut_entry->idx = allocate_warp(pc);
- lut_entry->tag = warp_tag;
- lut_entry->occ = 0;
- assert(warp_pool[lut_entry->idx].pc == pc);
- newwarp = true;
- newwarp_alloc = true;
- }
-
- // create the request vector
- bool tid_has_valid_entry = false;
- fill_all(m_req, 0);
- for (i = 0; i<simd_width; i++) {
- if (tid[i] != -1) {
- int lane = regfile_hash(tid[i],simd_width,regf_width);
- // make sure we are not having two threads going to same lane
- assert(lane < regf_width);
- m_req[lane] += 1;
- tid_has_valid_entry = true;
- }
- }
- assert(tid_has_valid_entry);
-
- // read the old idx pointing to an existing warp
- int old_idx = lut_entry->idx;
-
- // create the conflict vector
- fill_all(m_occ_ext, 0);
- int regf_mask = regf_width - 1;
- for (i = 0; i<simd_width; i++) {
- m_occ_ext[i & regf_mask] += ((lut_entry->occ & (1 << i)) == 0)? 0 : 1;
- }
- fill_all(m_occ_upd, 0);
- fill_all(m_occ_new, 0);
- int n_regf_slot = simd_width / regf_width;
- bool conflict = false;
- for (i = 0; i<regf_width; i++) {
- if (m_occ_ext[i] + m_req[i] > n_regf_slot) {
- m_occ_new[i] = m_occ_ext[i] + m_req[i] - n_regf_slot;
- m_occ_upd[i] = n_regf_slot - m_occ_ext[i];
- conflict = true;
- } else {
- m_occ_upd[i] = m_req[i];
- }
- }
-
- // if the pc of the warp mismatch with lut,
- // set conflict vector to all one.
- // that force all threads to the newly allocated warp
- if (warp_pool[old_idx].pc != pc) {
- conflict = true;
- for (i = 0; i<regf_width; i++) {
- m_occ_new[i] = m_req[i];
- m_occ_upd[i] = 0;
- m_occ_ext[i] = n_regf_slot;
- }
- }
-
- // if there are conflicted entries, get a new warp
- int new_idx = -1;
- if (conflict) {
- new_idx = allocate_warp(pc);
- lut_entry->idx = new_idx;
- lut_entry->occ = 0; //update the lut_entry
- assert(warp_pool[new_idx].pc == pc);
-
- int total_occ = 0;
- for (i = 0; i < regf_width; i++)
- total_occ += m_occ_ext[i] + m_req[i];
- if (total_occ <= simd_width) warp_fragmentation += 1;
- warp_merge_conflict += 1;
-
- newwarp_alloc = true;
- }
-
- // update the warp as indicated by the LUT
- // if the lane is conflicted, or the old warp is just not
- // write to the new warp
- int new_occ = 0;
- fill_all(m_occ_new, 0);
- for (i = 0; i<simd_width; i++) {
- if (tid[i] != -1) {
- int rfbank = regfile_hash(tid[i],simd_width,regf_width);
- int lane = -1;
- if ((m_occ_ext[rfbank] < n_regf_slot) || newwarp) {
- lane = rfbank + m_occ_ext[rfbank] * regf_width;
- assert(lane < simd_width);
- warp_pool[old_idx].tid[lane] = tid[i];
- warp_pool[old_idx].occ++;
- lut_entry->occ |= (1<<lane);
- m_occ_ext[rfbank]++;
- } else {
- lane = rfbank + m_occ_new[rfbank] * regf_width;
- assert(lane < simd_width);
- warp_pool[new_idx].tid[lane] = tid[i];
- warp_pool[new_idx].occ++;
- new_occ |= (1<<lane);
- m_occ_new[rfbank]++;
- assert(m_occ_new[rfbank] <= n_regf_slot);
- }
- }
- }
-
- // to cover the case where the pc of the warp mismatch with lut
- // (because the warp is issued)
- if (warp_pool[old_idx].pc == pc) {
- issue_warp_pdom.add_threads(old_idx, pc);
- }
- if (conflict) {
- lut_entry->occ = new_occ;
- issue_warp_pdom.add_threads(new_idx, pc);
- }
-
- warp_pool[lut_entry->idx].lut_ptr = lut_entry; // link up the lut entry and warp
-
- bool scheduler_consistency_check = false;
- if (scheduler_consistency_check && heuristic == MAJORITY) {
- ((issue_warp_majority_queue*)issue_warp_MAJ)->check_consistency();
- }
-
- return 1;
-}
-
-// called AFTER threads hit a barrier to insert them into the barrier queue
-// ASSUME: threads from released barrier are not hitting second barrier right away
-int dwf_hw_sche_class::update_warp_at_barrier( int* tid, address_type pc, int cta_id, int barrier_num )
-{
- assert(barrier_num < m_nbarriers);
- assert(cta_id >= 0);
-
- int i;
- int warp_index = 0xDEADBEEF;
-
- npc_tracker.add_threads( tid, pc );
-
- // always allocate new warp
- warp_index = allocate_warp(pc, false);
- assert(warp_pool[warp_index].pc == pc);
-
- // no need to create the request vector
- // no need to create the conflict vector
-
- // assign threads into the new warp
- fill_all(m_occ_ext, 0);
- int max_nthreads_per_rfbank = simd_width / regf_width;
- for (i = 0; i<simd_width; i++) {
- if (tid[i] != -1) {
- int rfbank = regfile_hash(tid[i],simd_width,regf_width);
- int lane = -1;
-
- assert(m_occ_ext[rfbank] < max_nthreads_per_rfbank);
- lane = rfbank + m_occ_ext[rfbank] * regf_width;
- assert(lane < simd_width);
- warp_pool[warp_index].tid[lane] = tid[i];
- warp_pool[warp_index].occ++;
- m_occ_ext[rfbank]++;
- }
- }
-
- warp_pool[warp_index].lut_ptr = NULL; // no link to any lut entry
-
- // put the warp id into barrier queue
- m_barrier[cta_id].m_queue.push_back(warp_index);
-
- // notify issue module to check this barrier at issue
- if ( m_barrier[cta_id].ready_to_issue() ) {
- m_cta_released_barrier.insert(cta_id);
- }
-
- return 1;
-}
-
-// called at decode stage when thread hit a barrier
-// ASSUME: threads from released barrier are not hitting second barrier right away
-void dwf_hw_sche_class::hit_barrier( int cta_id, int barrier_num )
-{
- assert(barrier_num < m_nbarriers);
- assert(cta_id >= 0);
-
- m_barrier[cta_id].m_release = false;
-}
-
-// called at decode stage when all thread in cta hit the barrier
-// ASSUME: threads from released barrier are not hitting second barrier right away
-void dwf_hw_sche_class::release_barrier( int cta_id, int barrier_num )
-{
- assert(barrier_num < m_nbarriers);
- assert(cta_id >= 0);
-
- map<int, dwf_barrier>::iterator i_barrier = m_barrier.find(cta_id);
- assert(i_barrier != m_barrier.end()); // barrier has to exists in the first place!
- i_barrier->second.m_release = true;
-}
-
-void dwf_hw_sche_class::issue_warp( int *tid, address_type *pc )
-{
- int i;
- bool warp_issued = false;
-
- // scan the released barriers for ready warp
- // TODO: arbitrate between different queues?
- set<int>::iterator i_ctabar = m_cta_released_barrier.begin();
- for (; i_ctabar != m_cta_released_barrier.end(); ++i_ctabar) {
- int cta_id = *i_ctabar;
- map<int, dwf_barrier>::iterator i_barrier = m_barrier.find(cta_id);
-
- if ( i_barrier->second.ready_to_issue() ) {
- int warp_idx = i_barrier->second.m_queue.front();
-
- for (i = 0; i < simd_width; i++) {
- tid[i] = warp_pool[warp_idx].tid[i];
- }
- *pc = warp_pool[warp_idx].pc;
-
- i_barrier->second.m_queue.pop_front();
- free_warp(warp_idx, false); // don't update warplut as the warp is not linked to it
-
- // remove cta from checking list if the queue is emptied
- // (if the last threads haven't made it back to scheduler in time,
- // update_warp_at_barrier will insert the cta id again)
- if (i_barrier->second.m_queue.empty()) {
- m_cta_released_barrier.erase(i_ctabar);
- }
-
- warp_issued = true;
-
- break;
- }
- }
-
- if (!warp_issued) {
- switch (heuristic) {
- case FIFO:
- // Oldest warp are issued first
- if (!issue_warp_FIFO_q.empty()) {
- int idx = issue_warp_FIFO_q.front();
- for (i = 0; i < simd_width; i++) {
- tid[i] = warp_pool[idx].tid[i];
- }
- *pc = warp_pool[idx].pc;
-
- issue_warp_FIFO_q.pop();
- free_warp(idx);
- } else {
- memset(tid, -1, sizeof(int)*simd_width);
- *pc = -1;
- }
- break;
- case PC:
- // lowest PC warp are issued first
- if (!issue_warp_PC_q.empty()) {
- int idx = issue_warp_PC_q.top();
- for (i = 0; i < simd_width; i++) {
- tid[i] = warp_pool[idx].tid[i];
- }
- *pc = warp_pool[idx].pc;
-
- issue_warp_PC_q.pop();
- free_warp(idx);
- } else {
- memset(tid, -1, sizeof(int)*simd_width);
- *pc = -1;
- }
- break;
- case MAJORITY:
- case MAJORITY_MAXHEAP:
- // issue the most common PC first
- {
- int idx = issue_warp_MAJ->pop_warp();
- if (idx >= 0) {
- for (i = 0; i < simd_width; i++) {
- tid[i] = warp_pool[idx].tid[i];
- }
- *pc = warp_pool[idx].pc;
- free_warp(idx);
- } else {
- memset(tid, -1, sizeof(int)*simd_width);
- *pc = -1;
- }
- }
- break;
- case PDOMPRIO:
- // issue the warp with lowest PDOM count
- {
- int idx = issue_warp_pdom.front_warp();
- if (idx >= 0) {
- issue_warp_pdom.pop_warp();
-
- for (i = 0; i < simd_width; i++) {
- tid[i] = warp_pool[idx].tid[i];
- }
- *pc = warp_pool[idx].pc;
- free_warp(idx);
-
- just_resume = false;
- } else {
- memset(tid, -1, sizeof(int)*simd_width);
- *pc = -1;
- }
- }
- break;
- default:
- printf("Unsupported Heuristics!\n");
- abort();
- break;
- }
- }
-
- npc_tracker.sub_threads( tid, *pc );
-
- int warppool_occ = warp_pool.size() - free_warp_q.size();
- if (max_warppool_occ < warppool_occ) {
- max_warppool_occ = warppool_occ;
- }
- warppool_occ_histo[warppool_occ] += 1;
-}
-
-void dwf_hw_sche_class::init_cta(int start_thread, int cta_size, address_type start_pc)
-{
- assert((start_thread % simd_width) == 0); // thread id starting at a warp
-
- int n_warp_2assign = cta_size / simd_width;
- n_warp_2assign += (cta_size % simd_width)? 1 : 0; // round up
-
- static int *thd_id = NULL;
- if (thd_id == NULL) thd_id = new int[simd_width];
-
- for (int w = 0; w < n_warp_2assign; w++) {
- // generate the warp update register for each warp
- fill_n(thd_id, simd_width, -1);
- int warp_start_tid = start_thread + w * simd_width;
- for (int i = 0; (i < simd_width) && (warp_start_tid + i) < (start_thread + cta_size); i++) {
- thd_id[i] = warp_start_tid + i;
- }
-
- // push these warps into DWF scheduler
- update_warp( thd_id, start_pc );
- }
-}
-
-void dwf_hw_sche_class::print_free_warp_q( FILE *fout )
-{
- fprintf(fout, "free_node_q (%zd)= ", free_warp_q.size() );
- deque<int>::iterator dit = free_warp_q.begin();
- for (; dit != free_warp_q.end(); dit++) {
- fprintf(fout, "%03d ", *dit);
- }
- fprintf(fout, "\n");
-}
-
-void print_warp( FILE *fout, warp_entry_t warp_e, int simd_width )
-{
- fprintf(fout, "\t%02d 0x%08x: (", warp_e.pdom_prio, warp_e.pc );
- for (int i=0;i<simd_width;i++) {
- fprintf(fout, "%03d ", warp_e.tid[i]);
- }
- fprintf(fout, ")\n");
-}
-
-void dwf_hw_sche_class::print_warp_pool( FILE *fout )
-{
- for (unsigned i=0; i< warp_pool.size(); i++) {
- if (warp_pool[i].pc != (address_type)-1) {
- fprintf(fout, "bp%03d:", i);
- print_warp(fout, warp_pool[i], simd_width);
- }
- }
-}
-
-void dwf_hw_sche_class::clear_policy_access( ) {
- if (heuristic == MAJORITY_MAXHEAP) {
- ((issue_warp_majority_heap*)issue_warp_MAJ)->clear_access( );
- }
-}
-
-void dwf_hw_sche_class::reset_policy_access( ) {
- if (heuristic == MAJORITY_MAXHEAP) {
- ((issue_warp_majority_heap*)issue_warp_MAJ)->reset_access( );
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// c-wrapper interface
-///////////////////////////////////////////////////////////////////////////
-
-int dwf_hw_n_sche = 0;
-dwf_hw_sche_class **dwf_hw_sche;
-unsigned *acc_dyn_pcs = NULL;
-
-void create_dwf_schedulers( int n_shaders,
- int lut_size, int lut_assoc,
- int simd_width, int regf_width,
- int n_threads, int insn_size,
- int heuristic,
- char *policy_opt )
-{
- dwf_hw_n_sche = n_shaders;
- dwf_hw_sche = new dwf_hw_sche_class*[n_shaders];
- for (int i=0; i<n_shaders; i++) {
- dwf_hw_sche[i] = new dwf_hw_sche_class( lut_size, lut_assoc,
- simd_width, regf_width,
- n_threads, insn_size,
- heuristic, i,
- policy_opt );
- }
-
- if (acc_dyn_pcs == NULL) {
- acc_dyn_pcs = new unsigned[n_shaders];
- std::fill_n(acc_dyn_pcs, n_shaders, 0);
- }
- for (int i=0; i<n_shaders; i++) {
- dwf_hw_sche[i]->npc_tracker.acc_pc_count = &acc_dyn_pcs[i];
- }
-}
-
-int dwf_update_warp( int shd_id, int* tid, address_type pc )
-{
- return dwf_hw_sche[shd_id]->update_warp( tid, pc );
-}
-
-int dwf_update_warp_at_barrier( int shd_id, int* tid, address_type pc, int cta_id )
-{
- return dwf_hw_sche[shd_id]->update_warp_at_barrier( tid, pc, cta_id);
-}
-
-void dwf_hit_barrier( int shd_id, int cta_id )
-{
- dwf_hw_sche[shd_id]->hit_barrier( cta_id );
-}
-
-void dwf_release_barrier( int shd_id, int cta_id )
-{
- dwf_hw_sche[shd_id]->release_barrier( cta_id );
-}
-
-void dwf_issue_warp( int shd_id, int *tid, address_type *pc )
-{
- dwf_hw_sche[shd_id]->issue_warp( tid, pc );
-}
-
-void dwf_clear_accessed( int shd_id )
-{
- dwf_hw_sche[shd_id]->clear_accessed( );
-}
-
-void dwf_clear_policy_access( int shd_id )
-{
- dwf_hw_sche[shd_id]->clear_policy_access( );
-}
-
-void dwf_reset_policy_access( int shd_id )
-{
- dwf_hw_sche[shd_id]->reset_policy_access( );
-}
-
-void dwf_init_CTA(int shd_id, int start_thread, int cta_size, address_type start_pc)
-{
- dwf_hw_sche[shd_id]->init_cta(start_thread, cta_size, start_pc);
- dwf_hw_sche[shd_id]->clear_accessed( );
- dwf_hw_sche[shd_id]->clear_policy_access( );
-}
-
-void dwf_print_stat( FILE* fout )
-{
- dwf_hw_sche_class::print_stats( fout );
- npc_tracker_class::histo_print( fout );
- fprintf(fout, "max_warppool_occ = ");
- for (int i=0; i<dwf_hw_n_sche; i++) {
- fprintf(fout, "%d ", dwf_hw_sche[i]->max_warppool_occ);
- }
- fprintf(fout, "\n");
- for (int i=0; i<dwf_hw_n_sche; i++) {
- fprintf(fout, "warppool_occ[%d] = ", i);
- for (int j=0; j<dwf_hw_sche[i]->max_warppool_occ; j++) {
- fprintf(fout, "%d ", dwf_hw_sche[i]->warppool_occ_histo[j]);
- }
- fprintf(fout, "\n");
- }
- if (dwf_hw_sche[0]->heuristic == MAJORITY_MAXHEAP) {
- fprintf(fout, "n_stall_on_maxheap = ");
- for (int i=0; i<dwf_hw_n_sche; i++) {
- fprintf(fout, "%d ",
- ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->n_stall_on_maxheap);
- }
- fprintf(fout, "\n");
- fprintf(fout, "maxheap_n_entries = ");
- for (int i=0; i<dwf_hw_n_sche; i++) {
- fprintf(fout, "%d ",
- ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->maxheap.max_n_entries);
- }
- fprintf(fout, "\n");
- fprintf(fout, "maxheap_lut_n_aliased = ");
- for (int i=0; i<dwf_hw_n_sche; i++) {
- fprintf(fout, "%d ",
- ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->mh_lut.n_aliased);
- }
- fprintf(fout, "\n");
- issue_warp_majority_heap::print_stat(fout);
- }
-}
-
-void dwf_reset_reconv_pt()
-{
- issue_warp_pdom_prio::reconvgence_pt.clear();
-}
-
-void dwf_insert_reconv_pt(address_type pc)
-{
- issue_warp_pdom_prio::reconvgence_pt.insert(pc);
-}
-
-void dwf_reinit_schedulers( int n_shaders )
-{
- for (int i=0; i<n_shaders; i++) {
- dwf_hw_sche[i]->issue_warp_pdom.reinit();
- }
-}
-
-void dwf_update_statistics( int shader_id )
-{
- dwf_hw_sche[shader_id]->npc_tracker.update_acc_count();
-}
-
-void g_print_dmaj_scheduler(int sid) {
- dwf_hw_sche[sid]->issue_warp_MAJ->print(stdout);
-}
-
-void g_print_warp_lut(int sid) {
- dwf_hw_sche[sid]->warp_lut_pc->print(stdout);
-}
-
-void g_print_free_warp_q(int sid) {
- dwf_hw_sche[sid]->print_free_warp_q(stdout);
-}
-
-void g_print_warp_pool(int sid) {
- dwf_hw_sche[sid]->print_warp_pool(stdout);
-}
-
-void g_print_max_heap(int sid) {
- dwf_hw_sche[sid]->issue_warp_MAJ->print(stdout);
-}
-
-#ifdef UNIT_TEST
-
- #undef UNIT_TEST
- #include "stat-tool.cc"
-
-int regfile_hash(signed istream_number, unsigned simd_size, unsigned n_banks) {
- if (gpgpu_thread_swizzling) {
- signed warp_ID = istream_number / simd_size;
- return((istream_number + warp_ID) % n_banks);
- } else {
- return(istream_number % n_banks);
- }
-}
-
-int log2i(int n) {
- int lg;
- lg = -1;
- while (n) {
- n>>=1;lg++;
- }
- return lg;
-}
-
-int test_FIFO()
-{
- dwf_hw_sche_class *dwf_sche;
- int i;
- int tid[6][4] = {
- { 0, 1, 2, 3},
- { 4, 5, 6, 7},
- { 8,-1,10,-1},
- {-1, 1,-1, 3},
- { 4, 9,-1,11},
- {-1,13,14,-1}
- };
-
- int expect_out[12][4] = {
- { 0, 1, 2, 3},
- { 0, 1, 2, 3},
- { 0, 1, 2, 3},
- { 4, 5, 6, 7},
- { 8, 1,10, 3},
- { 4, 9,14,11},
- {-1,13,-1,-1},
- { 4, 9,-1,11},
- {-1,13,14,-1},
- { 8,-1,10,-1},
- { 4, 9,14,11},
- { 8,13,10,-1}
- };
-
- int tid_out[4];
- address_type pc_out;
-
- dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, FIFO);
-
- // same threads - different pc
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[0], 0x409a80);
- dwf_sche->update_warp(tid[0], 0x409a88);
-
- // different threads - different pc
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[0], 0x409a90);
- dwf_sche->update_warp(tid[1], 0x409a80);
-
- // different threads - same pc
- // expect two warp to merge into one as there is no lane conflict
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[2], 0x409a90);
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[3], 0x409a90);
-
- // same as above, but with lane conflict
- // expect a new warp allocated,
- // but only the conflicting threads goes to new warp
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[4], 0x409a80);
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[5], 0x409a80);
-
- // different threads - different pc
- // purposely try to alias an existing mapping
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[4], 0x410a80);
- dwf_sche->update_warp(tid[5], 0x411a80);
-
- // going back to that mapping
- // a new warp should be allocated (despite lack of conflict)
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[2], 0x409a80);
-
- // testing the occupancy vector
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[4], 0x409aa0);
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[5], 0x409aa0);
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[2], 0x409aa0);
-
- // fill the warp pool up
- for (i=12; i<64; ) {
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[1], 0x409a80 + 8 * i++);
- dwf_sche->update_warp(tid[4], 0x409a80 + 8 * i++);
- }
- // issue all the warp (do some auto checking on the way)
- for (i=0; i<64; i++) {
- dwf_sche->issue_warp(tid_out, &pc_out);
- printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]);
- if (i<12) {
- if ( memcmp(tid_out, expect_out[i], 4*sizeof(int) ) ) {
- printf("%d warp mismatches\n", i);
- assert(0);
- }
- }
- }
-
- // now that all warpes are issue, no entries in the lut is valid
- // updating warp with an old address that remains in the lut
- // to see if detects the invalid lut entry
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[2], 0x409a80 + 8 * 63);
- dwf_sche->update_warp(tid[3], 0x409a80 + 8 * 62);
- dwf_sche->issue_warp(tid_out, &pc_out);
- assert(!memcmp(tid_out, tid[2], 4*sizeof(int) ));
- dwf_sche->issue_warp(tid_out, &pc_out);
- assert(!memcmp(tid_out, tid[3], 4*sizeof(int) ));
-
- dwf_sche->print_warp_pool(stdout);
- dwf_sche->warp_lut_pc->print(stdout);
- dwf_hw_sche_class::print_stats(stdout);
-
- delete dwf_sche;
-
- return 0;
-}
-
-int test_PC ()
-{
- dwf_hw_sche_class *dwf_sche;
- int i;
- int tid[4][4] = {
- { 0, 1, 2, 3},
- { 4, 5, 6, 7},
- { 8,-1,10,-1},
- {-1,13,14,-1}
- };
-
- int tid_out[4];
- address_type pc_out;
-
- dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, PC);
-
- // fill the warp pool up in reverse PC order
- for (i=0; i<4; i++) {
- for (int j=0; j<4; j++) {
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[j], 0x409a80 - 8 * i);
- }
- }
-
- // issue the warps, expect them to be in PC order, with higher occ warp issued first
- printf("PC Issue Logic:\n");
- for (i=0; i<4; i++) {
- for (int j=0; j<4; j++) {
- dwf_sche->issue_warp(tid_out, &pc_out);
- printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]);
- }
- }
-
-}
-
-int test_MAJ ()
-{
- dwf_hw_sche_class *dwf_sche;
- int i;
- int tid[4][4] = {
- { 0, 1, 2, 3},
- { 4, 5, 6, 7},
- { 8,-1,10,-1},
- {-1,13,14,-1}
- };
-
- int tid_out[4];
- address_type pc_out;
-
- dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, MAJORITY);
-
- // fill the warp pool up in reverse PC order
- for (i=0; i<4; i++) {
- for (int j=0; j<(4-i); j++) {
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[j], 0x409a80 - 8 * i);
- }
- }
-
- // issue the warps, expect them to be in PC order, with higher occ warp issued first
- printf("Majority Issue Logic:\n");
- for (i=0; i<4; i++) {
- for (int j=0; j<4; j++) {
- dwf_sche->issue_warp(tid_out, &pc_out);
- printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]);
- }
- }
-}
-
-int test_MAJ_HEAP ()
-{
- printf("\ntest_MAJ_HEAP:\n");
- dwf_hw_sche_class *dwf_sche;
- int i;
- int tid[4][4] = {
- { 0, 1, 2, 3},
- { 4, 5, 6, 7},
- { 8,-1,10,-1},
- {-1,13,14,-1}
- };
-
- int tid_out[4];
- address_type pc_out;
-
- dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, MAJORITY_MAXHEAP);
-
- // fill the warp pool up in reverse PC order
- for (i=0; i<4; i++) {
- for (int j=0; j<(i+1); j++) {
- dwf_sche->clear_accessed();
- dwf_sche->update_warp(tid[j], 0x409a80 + 8 * i);
- }
- }
-
- dwf_sche->reset_policy_access();
- dwf_sche->issue_warp_MAJ->print(stdout);
-
- // issue the warps, expect them to be in PC order, with higher occ warp issued first
- printf("Majority (Max Heap) Issue Logic:\n");
- for (i=0; i<4; i++) {
- for (int j=0; j<4; j++) {
- dwf_sche->issue_warp(tid_out, &pc_out);
- printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]);
- }
- dwf_sche->reset_policy_access();
- }
-}
-
-void test_warp_lut_pc ()
-{
- printf("\ntest_warp_lut_pc:\n");
- warp_lut_sa<pc_tag> warp_lut_pc(16, // size
- 4, // assoc
- 1); // insn_size
-
- address_type pc_value[] = {0, 4, 0, 8, 12, 16, 20, 8, 8, 0};
- int n_entry = sizeof(pc_value) / sizeof(address_type);
- vector<pc_tag> pc_stream(pc_value, pc_value + n_entry);
-
- int misses = 0;
- for (int n = 0; n < n_entry * 100; n++) {
- int i = n % n_entry;
- tag2warp_entry_t<pc_tag> *lut_entry = NULL;
- bool lut_miss = false;
-
- lut_entry = warp_lut_pc.lookup_pc2warp(pc_stream[i], lut_miss);
-
- if (lut_entry->tag != pc_stream[i]) {
- lut_entry->tag = pc_stream[i];
- lut_entry->occ = 1;
- misses += 1;
- }
- warp_lut_pc.clear_accessed();
- lut_entry->accessed = 0;
- }
-
- printf("Number of Miss = %d\n", misses);
-}
-
-int main () {
- //test_FIFO();
- //test_PC();
- //test_MAJ();
- test_MAJ_HEAP();
- test_warp_lut_pc();
- return 0;
-}
-
-#endif