/* * 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 #include #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) { 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; }