Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ ramulator_config_path: ../configs/ramulator2_configs/HBM2_TPUv3.yaml # resolved
# Optional: NUMA-style DRAM partitions (channels must divide evenly)
# dram_num_partitions: 2

# --- Energy model (TOGSim, optional) ---
energy_cost_table_path: ../configs/energy_tables/hbm2.yml # resolved relative to this YAML’s directory
# Omit this key to skip the energy report.

# --- Interconnect (TOGSim) ---
icnt_type: simple # simple | booksim2
icnt_latency_cycles: 10 # used when icnt_type is simple
Expand Down Expand Up @@ -460,6 +464,7 @@ One-line meaning for each group (details in the YAML block above).
- **Core (`num_cores`, `core_freq_mhz`, `core_stats_print_period_cycles`, `num_systolic_array_per_core`, `sa_weight_buffer_depth`, optional `core_type`, STONNE keys)**: how many cores, their clock, stats cadence, systolic count per core, the per-SA resident weight-slot count (must be > 0; bounds preload run-ahead—raise it to loosen the throttle), and optional non-default mesh vs STONNE mix.
- **VPU (`vpu_*`)**: vector lane count, per-lane scratchpad (KB), and vector register width—**compiler** uses these for tiling/codegen.
- **DRAM (`dram_type`, `dram_channels`, …)**: `ramulator2` uses `ramulator_config_path`; `simple` uses fixed latency and optional bandwidth caps (`dram_bandwidth_gbps_*`, `dram_freq_mhz` when capped). `dram_num_partitions` splits channels for NUMA-style addressing.
- **Energy (`energy_cost_table_path`)**: selects a pJ cost table (see `configs/energy_tables/`) and enables an end-of-run `=== Energy statistics ===` section reporting off-chip DRAM energy, summed over all channels. Activation energy needs row state, so it requires `dram_type: ramulator2`. Interval stats are unaffected.
- **Interconnect (`icnt_*`, `booksim_config_path`)**: `simple` adds fixed hop latency (`icnt_latency_cycles`); `booksim2` points at a BookSim2 topology file.
- **Codegen (`codegen_*`)**: mapping strategy (heuristic / autotune / external-hybrid), external JSON path, autotune search limits, and fusion/optimization set for the PyTorch compiler path.
- **L2 (`l2d_type`, `l2d_config`, optional `l2d_hit_latency`)**: optional data cache between cores and DRAM; `l2d_config` uses AccelSim-style cache geometry strings.
Expand Down
2 changes: 1 addition & 1 deletion TOGSim/extern/ramulator2
3 changes: 3 additions & 0 deletions TOGSim/include/Dram.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class Dram {
virtual mem_fetch* top(uint32_t cid) = 0;
virtual void pop(uint32_t cid) = 0;
uint32_t get_channel_id(mem_fetch* request);
/** Activity for the energy report, summed over every channel. */
virtual DramEnergyCounters get_energy_counters() { return DramEnergyCounters{}; }
virtual void print_stat() {}
virtual void print_cache_stats() {};
uint32_t get_channels_per_partition() { return _n_ch_per_partition; }
Expand Down Expand Up @@ -65,6 +67,7 @@ class DramRamulator2 : public Dram {
virtual bool is_empty(uint32_t cid) override;
virtual mem_fetch* top(uint32_t cid) override;
virtual void pop(uint32_t cid) override;
virtual DramEnergyCounters get_energy_counters() override;
virtual void print_stat() override;
void print_cache_stats() override;

Expand Down
53 changes: 53 additions & 0 deletions TOGSim/include/EnergyModel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

/**
* Off-chip DRAM energy constants, read from the `offchip_dram` section of the
* energy cost table selected by the simulation config's
* `energy_cost_table_path`. All values are in pJ.
*/
struct DramEnergyCosts {
std::string name;
std::string path;
double row_activation_pj = 0.0;
/* Per-bit terms kept separate so the breakdown stays visible in the report. */
std::vector<std::pair<std::string, double>> transfer_pj_per_bit;

double transfer_pj_per_bit_total() const;
/** "dram 1.51 + io 1.17 + phy 0.80" */
std::string transfer_breakdown() const;
};

/** Raw activity a DRAM model reports for energy accounting, aggregated over all channels. */
struct DramEnergyCounters {
uint64_t row_activations = 0;
/* Column commands served. Each moves one burst, never a partial one. */
uint64_t transactions = 0;
/* Burst size, i.e. the DRAM model's transaction granularity. */
uint32_t bytes_per_transaction = 0;
/* False when the DRAM model tracks no row state, so activation energy is unknown. */
bool available = false;

uint64_t transferred_bits() const {
return transactions * static_cast<uint64_t>(bytes_per_transaction) * 8ull;
}
};

struct DramEnergy {
double activation_pj = 0.0;
double transfer_pj = 0.0;
double total_pj = 0.0;
};

DramEnergyCosts load_dram_energy_costs(const std::string& cost_table_path);

DramEnergy compute_dram_energy(const DramEnergyCosts& costs, const DramEnergyCounters& counters);

/** Scale to the largest unit that keeps the value >= 1, e.g. "1.131 mJ". */
std::string format_energy(double pj);
std::string format_power(double watts);
std::string format_time(double seconds);
6 changes: 6 additions & 0 deletions TOGSim/include/SimulationConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <string>
#include <yaml-cpp/yaml.h>

#include "EnergyModel.h"

enum class CoreType { WS_MESH, STONNE };

enum class DramType { SIMPLE, RAMULATOR2 };
Expand Down Expand Up @@ -61,6 +63,10 @@ struct SimulationConfig {
uint32_t icnt_latency;
uint32_t icnt_stats_print_period_cycles=0;

/* Energy config. Disabled unless the config sets energy_cost_table_path. */
bool energy_model_enabled = false;
DramEnergyCosts dram_energy_costs;

/* Sheduler config */
uint32_t num_partition=1;
std::string scheduler_type;
Expand Down
1 change: 1 addition & 0 deletions TOGSim/include/Simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Simulator {
int get_partition_id(int core_id) { return _config.partiton_map[core_id]; }
std::unique_ptr<Scheduler>& get_partition_scheduler(int core_id) { return _partition_scheduler.at(get_partition_id(core_id)); }
void print_core_stat();
void print_energy_stat();
void cycle();
const SimulationConfig& get_config() const { return _config; }
const YAML::Node& get_hardware_config_yaml() const { return _hardware_config_yaml; }
Expand Down
8 changes: 8 additions & 0 deletions TOGSim/src/Common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ SimulationConfig initialize_config(const YAML::Node& config,
if (config["icnt_injection_ports_per_core"])
parsed_config.icnt_injection_ports_per_core = config["icnt_injection_ports_per_core"].as<uint32_t>();

/* Energy config */
if (config["energy_cost_table_path"]) {
const std::string cost_table_rel = config["energy_cost_table_path"].as<std::string>();
parsed_config.dram_energy_costs =
load_dram_energy_costs(parsed_config.resolve_against_simulation_config(cost_table_rel));
parsed_config.energy_model_enabled = true;
}

if (config["scheduler"])
parsed_config.scheduler_type = config["scheduler"].as<std::string>();
if (config["num_partition"])
Expand Down
12 changes: 12 additions & 0 deletions TOGSim/src/Dram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,18 @@ void DramRamulator2::pop(uint32_t cid) {
m_to_crossbar_queue[cid].pop();
}

DramEnergyCounters DramRamulator2::get_energy_counters() {
DramEnergyCounters counters;
counters.available = true;
/* _req_size is the model's own get_tx_bytes(), so one served request is exactly one burst. */
counters.bytes_per_transaction = _req_size;
for (int ch = 0; ch < _n_ch; ch++) {
counters.row_activations += _mem[ch]->row_activations();
counters.transactions += _mem[ch]->total_reads() + _mem[ch]->total_writes();
}
return counters;
}

void DramRamulator2::print_stat() {
spdlog::info("=== DRAM statistics ===");
if (_n_ch == 0)
Expand Down
92 changes: 92 additions & 0 deletions TOGSim/src/EnergyModel.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "EnergyModel.h"

#include <spdlog/spdlog.h>
#include <yaml-cpp/yaml.h>

#include <array>
#include <cmath>
#include <stdexcept>

#include "fmt/core.h"

double DramEnergyCosts::transfer_pj_per_bit_total() const {
double total = 0.0;
for (const auto& [name, pj] : transfer_pj_per_bit)
total += pj;
return total;
}

std::string DramEnergyCosts::transfer_breakdown() const {
std::string out;
for (const auto& [name, pj] : transfer_pj_per_bit) {
if (!out.empty())
out += " + ";
out += fmt::format("{} {:.2f}", name, pj);
}
return out;
}

DramEnergyCosts load_dram_energy_costs(const std::string& cost_table_path) {
YAML::Node table;
try {
table = YAML::LoadFile(cost_table_path);
} catch (const std::exception& e) {
throw std::runtime_error(
fmt::format("[Config/Energy] Failed to load energy cost table \"{}\": {}", cost_table_path, e.what()));
}

DramEnergyCosts parsed;
parsed.path = cost_table_path;
parsed.name = table["name"] ? table["name"].as<std::string>() : "unnamed";

const YAML::Node dram = table["offchip_dram"];
if (!dram)
throw std::runtime_error(
fmt::format("[Config/Energy] Energy cost table \"{}\" has no offchip_dram section", cost_table_path));

if (!dram["row_activation_pj"])
throw std::runtime_error(
fmt::format("[Config/Energy] Energy cost table \"{}\": offchip_dram.row_activation_pj is required", cost_table_path));
parsed.row_activation_pj = dram["row_activation_pj"].as<double>();

const YAML::Node per_bit = dram["transfer_pj_per_bit"];
if (!per_bit || !per_bit.IsMap() || per_bit.size() == 0)
throw std::runtime_error(fmt::format(
"[Config/Energy] Energy cost table \"{}\": offchip_dram.transfer_pj_per_bit must be a non-empty map", cost_table_path));
for (const auto& term : per_bit)
parsed.transfer_pj_per_bit.emplace_back(term.first.as<std::string>(), term.second.as<double>());

spdlog::info("[Config/Energy] Loaded energy cost table \"{}\" from {}", parsed.name, cost_table_path);
return parsed;
}

DramEnergy compute_dram_energy(const DramEnergyCosts& costs, const DramEnergyCounters& counters) {
DramEnergy energy;
energy.activation_pj = static_cast<double>(counters.row_activations) * costs.row_activation_pj;
energy.transfer_pj = static_cast<double>(counters.transferred_bits()) * costs.transfer_pj_per_bit_total();
energy.total_pj = energy.activation_pj + energy.transfer_pj;
return energy;
}

namespace {
/** Pick the unit whose scale keeps `value / scale` in [1, 1000), or the smallest unit. */
std::string scale_units(double value, const std::vector<std::pair<double, const char*>>& units) {
for (const auto& [scale, suffix] : units) {
if (std::fabs(value) >= scale)
return fmt::format("{:.3f} {}", value / scale, suffix);
}
return fmt::format("{:.3f} {}", value / units.back().first, units.back().second);
}
} // namespace

std::string format_energy(double pj) {
return scale_units(pj, {{1e12, "J"}, {1e9, "mJ"}, {1e6, "uJ"}, {1e3, "nJ"}, {1.0, "pJ"}});
}

std::string format_power(double watts) {
return scale_units(watts, {{1.0, "W"}, {1e-3, "mW"}, {1e-6, "uW"}});
}

std::string format_time(double seconds) {
return scale_units(seconds, {{1.0, "s"}, {1e-3, "ms"}, {1e-6, "us"}, {1e-9, "ns"}});
}
40 changes: 40 additions & 0 deletions TOGSim/src/Simulator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,44 @@ void Simulator::print_core_stat()
_cores[core_id]->print_stats();
}
spdlog::info("Total execution cycles: {}", _core_cycles);
print_energy_stat();
}

/* Whole-run totals only; the periodic interval logs carry no energy. */
void Simulator::print_energy_stat() {
if (!_config.energy_model_enabled)
return;

const DramEnergyCosts& costs = _config.dram_energy_costs;
spdlog::info("=== Energy statistics ===");
spdlog::info("[Energy] Energy cost table \"{}\" loaded from \"{}\"", costs.name, costs.path);

const std::string scope =
_config.dram_channels > 0
? fmt::format("OffChip DRAM channels 0..{} combined", _config.dram_channels - 1)
: std::string("OffChip DRAM");

const DramEnergyCounters counters = _dram->get_energy_counters();
if (!counters.available) {
spdlog::info("[Energy] {} | not modeled, the configured dram_type tracks no row state", scope);
return;
}

const DramEnergy energy = compute_dram_energy(costs, counters);
const double seconds =
(_core_cycles == 0 || _config.core_freq_mhz == 0)
? 0.0
: static_cast<double>(_core_cycles) / (static_cast<double>(_config.core_freq_mhz) * 1e6);

if (seconds > 0.0) {
spdlog::info("[Energy] {} | {} avg power, {} over {} | {} activation, {} transfer", scope,
format_power(energy.total_pj * 1e-12 / seconds), format_energy(energy.total_pj),
format_time(seconds), format_energy(energy.activation_pj), format_energy(energy.transfer_pj));
} else {
spdlog::info("[Energy] {} | {} total | {} activation, {} transfer", scope, format_energy(energy.total_pj),
format_energy(energy.activation_pj), format_energy(energy.transfer_pj));
}
spdlog::info("[Energy] {} | {} activations x {:.2f} pJ | {} transactions x {} B x {:.2f} pJ/bit ({})", scope,
counters.row_activations, costs.row_activation_pj, counters.transactions,
counters.bytes_per_transaction, costs.transfer_pj_per_bit_total(), costs.transfer_breakdown());
}
15 changes: 15 additions & 0 deletions configs/energy_tables/hbm2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Off-chip DRAM energy constants. All values in pJ.
#
# Swap this file out (via the `energy_cost_table_path` key of the simulation
# config) to model a different memory technology.
name: HBM2

offchip_dram:
# Energy of one row activation, counted as a PRE+ACT command pair.
row_activation_pj: 909.0
# Per-bit terms, summed for every bit that crosses the DRAM interface.
# Kept separate so the report can show the breakdown.
transfer_pj_per_bit:
dram: 1.51
io: 1.17
phy: 0.80
2 changes: 2 additions & 0 deletions configs/systolic_ws_128x128_c1_simple_noc_tpuv3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dram_channels: 16
dram_stats_print_period_cycles: 10000
ramulator_config_path: ../configs/ramulator2_configs/HBM2_TPUv3.yaml

energy_cost_table_path: ../configs/energy_tables/hbm2.yml

icnt_type: simple
icnt_latency_cycles: 10
icnt_freq_mhz: 940
Expand Down
Loading