From e0f1b4359832ba2952ddcff3a400cd7e1e3d02b5 Mon Sep 17 00:00:00 2001 From: Tor Aamodt Date: Tue, 5 Oct 2010 13:34:47 -0800 Subject: 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] --- src/gpgpu-sim/dwf.cc | 2606 -------------------------------------------------- 1 file changed, 2606 deletions(-) delete mode 100644 src/gpgpu-sim/dwf.cc (limited to 'src/gpgpu-sim/dwf.cc') 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 -#include -#include -#include -#include - -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 *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[n_set]; - for (i=0; in_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::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::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::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; ilut = 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 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_pool; - int simd_width; - - int n_stall_on_maxheap; - - queue update_queue; - static pow2_histogram n_pending_updates_histo; - - issue_warp_majority_heap (int simd_width = 0, vector *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= 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 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= 0) this->n_thds++; - } - } - - // called right after a warp is issued - void sub_threads( int *tid ) { - for (int i=0; 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::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 majority_map; - set warpq_set; - warp_queue* maj_warp; - - vector *warp_pool; - int simd_width; - - issue_warp_majority_queue(int simd_width = 0, vector *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::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::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::iterator set_it = warpq_set.begin(); - for (; set_it != warpq_set.end(); set_it++) { - warp_queue* bq = (*set_it); - - int real_nthds = 0; - deque::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_pool; - lesspdom_first( vector *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_pool; - int* thd_pdom_prio; - int simd_width; - int n_threads; - - int resort_needed; - list pdom_pqueue; //the queue holding all index - - lesspdom_first lesspdom_cmp; - - static set reconvgence_pt; //table holding all recvg pt - - issue_warp_pdom_prio (int simd_width = 0, vector *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= 0 && !(pdom_occ & (1<= 0) { - thd_pdom_prio[(*warp_pool)[bidx].tid[i]] = (*warp_pool)[bidx].pdom_prio; - } - } - } - - return bidx; - } - -}; - -set issue_warp_pdom_prio::reconvgence_pt = set(); -//*/ - - -class npc_tracker_class { -public: - map pc_count; - unsigned* acc_pc_count; - int simd_width; - static map 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= 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::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 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 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 tag2warp_set { -public: - vector< tag2warp_entry_t > entry; - list< tag2warp_entry_t* > lru_stack; - - tag2warp_set(int assoc = 0) : entry(assoc) { - for (unsigned j=0; jentry.size(); j++) { - this->lru_stack.push_back(&(this->entry[j])); - } - } - - tag2warp_set(const tag2warp_set& other) : entry(other.entry.size()) { - for (unsigned j=0; jentry.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 warp_lut { -public: - virtual ~warp_lut() {} - virtual tag2warp_entry_t* lookup_pc2warp( const Tag& tag, bool& lut_missed ) = 0; - virtual void invalidate_entry( tag2warp_entry_t* lut_entry, int warp_idx ) = 0; - virtual void clear_accessed( ) = 0; - virtual void print( FILE* fout) = 0; -}; - -template -class warp_lut_sa : public warp_lut { -private: - int lut_size; - int lut_assoc; - vector< tag2warp_set > tag2warp_lut; - int insn_size_lgb2; - - queue< tag2warp_entry_t* > lut_accessed_q; // store accessed lut entry for clear - - struct same_tag { - Tag tag; - bool operator()(tag2warp_entry_t* 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(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* lookup_pc2warp( const Tag& tag, bool& lut_missed ); - void invalidate_entry( tag2warp_entry_t* 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 unsigned int warp_lut_sa::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 -tag2warp_entry_t* warp_lut_sa::lookup_pc2warp( const Tag &tag, bool &lut_missed ) -{ - tag2warp_entry_t* lut_entry = NULL; - unsigned hashed_pc = tag.lut_hash(insn_size_lgb2, tag2warp_lut.size()); - list< tag2warp_entry_t* > &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* >::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 -void warp_lut_sa::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 warp_lut_perfect : public warp_lut { -private: - typedef map< Tag, tag2warp_entry_t* > 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* lookup_pc2warp( const Tag& tag, bool& lut_missed ) { - typename warp_map_t::iterator mit = m_tag2entry_map.find(tag); - - tag2warp_entry_t* 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(); - 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* 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 unsigned int warp_lut_perfect::lut_max_size = 0; - - -typedef tag2warp_entry_t warplut_entry_t; -typedef pc_tag warp_tag_t; - -class dwf_hw_sche_class { -public: - int m_id; - warp_lut *warp_lut_pc; - vector warp_pool; - deque free_warp_q; // the warp allocator - int simd_width; - int regf_width; - int insn_size_lgb2; - bool just_resume; - - vector m_req; // request vector from incoming warp - vector m_occ_new; // occupancy vector of the new warp, double as conflict vector - vector m_occ_upd; // occupancy vector of the updated existing warp - vector 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 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 - 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 issue_warp_FIFO_q; - - // PC warp issue logic - class pc_first { - public: - vector &warp_pool; - pc_first( vector &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, 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::print_stats( fout ); - warp_lut_sa::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 *) new warp_lut_perfect() : - (warp_lut *) new warp_lut_sa(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; iheuristic = 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; iwarppool_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::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& 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; iidx; - - // create the conflict vector - fill_all(m_occ_ext, 0); - int regf_mask = regf_width - 1; - for (i = 0; iocc & (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 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; iidx = 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; iocc |= (1<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= 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::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::iterator i_ctabar = m_cta_released_barrier.begin(); - for (; i_ctabar != m_cta_released_barrier.end(); ++i_ctabar) { - int cta_id = *i_ctabar; - map::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::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;iclear_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; inpc_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; imax_warppool_occ); - } - fprintf(fout, "\n"); - for (int i=0; iwarppool_occ_histo[j]); - } - fprintf(fout, "\n"); - } - if (dwf_hw_sche[0]->heuristic == MAJORITY_MAXHEAP) { - fprintf(fout, "n_stall_on_maxheap = "); - for (int i=0; iissue_warp_MAJ)->n_stall_on_maxheap); - } - fprintf(fout, "\n"); - fprintf(fout, "maxheap_n_entries = "); - for (int i=0; iissue_warp_MAJ)->maxheap.max_n_entries); - } - fprintf(fout, "\n"); - fprintf(fout, "maxheap_lut_n_aliased = "); - for (int i=0; iissue_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; iissue_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 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_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 *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 -- cgit v1.3