/* * Copyright (c) 2014-2015 Advanced Micro Devices, Inc. * All rights reserved. * * For use for simulation and test purposes only * * 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 copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Authors: John Kalamatianos, * Sooraj Puthoor, * Mark Wyse */ #include "gpu-compute/schedule_stage.hh" #include "gpu-compute/compute_unit.hh" #include "gpu-compute/gpu_static_inst.hh" #include "gpu-compute/vector_register_file.hh" #include "gpu-compute/wavefront.hh" ScheduleStage::ScheduleStage(const ComputeUnitParams *p) : numSIMDs(p->num_SIMDs), numMemUnits(p->num_global_mem_pipes + p->num_shared_mem_pipes) { for (int j = 0; j < numSIMDs + numMemUnits; ++j) { scheduler.emplace_back(p); } } ScheduleStage::~ScheduleStage() { scheduler.clear(); waveStatusList.clear(); } void ScheduleStage::init(ComputeUnit *cu) { computeUnit = cu; _name = computeUnit->name() + ".ScheduleStage"; for (int j = 0; j < numSIMDs + numMemUnits; ++j) { scheduler[j].bindList(&computeUnit->readyList[j]); } for (int j = 0; j < numSIMDs; ++j) { waveStatusList.push_back(&computeUnit->waveStatusList[j]); } dispatchList = &computeUnit->dispatchList; } void ScheduleStage::arbitrate() { // iterate over all Memory pipelines for (int j = numSIMDs; j < numSIMDs + numMemUnits; ++j) { if (dispatchList->at(j).first) { Wavefront *waveToMemPipe = dispatchList->at(j).first; // iterate over all execution pipelines for (int i = 0; i < numSIMDs + numMemUnits; ++i) { if ((i != j) && (dispatchList->at(i).first)) { Wavefront *waveToExePipe = dispatchList->at(i).first; // if the two selected wavefronts are mapped to the same // SIMD unit then they share the VRF if (waveToMemPipe->simdId == waveToExePipe->simdId) { int simdId = waveToMemPipe->simdId; // Read VRF port arbitration: // If there are read VRF port conflicts between the // a memory and another instruction we drop the other // instruction. We don't need to check for write VRF // port conflicts because the memory instruction either // does not need to write to the VRF (store) or will // write to the VRF when the data comes back (load) in // which case the arbiter of the memory pipes will // resolve any conflicts if (computeUnit->vrf[simdId]-> isReadConflict(waveToMemPipe->wfSlotId, waveToExePipe->wfSlotId)) { // FIXME: The "second" member variable is never // used in the model. I am setting it to READY // simply to follow the protocol of setting it // when the WF has an instruction ready to issue waveStatusList[simdId]->at(waveToExePipe->wfSlotId) .second = READY; dispatchList->at(i).first = nullptr; dispatchList->at(i).second = EMPTY; break; } } } } } } } void ScheduleStage::exec() { for (int j = 0; j < numSIMDs + numMemUnits; ++j) { uint32_t readyListSize = computeUnit->readyList[j].size(); // If no wave is ready to be scheduled on the execution resource // then skip scheduling for this execution resource if (!readyListSize) { continue; } Wavefront *waveToBeDispatched = scheduler[j].chooseWave(); dispatchList->at(j).first = waveToBeDispatched; waveToBeDispatched->updateResources(); dispatchList->at(j).second = FILLED; waveStatusList[waveToBeDispatched->simdId]->at( waveToBeDispatched->wfSlotId).second = BLOCKED; assert(computeUnit->readyList[j].size() == readyListSize - 1); } // arbitrate over all shared resources among instructions being issued // simultaneously arbitrate(); } void ScheduleStage::regStats() { }