gem5/src/mem/ruby/network/orion/NetworkPower.cc

431 lines
14 KiB
C++
Raw Normal View History

/*
* Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* 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;
* neither the name of the copyright holders 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
* OWNER 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.
*/
#include <stdio.h>
#include <math.h>
#include "mem/ruby/network/orion/power_router_init.hh"
#include "mem/ruby/network/orion/power_array.hh"
#include "mem/ruby/network/orion/power_crossbar.hh"
#include "mem/ruby/network/orion/power_arbiter.hh"
#include "mem/ruby/network/orion/power_bus.hh"
#include "mem/ruby/network/orion/NetworkPower.hh"
#include "mem/ruby/network/garnet-fixed-pipeline/Router_d.hh"
#include "mem/ruby/network/garnet-fixed-pipeline/NetworkLink_d.hh"
#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh"
#include "mem/ruby/network/orion/SIM_port.hh"
#include "mem/ruby/network/orion/parm_technology.hh"
/* --------- Static energy calculation functions ------------ */
//Input buffer
double SIM_reg_stat_energy(power_array_info *info, power_array *arr, double n_read, double n_write)
{
double Eavg = 0, Eatomic, Estruct, Estatic;
/* decoder */
if (info->row_dec_model) {
//row decoder
Estruct = 0;
/* assume switch probability 0.5 for address bits */
//input
Eatomic = arr->row_dec.e_chg_addr * arr->row_dec.n_bits * SWITCHING_FACTOR * (n_read + n_write);
Estruct += Eatomic;
//output
Eatomic = arr->row_dec.e_chg_output * (n_read + n_write);
Estruct += Eatomic;
/* assume all 1st-level decoders change output */
//internal node
Eatomic = arr->row_dec.e_chg_l1 * arr->row_dec.n_in_2nd * (n_read + n_write);
Estruct += Eatomic;
Eavg += Estruct;
}
/* wordline */
Estruct = 0;
//read
Eatomic = arr->data_wordline.e_read * n_read;
Estruct += Eatomic;
//write
Eatomic = arr->data_wordline.e_write * n_write;
Estruct += Eatomic;
Eavg += Estruct;
/* bitlines */
Estruct = 0;
//read
if (arr->data_bitline.end == 2) {
Eatomic = arr->data_bitline.e_col_read * info->eff_data_cols * n_read;
}
else {
/* assume switch probability 0.5 for single-ended bitlines */
Eatomic = arr->data_bitline.e_col_read * info->eff_data_cols * SWITCHING_FACTOR * n_read;
}
Estruct += Eatomic;
//write
/* assume switch probability 0.5 for write bitlines */
Eatomic = arr->data_bitline.e_col_write * info->data_width * SWITCHING_FACTOR * n_write;
Estruct += Eatomic;
//precharge
Eatomic = arr->data_bitline_pre.e_charge * info->eff_data_cols * n_read;
Estruct += Eatomic;
Eavg += Estruct;
/* memory cells */
Estruct = 0;
/* assume switch probability 0.5 for memory cells */
Eatomic = arr->data_mem.e_switch * info->data_width * SWITCHING_FACTOR * n_write;
Estruct += Eatomic;
Eavg += Estruct;
/* sense amplifier */
if (info->data_end == 2) {
Estruct = 0;
Eatomic = arr->data_amp.e_access * info->eff_data_cols * n_read;
Estruct += Eatomic;
Eavg += Estruct;
}
/* output driver */
if (info->outdrv_model) {
Estruct = 0;
//enable
Eatomic = arr->outdrv.e_select * n_read;
Estruct += Eatomic;
//data
/* same switch probability as bitlines */
Eatomic = arr->outdrv.e_chg_data * arr->outdrv.item_width * SWITCHING_FACTOR * info->n_item * info->assoc * n_read;
Estruct += Eatomic;
//output 1
/* assume 1 and 0 are uniformly distributed */
if (arr->outdrv.e_out_1 >= arr->outdrv.e_out_0 ) {
Eatomic = arr->outdrv.e_out_1 * arr->outdrv.item_width * SWITCHING_FACTOR * n_read;
Estruct += Eatomic;
}
//output 0
if (arr->outdrv.e_out_1 < arr->outdrv.e_out_0) {
Eatomic = arr->outdrv.e_out_0 * arr->outdrv.item_width * SWITCHING_FACTOR * n_read;
Estruct += Eatomic;
}
Eavg += Estruct;
}
/* static power */
Estatic = arr->i_leakage * Vdd * Period * SCALE_S;
//static energy
Eavg += Estatic;
return Eavg;
}
//crossbar
double SIM_crossbar_stat_energy(power_crossbar *crsbar, double n_data)
{
2009-05-11 19:38:45 +02:00
double Eavg = 0, Eatomic;
if (n_data > crsbar->n_out) {
n_data = crsbar->n_out;
}
switch (crsbar->model) {
case MATRIX_CROSSBAR:
case CUT_THRU_CROSSBAR:
case MULTREE_CROSSBAR:
/* assume 0.5 data switch probability */
//input
Eatomic = crsbar->e_chg_in * crsbar->data_width * SWITCHING_FACTOR * n_data;
Eavg += Eatomic;
//output
Eatomic = crsbar->e_chg_out * crsbar->data_width * SWITCHING_FACTOR * n_data;
Eavg += Eatomic;
//control
Eatomic = crsbar->e_chg_ctr * n_data;
Eavg += Eatomic;
if (crsbar->model == MULTREE_CROSSBAR && crsbar->depth > 1) {
//internal node
Eatomic = crsbar->e_chg_int * crsbar->data_width * (crsbar->depth - 1) * SWITCHING_FACTOR * n_data;
Eavg += Eatomic;
}
break;
default: break;/* some error handler */
}
return Eavg;
}
//arbiter
/* stat over one cycle */
/* info is only used by queuing arbiter */
double SIM_arbiter_stat_energy(power_arbiter *arb, power_array_info *info, double n_req)
{
double Eavg = 0, Estruct, Eatomic;
double total_pri, n_chg_pri, n_grant;
/* energy cycle distribution */
if (n_req > arb->req_width) {
n_req = arb->req_width;
}
if (n_req >= 1) n_grant = 1;
else n_grant = 1.0 / ceil(1.0 / n_req);
switch (arb->model) {
case RR_ARBITER:
/* FIXME: we may overestimate request switch */
//request
Eatomic = arb->e_chg_req * n_req;
Eavg += Eatomic;
//grant
Eatomic = arb->e_chg_grant * n_grant;
Eavg += Eatomic;
/* assume carry signal propagates half length in average case */
/* carry does not propagate in maximum case, i.e. all carrys go down */
//carry
Eatomic = arb->e_chg_carry * arb->req_width * SWITCHING_FACTOR * n_grant;
Eavg += Eatomic;
//internal carry
Eatomic = arb->e_chg_carry_in * (arb->req_width * SWITCHING_FACTOR - 1) * n_grant;
Eavg += Eatomic;
/* priority registers */
Estruct = 0;
//priority
//switch
Eatomic = arb->pri_ff.e_switch * 2 * n_grant;
Estruct += Eatomic;
//keep 0
Eatomic = arb->pri_ff.e_keep_0 * (arb->req_width - 2 * n_grant);
Estruct += Eatomic;
//clock
Eatomic = arb->pri_ff.e_clock * arb->req_width;
Estruct += Eatomic;
Eavg += Estruct;
break;
case MATRIX_ARBITER:
total_pri = arb->req_width * (arb->req_width - 1) * 0.5;
/* assume switch probability 0.5 for priorities */
n_chg_pri = (arb->req_width - 1) * SWITCHING_FACTOR;
/* FIXME: we may overestimate request switch */
//request
Eatomic = arb->e_chg_req * n_req;
Eavg += Eatomic;
//grant
Eatomic = arb->e_chg_grant * n_grant;
Eavg += Eatomic;
/* priority registers */
Estruct = 0;
//priority
//switch
Eatomic = arb->pri_ff.e_switch * n_chg_pri * n_grant;
Estruct += Eatomic;
/* assume 1 and 0 are uniformly distributed */
//keep 0
if (arb->pri_ff.e_keep_0 >= arb->pri_ff.e_keep_1) {
Eatomic = arb->pri_ff.e_keep_0 * (total_pri - n_chg_pri * n_grant) * SWITCHING_FACTOR;
Estruct += Eatomic;
}
//keep 1
if (arb->pri_ff.e_keep_0 < arb->pri_ff.e_keep_1) {
Eatomic = arb->pri_ff.e_keep_1 * (total_pri - n_chg_pri * n_grant) * SWITCHING_FACTOR;
Estruct += Eatomic;
}
//clock
Eatomic = arb->pri_ff.e_clock * total_pri;
Estruct += Eatomic;
Eavg += Estruct;
/* based on above assumptions */
//internal node
/* p(n-1)/2 + (n-1)/2 */
Eatomic = arb->e_chg_mint * (n_req + 1) * (arb->req_width - 1) * 0.5;
Eavg += Eatomic;
break;
case QUEUE_ARBITER:
/* FIXME: what if n_req > 1? */
Eavg = SIM_reg_stat_energy(info, &arb->queue, n_req, n_grant);
break;
default: break;/* some error handler */
}
return Eavg;
}
double SIM_bus_stat_energy(power_bus *bus, double e_link)
{
double Ebus;
Ebus = bus->e_switch * e_link * SWITCHING_FACTOR * bus->bit_width;
return (Ebus);
}
double Router_d::calculate_offline_power(power_router *router, power_router_info *info)
{
double Eavg = 0;
double P_in_buf, P_xbar, P_vc_in_arb, P_vc_out_arb, P_sw_in_arb, P_sw_out_arb, P_leakage, P_total;
double E_in_buf, E_xbar, E_vc_in_arb, E_vc_out_arb, E_sw_in_arb, E_sw_out_arb, E_leakage;
double e_in_buf_read, e_in_buf_write, e_crossbar, e_vc_local_arb, e_vc_global_arb, e_sw_local_arb, e_sw_global_arb;
double sim_cycles;
sim_cycles = g_eventQueue_ptr->getTime() - m_network_ptr->getRubyStartTime();
calculate_performance_numbers();
//counts obtained from perf. simulator
e_in_buf_read = (double )(buf_read_count/sim_cycles);
e_in_buf_write = (double )(buf_write_count/sim_cycles);
e_crossbar = (double )(crossbar_count/sim_cycles);
e_vc_local_arb = (double)(vc_local_arbit_count/sim_cycles);
e_vc_global_arb = (double)(vc_global_arbit_count/sim_cycles);
e_sw_local_arb = (double )(sw_local_arbit_count/sim_cycles);
e_sw_global_arb = (double )(sw_global_arbit_count/sim_cycles);
// e_link = (double )(link_traversal_count/sim_cycles);
/* input buffers */
if (info->in_buf)
E_in_buf = SIM_reg_stat_energy(&info->in_buf_info, &router->in_buf, e_in_buf_read, e_in_buf_write);
P_in_buf = E_in_buf * PARM_Freq;
Eavg += E_in_buf;
/* main crossbar */
if (info->crossbar_model)
E_xbar= SIM_crossbar_stat_energy(&router->crossbar, e_crossbar);
P_xbar = E_xbar * PARM_Freq;
Eavg += E_xbar;
/* vc input (local) arbiter */
if (info->vc_in_arb_model)
E_vc_in_arb = SIM_arbiter_stat_energy(&router->vc_in_arb, &info->vc_in_arb_queue_info, e_sw_local_arb);
P_vc_in_arb = E_vc_in_arb * PARM_Freq;
Eavg += E_vc_in_arb;
/* vc output (global) arbiter */
if (info->vc_out_arb_model)
E_vc_out_arb = SIM_arbiter_stat_energy(&router->vc_out_arb, &info->vc_out_arb_queue_info, e_sw_global_arb);
P_vc_out_arb = E_vc_out_arb * PARM_Freq;
Eavg += E_vc_out_arb;
/* sw input (local) arbiter */
if (info->sw_in_arb_model)
E_sw_in_arb = SIM_arbiter_stat_energy(&router->sw_in_arb, &info->sw_in_arb_queue_info, e_sw_local_arb);
P_sw_in_arb = E_sw_in_arb * PARM_Freq;
Eavg += E_sw_in_arb;
/* sw output (global) arbiter */
if (info->sw_out_arb_model)
E_sw_out_arb = SIM_arbiter_stat_energy(&router->sw_out_arb, &info->sw_out_arb_queue_info, e_sw_global_arb);
P_sw_out_arb = E_sw_out_arb * PARM_Freq;
Eavg += E_sw_out_arb;
/* static power */
E_leakage = router->i_leakage * Vdd * Period * SCALE_S;
P_leakage = E_leakage * PARM_Freq;
Eavg += E_leakage;
P_total = Eavg * PARM_Freq;
return Eavg;
}
double NetworkLink_d::calculate_offline_power(power_bus* bus)
{
double sim_cycles = (double) (g_eventQueue_ptr->getTime() - m_net_ptr->getRubyStartTime());
double e_link = (double) (m_link_utilized)/ sim_cycles;
double E_link = SIM_bus_stat_energy(bus, e_link);
double P_link = E_link * PARM_Freq;
return P_link;
}
double NetworkLink_d::calculate_power()
{
power_bus bus;
power_bus_init(&bus, GENERIC_BUS, IDENT_ENC, PARM_flit_width, 0, 1, 1, PARM_link_length, 0);
double total_power = calculate_offline_power(&bus);
return total_power;
}
void Router_d::power_router_initialize(power_router *router, power_router_info *info)
{
info->n_in = m_input_unit.size();
info->n_out = m_output_unit.size();
info->flit_width = PARM_flit_width;
info->n_v_channel = m_num_vcs;
info->n_v_class = m_virtual_networks;
}
double Router_d::calculate_power()
{
power_router router;
power_router_info router_info;
double total_energy, total_power;
power_router_initialize(&router, &router_info);
power_router_init(&router, &router_info);
total_energy = calculate_offline_power(&router, &router_info);
total_power = total_energy * PARM_Freq;
return total_power;
}