blob: 621fece123f17085c7c38346bdf285eec40e23f6 [file] [log] [blame]
/************************* INCLUDES *********************************/
#include <cstring>
#include <cfloat>
#include <limits>
#include <algorithm>
#include <string>
#include "vtr_assert.h"
#include "vpr_error.h"
#include "PowerSpicedComponent.h"
bool sorter_PowerCallibSize(PowerCallibSize* a, PowerCallibSize* b);
bool sorter_PowerCallibInputs(PowerCallibInputs* a, PowerCallibInputs* b);
PowerCallibInputs::PowerCallibInputs(PowerSpicedComponent* parent_,
float inputs)
: parent(parent_)
, num_inputs(inputs)
, sorted(false)
, done_callibration(false) {
/* Add min/max bounding entries */
add_size(0);
add_size(std::numeric_limits<float>::max());
}
PowerCallibInputs::~PowerCallibInputs() {
for (auto entry : entries) {
delete entry;
}
}
void PowerCallibInputs::add_size(float transistor_size, float power) {
PowerCallibSize* entry = new PowerCallibSize(transistor_size, power);
entries.push_back(entry);
sorted = false;
}
bool sorter_PowerCallibSize(PowerCallibSize* a, PowerCallibSize* b) {
return a->transistor_size < b->transistor_size;
}
void PowerCallibInputs::sort_me() {
sort(entries.begin(), entries.end(), sorter_PowerCallibSize);
sorted = true;
}
void PowerCallibInputs::callibrate() {
VTR_ASSERT(entries.size() >= 2);
for (std::vector<PowerCallibSize*>::iterator it = entries.begin() + 1;
it != entries.end() - 1; it++) {
float est_power = parent->component_usage(num_inputs,
(*it)->transistor_size);
(*it)->factor = (*it)->power / est_power;
}
/* Set min-value placeholder */
entries[0]->factor = entries[1]->factor;
/* Set max-value placeholder */
entries[entries.size() - 1]->factor = entries[entries.size() - 2]->factor;
done_callibration = true;
}
PowerCallibSize* PowerCallibInputs::get_entry_bound(bool lower,
float transistor_size) {
PowerCallibSize* prev = entries[0];
VTR_ASSERT(sorted);
for (std::vector<PowerCallibSize*>::iterator it = entries.begin() + 1;
it != entries.end(); it++) {
if ((*it)->transistor_size > transistor_size) {
if (lower)
return prev;
else
return *it;
}
prev = *it;
}
return nullptr;
}
PowerSpicedComponent::PowerSpicedComponent(std::string component_name,
float (*usage_fn)(int num_inputs, float transistor_size)) {
name = component_name;
component_usage = usage_fn;
/* Always pad with a high and low entry */
add_entry(0);
// add_entry(std::numeric_limits<int>::max());
add_entry(1000000000);
done_callibration = false;
sorted = true;
}
PowerSpicedComponent::~PowerSpicedComponent() {
for (auto entry : entries) {
delete entry;
}
}
PowerCallibInputs* PowerSpicedComponent::add_entry(int num_inputs) {
PowerCallibInputs* entry = new PowerCallibInputs(this, num_inputs);
entries.push_back(entry);
return entry;
}
PowerCallibInputs* PowerSpicedComponent::get_entry(int num_inputs) {
std::vector<PowerCallibInputs*>::iterator it;
for (it = entries.begin(); it != entries.end(); it++) {
if ((*it)->num_inputs == num_inputs) {
break;
}
}
if (it == entries.end()) {
return add_entry(num_inputs);
} else {
return *it;
}
}
PowerCallibInputs* PowerSpicedComponent::get_entry_bound(bool lower,
int num_inputs) {
PowerCallibInputs* prev = entries[0];
VTR_ASSERT(sorted);
for (std::vector<PowerCallibInputs*>::iterator it = entries.begin() + 1;
it != entries.end(); it++) {
if ((*it)->num_inputs > num_inputs) {
if (lower) {
if (prev == entries[0])
return nullptr;
else
return prev;
} else {
if (*it == entries[entries.size() - 1])
return nullptr;
else
return *it;
}
}
prev = *it;
}
return nullptr;
}
void PowerSpicedComponent::add_data_point(int num_inputs, float transistor_size, float power) {
VTR_ASSERT(!done_callibration);
PowerCallibInputs* inputs_entry = get_entry(num_inputs);
inputs_entry->add_size(transistor_size, power);
sorted = false;
}
float PowerSpicedComponent::scale_factor(int num_inputs,
float transistor_size) {
PowerCallibInputs* inputs_lower;
PowerCallibInputs* inputs_upper;
PowerCallibSize* size_lower;
PowerCallibSize* size_upper;
float factor_lower = 0.;
float factor_upper = 0.;
float factor;
float perc_upper;
VTR_ASSERT(done_callibration);
inputs_lower = get_entry_bound(true, num_inputs);
inputs_upper = get_entry_bound(false, num_inputs);
if (inputs_lower) {
/* Interpolation of factor between sizes for lower # inputs */
VTR_ASSERT(inputs_lower->done_callibration);
size_lower = inputs_lower->get_entry_bound(true, transistor_size);
size_upper = inputs_lower->get_entry_bound(false, transistor_size);
if (size_lower && size_upper) {
perc_upper = (transistor_size - size_lower->transistor_size)
/ (size_upper->transistor_size - size_lower->transistor_size);
factor_lower = perc_upper * size_upper->factor
+ (1 - perc_upper) * size_lower->factor;
} else {
VPR_FATAL_ERROR(VPR_ERROR_POWER, "Failed to interpolate transitor size");
}
}
if (inputs_upper) {
/* Interpolation of factor between sizes for upper # inputs */
VTR_ASSERT(inputs_upper->done_callibration);
size_lower = inputs_upper->get_entry_bound(true, transistor_size);
size_upper = inputs_upper->get_entry_bound(false, transistor_size);
if (size_lower && size_upper) {
perc_upper = (transistor_size - size_lower->transistor_size)
/ (size_upper->transistor_size - size_lower->transistor_size);
factor_upper = perc_upper * size_upper->factor
+ (1 - perc_upper) * size_lower->factor;
} else {
VPR_FATAL_ERROR(VPR_ERROR_POWER, "Failed to interpolate transitor size");
}
}
if (!inputs_lower) {
factor = factor_upper;
} else if (!inputs_upper) {
factor = factor_lower;
} else {
/* Interpolation of factor between inputs */
perc_upper = ((float)(num_inputs - inputs_lower->num_inputs))
/ ((float)(inputs_upper->num_inputs
- inputs_lower->num_inputs));
factor = perc_upper * factor_upper + (1 - perc_upper) * factor_lower;
}
return factor;
}
bool sorter_PowerCallibInputs(PowerCallibInputs* a, PowerCallibInputs* b) {
return a->num_inputs < b->num_inputs;
}
void PowerSpicedComponent::sort_me() {
sort(entries.begin(), entries.end(), sorter_PowerCallibInputs);
for (std::vector<PowerCallibInputs*>::iterator it = entries.begin();
it != entries.end(); it++) {
(*it)->sort_me();
}
sorted = true;
}
void PowerSpicedComponent::callibrate() {
sort_me();
for (std::vector<PowerCallibInputs*>::iterator it = entries.begin();
it != entries.end(); it++) {
(*it)->callibrate();
}
done_callibration = true;
}
bool PowerSpicedComponent::is_done_callibration() {
return done_callibration;
}
void PowerSpicedComponent::print(FILE* fp) {
fprintf(fp, "%s\n", name.c_str());
for (std::vector<PowerCallibInputs*>::iterator it = entries.begin() + 1;
it != entries.end() - 1; it++) {
fprintf(fp, "Num Inputs: %d\n", (*it)->num_inputs);
for (std::vector<PowerCallibSize*>::iterator it2 = (*it)->entries.begin()
+ 1;
it2 != (*it)->entries.end() - 1; it2++) {
fprintf(fp, " Transistor Size: %6f Factor: %3f\n",
(*it2)->transistor_size, (*it2)->factor);
}
}
}