Skip to content
Snippets Groups Projects
Commit d6aeced4 authored by Forget Julien's avatar Forget Julien
Browse files

Fixing merge conflicts

parents b13fcf40 188850c5
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,8 @@
**/*.o
**/*.so
**/dumpcft
**/libpwcet-runtime.a
**/*.a
**/_build
**/swymplify
**/*.out
libpwcet/test
This diff is collapsed.
CXXFLAGS=`otawa-config otawa/display --cflags`
CXXFLAGS+=-g
CXXFLAGS=`otawa-config otawa/etime otawa/display --cflags`
CXXFLAGS+=-g -Ofast -march=native
LDFLAGS=-g
LDLIBS=`otawa-config otawa/display --libs`
LDLIBS2=`otawa-config otawa/display otawa/cftree --libs`
CFLAGS=-O0 -g -Wall -W -fsanitize=address
LDLIBS=`otawa-config otawa/etime otawa/display --libs`
LDLIBS2=`otawa-config otawa/icat3 otawa/etime otawa/display otawa/cftree --libs`
CFLAGS=-Ofast -march=native -g -Wall -W -fsanitize=address
CXXFLAGS += -std=c++11 -O0 -g -Wall
CXXFLAGS += -std=c++11 -g -Wall
all: dumpcft pwcet/lib/libpwcet-runtime.a
default: dumpcft pwcet/lib/libpwcet-runtime.a
all: clean uninstall dumpcft pwcet/lib/libpwcet-runtime.a
dumpcft: dumpcft.o $(HOME)/.otawa/proc/otawa/cftree.so
$(CXX) $(LDFLAGS) -o dumpcft dumpcft.o $(LDLIBS2)
......@@ -32,4 +33,8 @@ $(HOME)/.otawa/proc/otawa/cftree.so: cftree.so
install: pwcet/lib/libpwcet-runtime.a dumpcft $(HOME)/.otawa/proc/otawa/cftree.so
uninstall:
rm -f $(HOME)/.otawa/proc/otawa/cftree.eld
rm -f $(HOME)/.otawa/proc/otawa/cftree.so
.PHONY: all test clean graph install
......@@ -95,11 +95,24 @@ void compute_node(evalctx_t * ctx, formula_t * f)
printf("compute_node: processing CONST node\n");
#endif
break;
case KIND_BOOLMULT:
#ifdef DEBUG
printf("compute_node: processing BOOLMULT node\n");
#endif
awcet_boolmult(ctx, f, &f->aw);
break;
case KIND_PARAM_LOOP:
#ifdef DEBUG
printf("compute_node: processing PARAM_LOOP node\n");
#endif
compute_node(ctx, &f->children[0]);
awcet_paramloop(ctx, &f->children->aw, f);
break;
//#ifdef DEBUG
default:
printf("compute_node: unknown node type %d\n", f->kind);
abort();
#endif
exit(1);;
//#endif
}
#ifdef DEBUG
printf("compute_node: loop=%d, eta[]={", f->aw.loop_id);
......@@ -246,6 +259,55 @@ void awcet_loop(evalctx_t * ctx, awcet_t * source, formula_t * dest)
}
}
void awcet_paramloop(evalctx_t * ctx, awcet_t * source, formula_t * dest)
{
int i, j;
int bound = compute_loop_bound(ctx, dest->condition);
long long loop_wcet = 0;
#ifdef DEBUG
printf("Computed loop bound: %d\n", bound);
#endif
// same as a regular loop
if (bound == 0) {
dest->aw.loop_id = LOOP_TOP;
dest->aw.eta_count = 0;
dest->aw.eta = NULL;
dest->aw.others = 0;
return;
}
if (source->loop_id == dest->opdata.loop_id) {
for (i = 0; (i < bound) && (i < source->eta_count); i++)
loop_wcet += source->eta[i];
if (i < bound)
loop_wcet += (bound - i) * source->others;
dest->aw.others = loop_wcet;
dest->aw.eta_count = 0;
dest->aw.loop_id = LOOP_TOP;
} else {
dest->aw.loop_id = source->loop_id;
dest->aw.eta_count = source->eta_count / bound;
dest->aw.others = source->others * bound;
if (source->eta_count % bound)
dest->aw.eta_count++;
// should correct problem crash when eta_count > 0
dest->aw.eta = (long long int*) malloc(dest->aw.eta_count * sizeof(long long));
for (i = 0; i < dest->aw.eta_count; i++) {
loop_wcet = 0;
for (j = 0; j < bound; j++) {
if ((j + i * bound) < source->eta_count) {
loop_wcet += source->eta[j + i * bound];
} else
loop_wcet += source->others;
}
dest->aw.eta[i] = loop_wcet;
}
}
}
void awcet_intmult(evalctx_t * ctx, awcet_t * source, formula_t * dest)
{
int i;
......@@ -256,6 +318,104 @@ void awcet_intmult(evalctx_t * ctx, awcet_t * source, formula_t * dest)
dest->aw.others = source->others * dest->opdata.coef;
}
/**
* Check the condition to execute the tree
* @param cdt the condition list
* @param condition_size the number of conditions to check
*/
int check_condition(evalctx_t* ctx, condition_t* cdts, int condition_size){
for(int i = 0; i < condition_size; i++){
condition_t* cdt = cdts+i;
const int left = cdt->int_value;
int right = 0;
const int terms_size = cdt->terms_number;
term_t* terms = cdt->terms;
for(int j = 0; j < terms_size; j++){
term_t* term = terms+j;
int value = term->value;
int coef = term->coef;
// if parameter we get the parameter value
if(term->kind == BOOL_PARAM){
value = ctx->bparam_valuation(term->value);
}
right += coef*value;
}
// compare right and left values
switch(cdt->kind){
case BOOL_LEQ:
#ifdef DEBUG
printf("Checking that %d <= %d\n", left, right);
#endif
if(!(left <= right))
return 0;
break;
case BOOL_EQ:
#ifdef DEBUG
printf("Checking that %d == %d\n", left, right);
#endif
if(!(left == right))
return 0;
break;
default:
printf("Error, unrecognized bool condition type: %d", cdt->kind);
exit(1);
}
}
// all conditionals are checked as true
return 1;
}
int compute_loop_bound(evalctx_t* ctx, condition_t* cdt){
// Should only be called in the case of a parametric loop bound
if(cdt->kind != BOOL_BOUND){
printf("Error, compute_loop_bound called without BOOL_BOUND kind");
exit(1);
}
// compute the bound
int bound = 0;
for(int i=0;i<cdt->terms_number;i++){
term_t* term = cdt->terms + i;
int value = term->value;
int coef = term->coef;
if(term->kind == BOOL_PARAM)
value = ctx->bparam_valuation(value);
bound += coef * value;
}
bound = bound < 0 ? 0 : bound; // a loop bound cannot be < 0, but the evaluation of the expression can
return bound;
}
void awcet_boolmult(evalctx_t* ctx, formula_t* source, awcet_t* dest){
// source = boolmult formula
// dest = WCET
// processing condition, [0] always represent the condition and [1] the WCET formula
if(source->children[0].kind != BOOL_CONDITIONS){
printf("Error : Boolmult first child not a boolean condition but of type: %d", source->children[0].kind);
exit(1);
}
condition_t* cdts = source->children[0].condition;
int condition_size = source->children[0].opdata.children_count;
int result = check_condition(ctx, cdts, condition_size);
// if condition is true then WCET of formula
if(result == 1){
formula_t fchild = source->children[1];
compute_node(ctx, &fchild);
// copy child formula WCET
dest->eta_count = fchild.aw.eta_count;
dest->eta = fchild.aw.eta;
dest->others = fchild.aw.others;
dest->loop_id = fchild.aw.loop_id;
}
// else theta
else{
// bot WCET == {0}
dest->eta_count = 0;
dest->eta = NULL;
dest->others = 0;
dest->loop_id = LOOP_TOP;
}
}
void awcet_ann(evalctx_t * ctx, awcet_t * source, formula_t * dest)
{
int i;
......@@ -317,11 +477,12 @@ int awcet_is_equal(awcet_t * s1, awcet_t * s2)
}
long long evaluate(formula_t *f, loopinfo_t *li, param_valuation_t pv, void *data)
long long evaluate(formula_t *f, loopinfo_t *li, param_valuation_t pv, bparam_valuation_t bpv, void *data)
{
evalctx_t ctx;
ctx.li = li;
ctx.param_valuation = pv;
ctx.bparam_valuation = bpv;
ctx.pv_data = data;
compute_node(&ctx, f);
if (f->aw.eta_count == 0) {
......@@ -368,6 +529,8 @@ void compute_eta_count(formula_t *f) {
break;
case KIND_CONST:
break;
default:
printf("error : unrecognized formula kind (compute_eta_count) : %d\n", f->kind);
}
}
......@@ -414,12 +577,18 @@ void writePWF(formula_t *f, FILE *out, long long *bounds) {
if (bound < 0) {
fprintf(stderr, "warning: loop %d is unbounded\n", f->opdata.loop_id);
}
if(strcmp(f->bool_expr, "-1") != 0){ // parametric loop
fprintf(out, ", (__top;{0}), l:%d)^(%s)", f->opdata.loop_id, f->bool_expr);
}
else { // non parametric
if (f->param_id) {
fprintf(out, ", (__top;{0}), l:%d)^p:%d", f->opdata.loop_id, f->param_id);
} else {
fprintf(out, ", (__top;{0}), l:%d)^%lld", f->opdata.loop_id, bound);
}
}
}
break;
case KIND_ANN:
......@@ -427,6 +596,19 @@ void writePWF(formula_t *f, FILE *out, long long *bounds) {
writePWF(f->children, out, bounds);
fprintf(out, "|(l:%d,%d))", f->opdata.ann.loop_id, f->opdata.ann.count);
break;
case KIND_BOOLMULT:
fprintf(out, "(");
writePWF(f->children, out, bounds);
fprintf(out, " * ");
writePWF(f->children+1, out, bounds);
fprintf(out, ")");
break;
case KIND_STR:
fprintf(out, "(%s)",f->bool_expr);
break;
default:
printf("error : unrecognized formula kind (writePWF) : %d\n", f->kind);
}
}
......
......@@ -10,6 +10,7 @@ WSymb: Symbolic Worst-Case Execution Time (WCET) computation.
* Clement Ballabriga <Clement.Ballabriga@nospamuniv-lille.fr>
* Julien Forget <Julien.Forget@nospamuniv-lille.fr>
* Celestine Sauvage <celestine.sauvage@nospamgmail.com>
* Sandro Grebant <sandro.grebant@nospamuniv-lille.fr>
License: GPL 2.1 or higher.
......
[elm-plugin]
name = cftree
author = Celestine SAUVAGE <Celestive.Sauvage.etu@univ-lille.fr>
author = Sandro Grebant <sandro.grebant@univ-lille.fr>
description = Control Flow Tree extractor
Clement Ballabriga <Clement.Ballabriga@univ-lille.fr>
Sandro Grebant <sandro.grebant@univ-lille.fr>
\ No newline at end of file
#!/usr/bin/env python3
LOOP_TOP = -1 #whole program
_id = -1
def new_id():
global _id
_id = _id + 1
return _id
indent_size = 4
indent = " " * indent_size
statements = ""
params = set()
vars = set()
def var(s):
global vars
global declarations
if s not in vars:
vars.add(s)
declarations = declarations + indent + "int " + s + ";\n"
return s
def param(p):
global params
if p not in params:
params.add(p)
return p
declarations = ""
def code(s):
global statements
statements = statements + indent + s + "\n"
class Expression(object):
def __init__(self):
raise NotImplementedError("Is abstract class")
class Seq(Expression):
def __init__(self, children):
self.children = children
def generate(self):
my_id = new_id()
children_results = [c.generate() for c in self.children]
eta_count = max([len(cr[1]) for cr in children_results])
eta_vars = []
loop_id_var = var("seq_" + str(my_id) + "_loop_id")
my_loop_id = max([cr[0] for cr in children_results]) #assume loop id are in topological order
code(loop_id_var + " = " + str(my_loop_id) + ";")
for i in range(eta_count):
eta_vars.append(var("seq_" + str(my_id) + "_eta_" + str(i)))
eta_vars_code = [ev + " = 0" for ev in eta_vars]
for cr in children_results:
(child_loop_id, child_vars ) = cr
for cv in range(eta_count):
if cv < len(child_vars):
eta_vars_code[cv] += " + " + child_vars[cv]
else:
eta_vars_code[cv] += " + " + child_vars[-1]
for evc in eta_vars_code:
code(evc + ";")
return (my_loop_id, eta_vars)
class Alt(Expression):
def __init__(self, left, right):
self.left = left
self.right = right
def __init__(self, children):
if len(children) == 1:
self.left = children[0]
self.right = Constant(LOOP_TOP, [0])
return
middle = len(children)//2
left = children[0:middle]
right = children[middle:]
if len(left) == 1:
self.left = left[0]
else:
self.left = Alt(left)
if len(right) == 1:
self.right = right[0]
else:
self.right = Alt(right)
def helper(self, result_vars, big_vars, small_vars, last_expr=None, indent=0):
if small_vars > big_vars:
(small_vars, big_vars) = (big_vars, small_vars)
if len(small_vars) == 0:
for i in range(len(result_vars)):
bi = i
if bi >= len(big_vars):
bi = len(big_vars) - 1
if last_expr:
code(indent*" " + result_vars[i] + " = " + last_expr + ";")
else:
code(indent*" " + result_vars[i] + " = " + big_vars[bi] + ";")
return
code(indent*" " + "if (" + big_vars[0] + " > " + small_vars[0] + ") {")
code((indent + indent_size)*" " + result_vars[0] + " = " + big_vars[0] + ";")
self.helper(result_vars[1:], big_vars[1:], small_vars, big_vars[0], indent + indent_size)
code(indent*" " + "} else {")
code((indent + indent_size) *" " + result_vars[0] + " = " + small_vars[0] + ";")
self.helper(result_vars[1:], big_vars, small_vars[1:], small_vars[0], indent + indent_size)
code(indent*" " + "}")
def generate(self):
my_id = new_id()
(left_loop_id, left_vars) = self.left.generate()
(right_loop_id, right_vars) = self.right.generate()
result_vars = []
for i in range(len(left_vars) + len(right_vars) - 1):
result_vars.append(var("alt_" + str(my_id) + "_eta_" + str(i)))
self.helper(result_vars, left_vars, right_vars)
return (max(left_loop_id, right_loop_id), result_vars)
class Loop(Expression):
def __init__(self, body, loop_id, bound):
self.body = body
self.loop_id = loop_id
self.bound = bound
def generate(self):
my_id = self.loop_id
(body_loop_id, body_vars) = self.body.generate()
if isinstance(self.bound, ParamBound):
bound_var = var("loop_" + str(my_id) + "_bound")
code(bound_var + " = " + self.bound.param_bound + ";")
else:
bound_var = var("loop_" + str(my_id) + "_bound")
code(bound_var + " = " + str(self.bound.bound_value) + ";")
if body_loop_id == self.loop_id:
result_var = var("loop_" + str(my_id) + "_eta_0")
for i in range(len(body_vars)):
if i == 0:
code("if (" + str(bound_var) + " == " + str(i) + ") " + result_var + " = 0;")
elif i < len(body_vars) - 1:
code("if (" + str(bound_var) + " == " + str(i) + ") " + result_var + " = (" + " + ".join(body_vars[0:i]) + ");")
else:
code("if (" + str(bound_var) + " >= " + str(i) + ") " + result_var + " = (" + " + ".join(body_vars[0:-1]) + ") + " + body_vars[-1] + "*(" + bound_var + " - " + str(i) + ");")
return (LOOP_TOP, [result_var])
else:
result_vars = []
for i in range(len(body_vars)):
result_vars.append(var("loop_" + str(my_id) + "_eta_" + str(i)))
for i in range(len(body_vars) + 1):
paquets = ""
j = 0
if i == 0:
while j < len(body_vars):
paquets += result_vars[j] + " = 0; "
j += 1
else:
k = 0
if i == len(body_vars):
bound_expr = bound_var
else:
bound_expr = str(i)
while j < len(body_vars):
paquets += result_vars[k] + " = "
paquets += " + ".join(body_vars[j: j + i])
if (j + i) > len(body_vars):
paquets += " + " + body_vars[-1] + "*" + str((j + i) - len(body_vars))
if i == len(body_vars):
paquets += " + (" + bound_expr + " - " + str(i) + ")*" + body_vars[-1]
paquets += "; "
j = j + i
k = k + 1
while k < len(body_vars):
paquets += result_vars[k] + " = " + body_vars[-1] + "*" + bound_expr + "; "
k = k + 1
if i == len(body_vars):
cond = ">="
else:
cond = "=="
code("if (" + str(bound_var) + " " + cond + " " + str(i) + ") { " + paquets + "}")
return (body_loop_id, result_vars)
class Constant(Expression):
def __init__(self, loop_id, eta):
self.eta = eta
self.loop_id = loop_id
def generate(self):
my_id = new_id()
code(var("cst_" + str(my_id) + "_loop_id") + " = " + str(self.loop_id) + ";")
for i in range(len(self.eta)):
code(var("cst_" + str(my_id) + "_eta_" + str(i)) + " = " + str(self.eta[i]) + ";")
return (self.loop_id, ["cst_" + str(my_id) + "_eta_" + str(i) for i in range(len(self.eta))])
class Conditional(Expression):
def __init__(self, test, tree):
self.test = test
self.tree = tree
def generate(self):
my_id = new_id()
result = self.tree.generate()
# compute the params
for i in range(4):
param_str = "param_" + str(i)
if param_str in self.test:
param(param_str)
# compute the result
loop_id = result[0]
eta = result[1]
eta_count = len(eta)
for i in range(eta_count):
code(eta[i] + " = (" + self.test + ") ? " + eta[i] + " : 0;")
return (loop_id, eta)
class Bound(object):
def __init__(self):
raise NotImplementedError("Is abstract class")
class ParamBound(Bound):
def __init__(self, param_bound):
# compute the params
for i in range(4):
param_str = "param_" + str(i)
if param_str in param_bound:
param(param_str)
self.param_bound = param_bound
class ConstantBound(Bound):
def __init__(self, bound_value):
self.bound_value = bound_value
def generate(formula):
(loop_id, eta_vars) = formula.generate()
code("return " + eta_vars[0] + ";")
# Documentation print
print("/*")
print(" * WCET evaluation function")
for p in sorted(list(params)):
pnum = int(p.replace("param_",""))+1
print(" * @param " + p + " ", pnum, "th procedure argument")
print(" * @return The WCET of the procedure depending on its arguments")
print(" */")
# End of documentation
print("int eval(", end="")
first = True
for p in sorted(list(params)):
if not first:
print(", ", end="")
print("int " + p, end="")
first = False
print(") {\n" + declarations + "\n" + statements + "}\n")
#audiobeam_find_max_in_arr = Alt([Constant(0, [1331, 1321, 500, 40, 30, 10]), Loop(Constant(2, [325, 265, 100, 50, 20]), 0, ParamBound(1))])
#audiobeam_find_max_in_arr = Seq([Constant(0, [1331, 1321]), Loop(Constant(2, [325, 265]), 2, ConstantBound(2))])
#generate(audiobeam_find_max_in_arr)
#toto = Loop(Seq([Constant(0, [20, 10]), Constant(0, [100])]), 0, ParamBound(1))
#generate(toto)
#include <stdio.h>
#include <time.h>
extern int eval(int param);
#define NANO 1000000000
#define ITERATIONS 50000000
int main(int argc, char *argv) {
/* Volatile to force evaluation each loop iteration */
volatile int paramval = 0;
volatile int result = 0;
struct timespec ts1, ts2;
while (scanf("%d", &paramval) == 1) {
volatile int result = 0;
clock_gettime(CLOCK_REALTIME, &ts1);
for (int i = 0; i < ITERATIONS; i++) {
result = eval(paramval);
}
clock_gettime(CLOCK_REALTIME, &ts2);
long long nsec = ts2.tv_nsec;
nsec -= ts1.tv_nsec;
if (ts2.tv_sec > ts1.tv_sec)
nsec += (ts2.tv_sec - ts1.tv_sec)*NANO;
printf("Param=%d WCET=%d, time=%llu nsec for %u iters (%llu nsec/iter)\n", paramval, result, nsec, ITERATIONS, nsec/ITERATIONS);
}
}
......@@ -37,12 +37,17 @@
#include <otawa/flowfact/features.h>
#include "include/CFTree.h"
#include <otawa/hard/features.h>
#include <otawa/hard/CacheConfiguration.h>
#include <otawa/cache/cat2/features.h>
#include <otawa/etime/features.h>
#include <otawa/hard/Processor.h>
using namespace otawa; //comme import
using namespace otawa::cftree;
#define CONDITIONS_FILE "constraints.csv"
#define LOOP_BOUNDS_FILE "loop_bounds.csv"
void fix_virtualized_loopinfo(CFG *entryCFG, Block *loop = nullptr) {
for (CFG::BlockIter iter(entryCFG->blocks()); iter(); iter++) {
......@@ -73,6 +78,7 @@ struct param_func *read_pfl(char *binary) {
strncpy(filename, binary, sizeof(filename) - 4);
filename[sizeof(filename) - 5] = 0;
strcat(filename, ".pfl");
cout << "pfl file = " << filename << endl;
FILE *f = fopen(filename, "r");
if (f != nullptr) {
printf("Found PFL file, reading it\n");
......@@ -94,11 +100,50 @@ struct param_func *read_pfl(char *binary) {
res[i].funcname = nullptr;
printf("End of PFL file processing\n");
fclose(f);
PFL = res;
return res;
} else return NULL;
}
void strreplace(char *string, const char *find, const char *replaceWith){
if(strstr(string, replaceWith) != NULL){
char *temporaryString = (char*) malloc(strlen(strstr(string, find) + strlen(find)) + 1);
strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part
*strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial string
strcat(string, replaceWith); //Concat the first part of the string with the part to replace with
strcat(string, temporaryString); //Concat the first part of the string with the part after the replaced part
free(temporaryString); //Free the memory to avoid memory leaks
}
}
// =================================================
// Manage the timing measurements
// =================================================
enum { NS_PER_SECOND = 1000000000 };
void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td)
{
td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
td->tv_sec = t2.tv_sec - t1.tv_sec;
if (td->tv_sec > 0 && td->tv_nsec < 0)
{
td->tv_nsec += NS_PER_SECOND;
td->tv_sec--;
}
else if (td->tv_sec < 0 && td->tv_nsec > 0)
{
td->tv_nsec -= NS_PER_SECOND;
td->tv_sec++;
}
}
int main(int argc, char **argv) {
// start measurements
struct timespec start, finish, delta;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
try{
if ((argc < 3) || (argc > 4)) {
fprintf(stderr, "usage: %s <ARM binary> <formula file> [<entry fct (by default main)>]\n", argv[0]);
exit(1);
......@@ -110,17 +155,81 @@ int main(int argc, char **argv) {
Manager manager;
NO_SYSTEM(conf) = true;
TASK_ENTRY(conf) = "main";
VERBOSE(conf) = false;
//TASK_ENTRY(conf) = "main";
TASK_ENTRY(conf) = (argc >= 4) ? argv[3] : "main";
// add the processor model
#ifdef PIPELINE
char proc[4096];
strcpy(proc, argv[0]);
strcat(proc, "/hw/processor.xml");
strreplace(proc, "dumpcft", "");
PROCESSOR_PATH(conf) = proc; // relative path to the processor file
//PROCESSOR(conf) = hard::Processor::load(proc);
#endif
#ifdef ICACHE
// add a default cache (will not be used into the app, but the plugin needs it in order to manage LBlocks, or a required features will make the program crash)
char result[4096];
strcpy(result, argv[0]);
strcat(result, "/hw/cache.xml");
strreplace(result, "dumpcft", "");
CACHE_CONFIG_PATH(conf) = result; // relative path to the cache file
#endif
//VERBOSE(conf) = true;
ws = manager.load(argv[1], conf);
ws->require(otawa::VIRTUALIZED_CFG_FEATURE, conf);
const CFGCollection *coll = INVOLVED_CFGS(ws);
// set the entry of the task
CFG *entry = nullptr;
const char *entryname = (argc >= 4) ? argv[3] : "main";
elm::String entryname_s(entryname);
for (CFGCollection::Iter iter(*coll); iter(); iter ++) {
if (entryname_s == (*iter)->name()) {
entry = (*iter);
break;
}
}
if (entry == nullptr) {
cerr << "entry point " << entryname_s << " not found" << endl;
exit(1);
}
// push conditions on the CFG to make it easier to know if we generate ALT or CONDITIONAL_ALT
ConditionParser parser;
std::map<otawa::address_t, std::vector<std::map<bool, otawa::cftree::BranchCondition *> *> *> conditionsMap = parser.readFromFile(CONDITIONS_FILE);
// adon to support loop headers
LoopBoundParser lbp;
std::map<int,LoopBound> lbs = lbp.readFromFile(LOOP_BOUNDS_FILE);
// needed before running CFT
ws->require(LOOP_HEADERS_FEATURE, conf);
parser.pushConditionsOnCFGs(entry, &conditionsMap, &lbs);
#ifdef ICACHE
ws->require(COLLECTED_LBLOCKS_FEATURE, conf); // cache implement : retrieve L-Blocks
ws->require(ICACHE_CATEGORY2_FEATURE, conf); // cache implement : retrieve Block cache type
ws->require(ICACHE_CONSTRAINT2_FEATURE, conf); // cache implement : retrieve miss penalty
#endif
ws->require(DynFeature("otawa::cftree::EXTRACTED_CFT_FEATURE"), conf);
const CFGCollection *coll = INVOLVED_CFGS(ws);
#ifdef ICACHE
// set the penalty of the cache
int icacheMissPenalty = hard::CACHE_CONFIGURATION_FEATURE.get(ws)->instCache()->missPenalty();
// DISPLAY CACHE INFOS
// cout << endl << "CACHE INFORMATIONS:" << endl;
// cout << "\tSize: " << hard::CACHE_CONFIGURATION_FEATURE.get(ws)->instCache()->cacheSize() << endl;
// cout << "\tWays: " << hard::CACHE_CONFIGURATION_FEATURE.get(ws)->instCache()->wayCount() << endl << endl;
//cout << "Miss penalty of the current cache : " << icacheMissPenalty << endl;
BasicCacheBlock::setPenalty(icacheMissPenalty);
#endif
StringBuffer buf;
buf << argv[1] << "-decomp.c";
elm::io::OutFileStream s(buf.toString());
......@@ -139,29 +248,36 @@ int main(int argc, char **argv) {
}
// produce awcet
CFG *entry = nullptr;
const char *entryname = (argc >= 4) ? argv[3] : "main";
elm::String entryname_s(entryname);
for (CFGCollection::Iter iter(*coll); iter(); iter ++) {
if (entryname_s == (*iter)->name()) {
entry = (*iter);
break;
}
}
if (entry == nullptr) {
cerr << "entry point " << entryname_s << " not found" << endl;
exit(1);
}
/* cout << "Computing WCET using IPET..." << endl; */
ws->require(ipet::WCET_FEATURE, conf);
/* cout << "WCET value using IPET: " << ipet::WCET(ws) << endl; */
#ifdef PIPELINE
etime::RECORD_TIME(conf) = true;
ws->require(etime::EDGE_TIME_FEATURE, conf);
#endif
// This requires to solve ILP, and thus it is not optimal, that's why we use another require
//ws->require(ipet::WCET_FEATURE, conf);
//cout << "WCET value using IPET: " << ipet::WCET(ws) << endl;
// Instead of WCET feature, we use:
// LOOP_HEADERS_FEATURE so as to get the LOOP_HEADER boolean value
// FLOW_FACTS_FEATURE in order to get the loop bounds
// BB_TIME_FEATURE to get the WCET of basic blocks
ws->require(ipet::FLOW_FACTS_FEATURE, conf);
ws->require(ipet::BB_TIME_FEATURE, conf);
/* cout << "Exporting to AWCET..."; */
formula_t f;
memset(&f, 0, sizeof(f));
/* infeasible paths implement */
CFTREE(entry)->exportToAWCET(&f, pfl);
/* cout << "done." << endl; */
#ifdef IP
if(allConstraints.size() > 0){
cout << "Some constraints could not be attached to a node: " ;
printPseudoPaths(allConstraints);
throw InvalidConstraintException("Error : could not attach all constraints to tree nodes");
}
#endif
int max_loop_id = 0;
fix_virtualized_loopinfo(entry);
......@@ -213,4 +329,18 @@ int main(int argc, char **argv) {
fclose(pwf_file);
free(loop_bounds);
// avoid double free of pointers
finder.empty();
} catch (otawa::Exception &ex){
cout << "An error occured : " << ex.message() << endl;
cerr << "An error occured : " << ex.message() << endl;
}
// stop measurements
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &finish);
// compute analysis time
sub_timespec(start, finish, &delta);
printf("dumpcft time: %d.%.9ld\n", (int)delta.tv_sec, delta.tv_nsec);
}
<?xml version="1.0" encoding="UTF-8"?>
<cache-config>
<icache>
<block_bits>4</block_bits>
<way_bits>0</way_bits>
<row_bits>12</row_bits>
</icache>
</cache-config>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE processor SYSTEM "/home/casse/otawa/otawa/data/dtd/cache.dtd">
<cache-config>
<icache>
<block_bits>4</block_bits>
<row_bits>1</row_bits>
<way_bits>2</way_bits>
<replace>LRU</replace>
</icache>
</cache-config>
<?xml version="1.0" encoding="UTF-8"?>
<processor class="otawa::hard::Processor">
<arch>ppc</arch>
<model>ppc750</model>
<builder>motorola</builder>
<stages>
<stage id="FI">
<name>FI</name>
<width>2</width>
<type>FETCH</type>
</stage>
<stage id="DI">
<name>DI</name>
<width>2</width>
<type>LAZY</type>
</stage>
<stage id="EX">
<name>EX</name>
<type>EXEC</type>
<width>4</width>
<ordered>true</ordered>
<fus>
<fu id="MEM">
<name>MEM</name>
<latency>5</latency>
<pipelined>true</pipelined>
<mem>true</mem>
</fu>
<fu id="ALU">
<name>ALU</name>
<width>2</width>
</fu>
<fu id="FALU">
<name>FALU</name>
<latency>3</latency>
<pipelined>true</pipelined>
</fu>
<fu id="MUL">
<name>MUL</name>
<latency>6</latency>
<pipelined>true</pipelined>
</fu>
<fu id="DIV">
<name>DIV</name>
<latency>15</latency>
</fu>
</fus>
<dispatch>
<inst>
<type>IS_LOAD</type>
<fu ref="MEM"/>
</inst>
<inst>
<type>IS_STORE</type>
<fu ref="MEM"/>
</inst>
<inst>
<type>IS_FLOAT</type>
<fu ref="FALU"/>
</inst>
<inst>
<type>IS_MUL</type>
<fu ref="MUL"/>
</inst>
<inst>
<type>IS_DIV</type>
<fu ref="DIV"/>
</inst>
<inst>
<type>IS_INT</type>
<fu ref="ALU"/>
</inst>
<inst>
<type>IS_CONTROL</type>
<fu ref="ALU"/>
</inst>
<inst>
<type>IS_INTERN</type>
<fu ref="ALU"/>
</inst>
</dispatch>
</stage>
<stage id="CM">
<name>CM</name>
<type>COMMIT</type>
<width>2</width>
</stage>
</stages>
<queues>
<queue>
<name>FETCH_QUEUE</name>
<size>3</size>
<input ref="FI"/>
<output ref="DI"/>
</queue>
<queue>
<name>ROB_QUEUE</name>
<size>4</size>
<input ref="DI"/>
<output ref="CM"/>
<intern>
<stage ref="EX"/>
</intern>
</queue>
</queues>
</processor>
This diff is collapsed.
......@@ -33,6 +33,7 @@
struct evalctx_s {
loopinfo_t *li;
param_valuation_t *param_valuation;
bparam_valuation_t *bparam_valuation;
void *pv_data;
};
typedef struct evalctx_s evalctx_t;
......@@ -49,7 +50,11 @@ void awcet_alt(evalctx_t * ctx, int source_count, formula_t * source,
void awcet_loop(evalctx_t * ctx, awcet_t * source, formula_t * dest);
void awcet_ann(evalctx_t * ctx, awcet_t * source, formula_t * dest);
void awcet_intmult(evalctx_t * ctx, awcet_t * source, formula_t * dest);
void awcet_boolmult(evalctx_t* ctx, formula_t* source, awcet_t* dest);
void awcet_paramloop(evalctx_t* ctx, awcet_t* source, formula_t* dest);
int check_condition(evalctx_t* ctx, condition_t* cdts, int condition_size);
int compute_loop_bound(evalctx_t* ctx, condition_t* cdt);
void writeC(formula_t *f, FILE *out, int indent);
void writePWF(formula_t *f, FILE *out, long long *bounds);
......
Authors
--
Sandro Grebant (Université de Lille)
ARMPREFIX=arm-none-eabi
CC=gcc
ARMCC=$(ARMPREFIX)-gcc
ARMAR=$(ARMPREFIX)-ar
ARMRANLIB=$(ARMPREFIX)-ranlib
CFLAGS=-Ofast -g -Wall -march=native
ARMCFLAGS=-Ofast -g -Wall -fno-tree-loop-distribute-patterns
default: libpwcet.a libpwcet_arm.a
all: clean libpwcet.a libpwcet_arm.a
pwcet.o:
$(CC) $(CFLAGS) -c pwcet.c -o $@
pwcet_arm.o:
$(ARMCC) $(ARMCFLAGS) -c pwcet.c -o $@
libpwcet.a: pwcet.o
ar r $@ $^
ranlib $@
libpwcet_arm.a: pwcet_arm.o
$(ARMAR) r $@ $^
$(ARMRANLIB) $@
clean:
rm -f *.o *.a
This diff is collapsed.
This diff is collapsed.
......@@ -66,9 +66,36 @@ typedef union opdata_u opdata_t;
#define KIND_CONST 4
#define KIND_AWCET 5
#define KIND_INTMULT 6
#define KIND_BOOLMULT 7
#define KIND_STR 8
#define KIND_PARAM_LOOP 15
/* Boolean operator type */
#define BOOL_CONST 9
#define BOOL_PARAM 10
#define BOOL_CONDITIONS 11
#define BOOL_LEQ 12
#define BOOL_EQ 13
#define BOOL_BOUND 14
#define IDENT_NONE 0
struct term_s {
int kind;
int coef;
int value;
};
typedef struct term_s term_t;
/* Condition representation */
struct condition_s {
int kind;
int int_value; // parameter id or constant
int terms_number; // the number of terms
term_t *terms; // terms for leq / eq
};
typedef struct condition_s condition_t;
/* WCET formula representation */
struct formula_s {
int kind;
......@@ -83,6 +110,8 @@ struct formula_s {
opdata_t opdata;
awcet_t aw;
struct formula_s *children;
struct condition_s *condition;
char bool_expr[1000];
};
typedef struct formula_s formula_t;
union param_value_u {
......@@ -94,7 +123,9 @@ typedef union param_value_u param_value_t;
typedef void (param_valuation_t) (int param_id, param_value_t * param_val, void *data);
typedef int bparam_value_t;
typedef bparam_value_t (bparam_valuation_t) (int bparam_id);
long long evaluate(formula_t *f, loopinfo_t *li, param_valuation_t pv, void *data);
long long evaluate(formula_t *f, loopinfo_t *li, param_valuation_t pv, bparam_valuation_t bpv, void *data);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment