-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does Tiramisu have legality check of scheduling? #300
Comments
Hi @iasakura , The master version of Tiramisu does not have dependence analysis implemented. One of our contributors had dependence analysis implemented but did not contribute his code. We are interested in having this feature though. If you are interested in helping that is very appreciated. Implementing legality check in Tiramisu is easy: we use the ISL library which already computes all dependences and returns a graph of dependences. What we need to do on the Tiramisu is two things: (1) extract all the information necessary and that will be passed to ISL to compute the dependences; and (2) implement a legality check that check if the dependences after applying the schedule is still preserved (this means computing the dependences then applying the schedule and computing whether the new schedule breaks the dependences which amounts to computing the difference between execution dates). All of this is easy to implement and I can assist you about each of these steps. So if you are interested in helping let me know please. |
Hi @rbaghdadi, Thank you for replying! I am very interested in legality check of tiramisu. So I will try to implement legality check. The following is my implementation idea. (1) Build the dataflow dependence relation D from layer 1 IR. D is a binary relation (isl map) on iteration space such that (i -> j) \in D iff the iteration j reads the values computed in the iteration i. It can be easily built from the read relation R: i -> j \in R iff the iteration j reads from i ( (2) Check legality of time scheduling. Given scheduling function S, we can check the legality of time scheduling S by checking D \subset <_S where <_S is a scheduling relation satisfying i <_S j iff S(i) < S(j) (lexicographical order). (3) Check legality check of memory scheduling. Given a write function W, which is given by (i) Compute the last use map L. L maps an iteration i to its last use iteration. It can be computed by # C1 = { i1 -> i2 : S(i1) < S(L(i2)) }
C1 = S.lex_lt_union_map(L.apply_range(S))
# C2 = { i1 -> i2 : S(i2) < S(L(i1)) }
# = C.reverse()
C2 = C1.reverse()
# CS = { i1 -> i2 : i1 < L(i2) && i2 < L(i1) }
# = { i1 -> i2 : i1 < L(i2) } \cap { i1 -> i2 : i2 < L(i1) }
# = C1 \cap C2
CS = C1.intersect(C2).subtract(I.identity()) Finally, we can check the validity of W by checking emptiness of the set { i -> j : i -> j \in CS and W(i) = W(j) }. It can be checked by the folliwng code. # pairs of iterations which writes to same indices
same_idx=W.domain_product(W).domain().unwrap()
# { i1 -> i2 : i1 -> i2 \in CS, WW(i1) == WW(i2) }
invalid=same_idx.intersect(CS)
ok=invalid.is_empty() The bellow is a simple example checking legality for iterative matrix-vector multiplication using double buffering. import islpy as isl
# for (t)
# for (j)
# for (i)
# prod[t%2][i]= prod[t%2][i] + A[i][j] * prod[(t-1)%2][j]
# Tiramisu code:
# computation prod("prod" {t, i, j}, p_float32);
# prod.set_expression(prod(t, i, j - 1) + A(i, j) * prod(t - 1, j, N - 1));
# prod.interchange(i, j)
# prod.store_in("prod_buf", {t % 2, i, 0})
# Iteration domain
I = isl.Set('[T, N] -> {prod[t, i, j] : 0 <= t < T and 0 <= i < N and 0 <= j < N}')
# Read relation
R = isl.Map('[T, N] -> {prod[t, i, j] -> prod[t, i, j-1] : t > 0 and j > 0; prod[t, i, j] -> prod[t-1, j, N-1] : t > 0 and j > 0}').intersect_domain(I)
# Default write relation
Wdefault = isl.Map('[T, N] -> {prod[t, i, j] -> prod[t, i, j]}').intersect_domain(I)
# User specified write function
W = isl.Map('[T, N, M] -> {prod[t, i, j] -> prod_buf[t % 2, i, 0]}').intersect_domain(I)
# Scheduling function & relation
S = isl.Map('[T, N] -> {prod[t, i, j] -> [t, j, 0]}')
O = S.lex_lt_union_map(S)
# Dependency relation
D = Wdefault.apply_range(R.reverse())
# Check legality of time scheduling
is_time_sched_ok = D.is_subset(O)
print(is_time_sched_ok)
# Last use function
# {(i->j)->k : i->j \in D and j -> k \in S }.lexmax()
L = D.range_map().apply_range(S).lexmax().domain().unwrap()
# Conflict set CS = C1 \cap C2
# C1 = { i1 -> i2 : S(i1) < S(L(i2)) }
C1 = S.lex_lt_union_map(L.apply_range(S))
# C2 = { i1 -> i2 : S(i2) < S(L(i1)) }
# = C.reverse()
C2 = C1.reverse()
# CS = { i1 -> i2 : i1 < L(i2) && i2 < L(i1) }
# = { i1 -> i2 : i1 < L(i2) } \cap { i1 -> i2 : i2 < L(i1) }
# = C1 \cap C2
CS = C1.intersect(C2).subtract(I.identity())
# pairs of iterations which writes to same indices
# { i1 -> i2 : i1 -> i2, W(i1) == W(i2) }
same_idx=W.domain_product(W).domain().unwrap()
# Conflicting pair which write to the same index
invalid=same_idx.intersect(CS)
# Check legality of memory scheduling
is_memory_sched_ok=invalid.is_empty()
print(is_memory_sched_ok) I will implement the above algorithm as a [1] Someshekaracharya Bhaskaracharya, Uday Bondhugula, and Albert Cohen. SMO: An integrated approach to intra-array and inter-array storage optimization. POPL 2016 |
Hi @iasakura , This looks very interesting. Thanks! Let me look at this in detail and get back to you. |
Hi @rbaghdadi , I implemented PoC version of legality check of scheduling. Here is my branch: |
Hi @iasakura , thanks! This looks great. I'll review the code and let you know. |
Here are few high level comments:
The other things seem tp be good for me! Thanks for the nice implementation! |
Hi @rbaghdadi , Thank you for your nice comments!
Sure! I will add comments soon.
Oh, I didn't find Also, I want to add more tests for legality check. If you have good example, please let me know. |
Thanks. Yes good point. But actually Layer I can introduce false dependences because it supports updates. The user can declare a computation and then update it (i.e., erase the old value and put a new value). This is the case of reductions or simply in-place computations. There is no need to do dependence analysis at Layer I though, it is better to do it in Layer III once you know how computations are stored in memory. So I'm Ok with your suggestions. It would just be good to expose the result of dependence analysis to Tiramisu users because such result would be useful (for example for computing live-in and live-out variables or for bound inference). Depending on how much time you have to work on this, feel free to do just what you suggested above or to actually do dependence analysis in Layer III (by exploiting the ISL dependence analysis call). |
I tried the following example in Tiramisu master (c40b004).
I expected that this will cause an error when "AFTER=" is enabled because the scheduling
g.after(f, x)
breaks dependency between f and g. However, it can be compiled and returns a broken result.The Tiramisu paper "Tiramisu: A Code Optimization Framework for High Performance Systems" says that "TIRAMISU does not have
this restriction since it checks transformation legality using
dependence analysis [18].", but I cannot find the way to check "transformation legality".
How can we check the legality of transformation?
The text was updated successfully, but these errors were encountered: