mirror of
https://github.com/vortexgpgpu/vortex.git
synced 2025-06-28 09:37:38 -04:00
Some checks are pending
CI / setup (push) Waiting to run
CI / build (32) (push) Blocked by required conditions
CI / build (64) (push) Blocked by required conditions
CI / tests (cache, 32) (push) Blocked by required conditions
CI / tests (cache, 64) (push) Blocked by required conditions
CI / tests (config1, 32) (push) Blocked by required conditions
CI / tests (config1, 64) (push) Blocked by required conditions
CI / tests (config2, 32) (push) Blocked by required conditions
CI / tests (config2, 64) (push) Blocked by required conditions
CI / tests (debug, 32) (push) Blocked by required conditions
CI / tests (debug, 64) (push) Blocked by required conditions
CI / tests (opencl, 32) (push) Blocked by required conditions
CI / tests (opencl, 64) (push) Blocked by required conditions
CI / tests (regression, 32) (push) Blocked by required conditions
CI / tests (regression, 64) (push) Blocked by required conditions
CI / tests (scope, 32) (push) Blocked by required conditions
CI / tests (scope, 64) (push) Blocked by required conditions
CI / tests (stress, 32) (push) Blocked by required conditions
CI / tests (stress, 64) (push) Blocked by required conditions
CI / tests (synthesis, 32) (push) Blocked by required conditions
CI / tests (synthesis, 64) (push) Blocked by required conditions
CI / tests (vector, 32) (push) Blocked by required conditions
CI / tests (vector, 64) (push) Blocked by required conditions
CI / tests (vm, 32) (push) Blocked by required conditions
CI / tests (vm, 64) (push) Blocked by required conditions
CI / complete (push) Blocked by required conditions
167 lines
No EOL
5.5 KiB
C++
167 lines
No EOL
5.5 KiB
C++
// Copyright © 2019-2023
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "dram_sim.h"
|
|
#include "util.h"
|
|
#include <fstream>
|
|
|
|
DISABLE_WARNING_PUSH
|
|
DISABLE_WARNING_UNUSED_PARAMETER
|
|
DISABLE_WARNING_MISSING_FIELD_INITIALIZERS
|
|
#include <base/base.h>
|
|
#include <base/request.h>
|
|
#include <base/config.h>
|
|
#include <frontend/frontend.h>
|
|
#include <memory_system/memory_system.h>
|
|
DISABLE_WARNING_POP
|
|
|
|
using namespace vortex;
|
|
|
|
class DramSim::Impl {
|
|
private:
|
|
struct mem_req_t {
|
|
uint64_t addr;
|
|
bool is_write;
|
|
ResponseCallback callback;
|
|
void* arg;
|
|
};
|
|
|
|
Ramulator::IFrontEnd* ramulator_frontend_;
|
|
Ramulator::IMemorySystem* ramulator_memorysystem_;
|
|
uint32_t cpu_channel_size_;
|
|
uint64_t cpu_cycles_;
|
|
uint32_t scaled_dram_cycles_;
|
|
static const uint32_t tick_cycles_ = 1000;
|
|
static const uint32_t dram_channel_size_ = 16; // 128 bits
|
|
std::queue<mem_req_t> pending_reqs_;
|
|
|
|
void handle_pending_requests() {
|
|
if (pending_reqs_.empty())
|
|
return;
|
|
auto& req = pending_reqs_.front();
|
|
auto req_type = req.is_write ? Ramulator::Request::Type::Write : Ramulator::Request::Type::Read;
|
|
std::function<void(Ramulator::Request&)> callback = nullptr;
|
|
if (req.callback) {
|
|
callback = [req_callback = std::move(req.callback), req_arg = std::move(req.arg)](Ramulator::Request& /*dram_req*/) {
|
|
req_callback(req_arg);
|
|
};
|
|
}
|
|
if (ramulator_frontend_->receive_external_requests(req_type, req.addr, 0, callback)) {
|
|
if (req.is_write) {
|
|
// Ramulator does not handle write responses, so we fire the callback ourselves.
|
|
if (req.callback) {
|
|
req.callback(req.arg);
|
|
}
|
|
}
|
|
pending_reqs_.pop();
|
|
}
|
|
}
|
|
|
|
public:
|
|
Impl(uint32_t num_channels, uint32_t channel_size, float clock_ratio) {
|
|
YAML::Node dram_config;
|
|
dram_config["Frontend"]["impl"] = "GEM5";
|
|
dram_config["MemorySystem"]["impl"] = "GenericDRAM";
|
|
dram_config["MemorySystem"]["clock_ratio"] = 1;
|
|
dram_config["MemorySystem"]["DRAM"]["impl"] = "HBM2";
|
|
dram_config["MemorySystem"]["DRAM"]["org"]["preset"] = "HBM2_8Gb";
|
|
dram_config["MemorySystem"]["DRAM"]["org"]["density"] = 8192;
|
|
dram_config["MemorySystem"]["DRAM"]["org"]["channel"] = num_channels;
|
|
dram_config["MemorySystem"]["DRAM"]["timing"]["preset"] = "HBM2_2Gbps";
|
|
dram_config["MemorySystem"]["Controller"]["impl"] = "Generic";
|
|
dram_config["MemorySystem"]["Controller"]["Scheduler"]["impl"] = "FRFCFS";
|
|
dram_config["MemorySystem"]["Controller"]["RefreshManager"]["impl"] = "AllBank";
|
|
dram_config["MemorySystem"]["Controller"]["RowPolicy"]["impl"] = "OpenRowPolicy";
|
|
{
|
|
YAML::Node draw_plugin;
|
|
draw_plugin["ControllerPlugin"]["impl"] = "TraceRecorder";
|
|
draw_plugin["ControllerPlugin"]["path"] = "./trace/ramulator.log";
|
|
dram_config["MemorySystem"]["Controller"]["plugins"].push_back(draw_plugin);
|
|
}
|
|
dram_config["MemorySystem"]["AddrMapper"]["impl"] = "RoBaRaCoCh";
|
|
|
|
ramulator_frontend_ = Ramulator::Factory::create_frontend(dram_config);
|
|
ramulator_memorysystem_ = Ramulator::Factory::create_memory_system(dram_config);
|
|
ramulator_frontend_->connect_memory_system(ramulator_memorysystem_);
|
|
ramulator_memorysystem_->connect_frontend(ramulator_frontend_);
|
|
|
|
cpu_channel_size_ = channel_size;
|
|
scaled_dram_cycles_ = static_cast<uint64_t>(clock_ratio * tick_cycles_);
|
|
this->reset();
|
|
}
|
|
|
|
~Impl() {
|
|
std::ofstream nullstream("ramulator.stats.log");
|
|
auto original_buf = std::cout.rdbuf();
|
|
std::cout.rdbuf(nullstream.rdbuf());
|
|
ramulator_frontend_->finalize();
|
|
ramulator_memorysystem_->finalize();
|
|
std::cout.rdbuf(original_buf);
|
|
}
|
|
|
|
void reset() {
|
|
cpu_cycles_ = 0;
|
|
}
|
|
|
|
void tick() {
|
|
cpu_cycles_ += tick_cycles_;
|
|
while (cpu_cycles_ >= scaled_dram_cycles_) {
|
|
this->handle_pending_requests();
|
|
ramulator_memorysystem_->tick();
|
|
cpu_cycles_ -= scaled_dram_cycles_;
|
|
}
|
|
}
|
|
|
|
void send_request(uint64_t addr, bool is_write, ResponseCallback response_cb, void* arg) {
|
|
// enqueue the request
|
|
if (cpu_channel_size_ > dram_channel_size_) {
|
|
uint32_t n = cpu_channel_size_ / dram_channel_size_;
|
|
for (uint32_t i = 0; i < n; ++i) {
|
|
uint64_t dram_byte_addr = (addr / cpu_channel_size_) * dram_channel_size_ + (i * dram_channel_size_);
|
|
if (i == 0) {
|
|
pending_reqs_.push({dram_byte_addr, is_write, response_cb, arg});
|
|
} else {
|
|
pending_reqs_.push({dram_byte_addr, is_write, nullptr, nullptr});
|
|
}
|
|
}
|
|
} else if (cpu_channel_size_ < dram_channel_size_) {
|
|
uint64_t dram_byte_addr = (addr / cpu_channel_size_) * dram_channel_size_;
|
|
pending_reqs_.push({dram_byte_addr, is_write, response_cb, arg});
|
|
} else {
|
|
uint64_t dram_byte_addr = addr;
|
|
pending_reqs_.push({dram_byte_addr, is_write, response_cb, arg});
|
|
}
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DramSim::DramSim(uint32_t num_channels, uint32_t channel_size, float clock_ratio)
|
|
: impl_(new Impl(num_channels, channel_size, clock_ratio))
|
|
{}
|
|
|
|
DramSim::~DramSim() {
|
|
delete impl_;
|
|
}
|
|
|
|
void DramSim::reset() {
|
|
impl_->reset();
|
|
}
|
|
|
|
void DramSim::tick() {
|
|
impl_->tick();
|
|
}
|
|
|
|
void DramSim::send_request(uint64_t addr, bool is_write, ResponseCallback callback, void* arg) {
|
|
impl_->send_request(addr, is_write, callback, arg);
|
|
} |