170 lines
3.9 KiB
C++
170 lines
3.9 KiB
C++
#include <set>
|
|
#include <fstream>
|
|
|
|
#include "isaac/array.h"
|
|
#include "isaac/jit/syntax/engine/process.h"
|
|
#include "isaac/runtime/scheduler/dag.h"
|
|
|
|
namespace isaac
|
|
{
|
|
namespace runtime
|
|
{
|
|
namespace scheduler
|
|
{
|
|
|
|
int extended_gcd(int a, int b, int &x, int &y)
|
|
{
|
|
if (a % b == 0){
|
|
x = 0;
|
|
y = 1;
|
|
return b;
|
|
}
|
|
|
|
int newx, newy;
|
|
int ret = extended_gcd(b, a % b, newx, newy);
|
|
|
|
x = newy;
|
|
y = newx - newy * (a / b);
|
|
return ret;
|
|
}
|
|
|
|
int gcd(int a, int b)
|
|
{
|
|
while(true)
|
|
{
|
|
if (a == 0)
|
|
return b;
|
|
b %= a;
|
|
if (b == 0)
|
|
return a;
|
|
a %= b;
|
|
}
|
|
}
|
|
|
|
int diophantine(int a, int b, int c, int &x, int &y)
|
|
{
|
|
int absa = std::abs(a);
|
|
int absb = std::abs(b);
|
|
int absc = std::abs(c);
|
|
int d = gcd(absa, absb);
|
|
if(absc % d > 0)
|
|
return -1;
|
|
int k = absc/d;
|
|
int res = extended_gcd(absa/d, absb/d, x, y);
|
|
x*=k;
|
|
y*=k;
|
|
if(a < 0) x*=-1;
|
|
if(b < 0) y*=-1;
|
|
if(c < 0){
|
|
x *= -1;
|
|
y *= -1;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int lcm(int a, int b)
|
|
{
|
|
int temp = gcd(a, b);
|
|
return temp ? (a / temp * b) : 0;
|
|
}
|
|
|
|
int first_overlap(int starta, int inca, int startb, int incb, int& x, int& y)
|
|
{
|
|
if(diophantine(inca, -incb, startb - starta, x, y)==-1)
|
|
return -1;
|
|
//Projects back the val so that it is immediately
|
|
//greater than max(starta, startb) up to lcm
|
|
int val = starta + inca*x;
|
|
int off = val - std::max(starta, startb);
|
|
int l = lcm(inca, incb);
|
|
if(off < 0 || off > l)
|
|
val += (1 - off/l)*l;
|
|
x = (val - starta)/inca;
|
|
y = (val - startb)/incb;
|
|
return val;
|
|
}
|
|
|
|
|
|
tuple dag::repack(int_t start, const tuple &ld)
|
|
{
|
|
std::vector<int_t> result(ld.size());
|
|
for(size_t i = result.size() - 1 ; i >= 1 ; i--){
|
|
int_t stride = ld[i-1];
|
|
result[i] = start/stride;
|
|
start -= result[i]*stride;
|
|
}
|
|
result[0] = start;
|
|
return result;
|
|
}
|
|
|
|
bool dag::overlap(expression_tree::node const & x, expression_tree::node const & y)
|
|
{
|
|
if(x.array.handle.cl != y.array.handle.cl ||
|
|
x.array.handle.cu != y.array.handle.cu ||
|
|
x.shape.size() != y.shape.size())
|
|
return false;
|
|
tuple offx = repack(x.array.start, x.ld);
|
|
tuple offy = repack(y.array.start, y.ld);
|
|
for(size_t i = 0 ; i < x.shape.size() ; ++i){
|
|
int indx, indy;
|
|
if(first_overlap(offx[i], x.ld[i], offy[i], y.ld[i], indx, indy)==-1)
|
|
return false;
|
|
if(indx < 0 || indx >= x.shape[i] || indy < 0 || indy >= y.shape[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
dag::dag()
|
|
{ jobs_.reserve(16); }
|
|
|
|
array_base& dag::create_temporary(array_base* tmp)
|
|
{
|
|
tmp_.push_back(std::shared_ptr<array_base>(tmp));
|
|
return *tmp;
|
|
}
|
|
|
|
void dag::append(expression_tree const & job, std::string const & name)
|
|
{
|
|
//Add new job
|
|
jobs_.push_back(job);
|
|
job_t newid = jobs_.size() - 1;
|
|
adjacency_.insert({newid, {}});
|
|
names_.push_back(name.empty()?tools::to_string(newid):name);
|
|
//Add dependencies;
|
|
std::vector<expression_tree::node const *> nread;
|
|
auto extractor = [&](size_t idx) { if(job[idx].type==DENSE_ARRAY_TYPE) nread.push_back(&job[idx]);};
|
|
symbolic::traverse(job, job[job.root()].binary_operator.rhs, extractor);
|
|
for(job_t previd = 0 ; previd < jobs_.size() ; ++previd){
|
|
expression_tree const & current = jobs_[previd];
|
|
expression_tree::node const & assignment = current[current.root()];
|
|
expression_tree::node const & pwritten = current[assignment.binary_operator.lhs];
|
|
auto pred = [&](expression_tree::node const * x){ return overlap(*x, pwritten);};
|
|
bool has_raw = std::find_if(nread.begin(), nread.end(), pred) != nread.end();
|
|
if(has_raw)
|
|
adjacency_[previd].push_back(newid);
|
|
}
|
|
|
|
}
|
|
|
|
void dag::export_graphviz(std::string const & path)
|
|
{
|
|
std::ofstream out(path);
|
|
out << "digraph {" << std::endl;
|
|
for(auto const & x: adjacency_)
|
|
out << x.first << "[label=\"" << names_[x.first] << "\"];" << std::endl;
|
|
for(auto const & x: adjacency_)
|
|
{
|
|
if(x.second.empty())
|
|
out << x.first << std::endl;
|
|
else
|
|
for(job_t y: x.second)
|
|
out << x.first << " -> " << y << ";" << std::endl;
|
|
}
|
|
out << "}" << std::endl;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|