OpenFPGA/vpr7_x2p/vpr/SRC/power/PowerSpicedComponent.c

231 lines
6.0 KiB
C

/************************* INCLUDES *********************************/
#include <cstring>
#include <cfloat>
#include <limits>
#include <algorithm>
using namespace std;
#include <assert.h>
#include "util.h"
#include "PowerSpicedComponent.h"
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());
}
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() {
assert(entries.size() >= 2);
for (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];
assert(sorted);
for (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 NULL;
}
PowerSpicedComponent::PowerSpicedComponent(
float (*usage_fn)(int num_inputs, float transistor_size)) {
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;
}
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) {
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];
assert(sorted);
for (vector<PowerCallibInputs*>::iterator it = entries.begin() + 1;
it != entries.end(); it++) {
if ((*it)->num_inputs > num_inputs) {
if (lower) {
if (prev == entries[0])
return NULL;
else
return prev;
} else {
if (*it == entries[entries.size() - 1])
return NULL;
else
return *it;
}
}
prev = *it;
}
return NULL;
}
void PowerSpicedComponent::add_data_point(int num_inputs, float transistor_size,
float power) {
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;
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 */
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);
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;
}
if (inputs_upper) {
/* Interpolation of factor between sizes for upper # inputs */
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);
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;
}
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(void) {
sort(entries.begin(), entries.end(), sorter_PowerCallibInputs);
for (vector<PowerCallibInputs*>::iterator it = entries.begin();
it != entries.end(); it++) {
(*it)->sort_me();
}
sorted = true;
}
void PowerSpicedComponent::callibrate(void) {
sort_me();
for (vector<PowerCallibInputs*>::iterator it = entries.begin();
it != entries.end(); it++) {
(*it)->callibrate();
}
done_callibration = true;
}
bool PowerSpicedComponent::is_done_callibration(void) {
return done_callibration;
}