[patch] testcases for autopar

1 view
Skip to first unread message

Li Feng

unread,
Jul 3, 2009, 10:56:34 AM7/3/09
to gcc-gr...@googlegroups.com, Tobias Grosser
Hi,

Currently I'm preparing testsuites for autopar,
especially for loops with IF conditions and triangle
loops.

1. IF conditions
This works well for my test case, see test case 0.

2. Triangle loops.

- Dependency checking part works well with triangle
loop, while the code generation part seems not, it will
not generate parallel code (actually,
I don't know whether this is reasonable or not), which
will fail at if (!try_get_loop_niter (loop, &niter_desc))
with saying "number of iterations not known".

- A might be bug in SCoP detection
For the test case 1, it will not recognize the SCoP.

3. Testcases will test both dependency checking and
code generation.
- The former testsuites only test whether it generate gmp
code. Now I would like to dump some dependency checking
information (sth. like "%d loops carried no dependency")
to graphite dump file and checking whether
this part works well (see the patch).

- Graphite pass trigger several times for the simple testcase 3.
I'm wondering when this happens? For this testcase, there is
only one loop that can parallel, but while it dump the
information "1 loops carried no dependency" twice. Then I
found out Graphite pass is trigger several times.

[test cases]
* test case 0
for (i = 0; i < N; i++)
{
if (i < T)
/* loop i1: carried no dependency. */
A[i] = A[i+T];
else
/* loop i2: carried dependency. */
A[i] = A[i+T+1];
}

* test case 1 (if I change i<=N and j <= i to
i < N and j < i, this works well)
#define N 500
int foo(void)
{
int i,j;
int A[3*N];

for (i = 1; i < N; i++)
for (j = 1; j < i; j++)
/* This loop carried no dependency, it fails
at code generation part.*/
A[j+N] = A[j] + 5;

return A[10];
}

* test case 3 (This stays in graphite_autopar/force-parallel-1.c)
void abort (void);

void parloop (int N)
{
int i;
int x[10000000];

for (i = 0; i < N; i++)
x[i] = i + 3;

for (i = 0; i < N; i++)
{
if (x[i] != i + 3)
abort ();
}
}

int main(void)
{
parloop(10000000);

return 0;
}
=====================
Here is the first bunch of patch, I will try to add more testsuites later.

diff --git a/gcc/graphite-clast-to-gimple.c b/gcc/graphite-clast-to-gimple.c
index 55d5f7e..8032239 100644
--- a/gcc/graphite-clast-to-gimple.c
+++ b/gcc/graphite-clast-to-gimple.c
@@ -1302,15 +1302,25 @@ void mark_loops_parallel (htab_t bb_pbb_mapping)
{
loop_p loop;
loop_iterator li;
+ int num_no_dependency = 0;

FOR_EACH_LOOP (li, loop, 0)
{
if (!loop->aux)
- continue;
+ continue;

if (!dependency_in_loop_p (loop, bb_pbb_mapping))
- loop->can_be_parallel = true;
+ {
+ loop->can_be_parallel = true;
+ num_no_dependency++;
+ }
}
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\n%d loops carried no dependency.\n",
+ num_no_dependency);
+ }
+
}

#endif
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-1.c b
index 8ef77a7..a507759 100644
--- a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-1.c
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-1.c
@@ -22,6 +22,8 @@ int main(void)
return 0;
}
/* Check that parallel code generation part make the right answer. */
+/* { dg-final { scan-tree-dump-times "1 loops carried no dependency" 2 "graphit
+/* { dg-final { cleanup-tree-dump "graphite" } } */
/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-2.c b
index 54eaac9..a198fed 100644
--- a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-2.c
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-2.c
@@ -23,6 +23,8 @@ int main(void)
}

/* Check that parallel code generation part make the right answer. */
+/* { dg-final { scan-tree-dump-times "2 loops carried no dependency" 1 "graphit
+/* { dg-final { cleanup-tree-dump "graphite" } } */
/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-3.c b
index e9511b1..7b7e691 100644
--- a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-3.c
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-3.c
@@ -1,28 +1,37 @@
void abort (void);

-void parloop (int N)
+#define N 500
+
+void foo(void)
{
- int i, j;
- int Z[3000][3000];
+ int i,j;
+
+ int Z[2*N+2][2*N+2], B[2*N+2][2*N+2];
+
+ for (i = 0; i < 2*N+2; i++)
+ for (j = 0; j < 2*N+2; j++)
+ B[i][j] = Z[i][j] = i + j;

for (i = 0; i <= N; i++)
for (j = 0; j <= N; j++)
Z[i][j] = Z[j+N][i+N+1];

for (i = 0; i <= N; i++)
- for (j = 0; j <= N; j++)
- if (Z[i][j] != Z[j+N][i+N+1])
+ for (j = 0; j <=N; j++)
+ if (Z[i][j] != B[j+N][i+N+1])
abort();
}

-int main(void)
+int main()
{
- parloop(1000);
-
+ foo();
return 0;
}

/* Check that parallel code generation part make the right answer. */
-/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "4 loops carried no dependency" 1 "graphit
+/* { dg-final { cleanup-tree-dump "graphite" } } */
+/* { dg-final { scan-tree-dump-times "loopfn.0" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn.1" 5 "optimized" } } */
/* { dg-final { cleanup-tree-dump "parloops" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-4.c b
new file mode 100644
index 0000000..ce522ec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-4.c
@@ -0,0 +1,55 @@
+/* Autopar with IF conditions. */
+
+void abort();
+
+#define N 10000
+#define T 1000
+
+void foo(void)
+{
+ int i;
+ int A[2*N], B[2*N];
+
+ /* Initialize array: carried no dependency. */
+ for (i = 0; i < 2*N; i++)
+ B[i] = A[i] = i;
+
+ for (i = 0; i < N; i++)
+ {
+ if (i < T)
+ /* loop i1: carried no dependency. */
+ A[i] = A[i+T];
+ else
+ /* loop i2: carried dependency. */
+ A[i] = A[i+T+1];
+ }
+
+ /* If it runs a wrong answer, abort. */
+ for (i = 0; i < N; i++)
+ {
+ if (i < T)
+ {
+ if (A[i] != B[i+T])
+ abort();
+ }
+ else
+ {
+ if (A[i] != B[i+T+1])
+ abort();
+ }
+ }
+}
+
+int main()
+{
+ foo();
+ return 0;
+}
+
+/* Check that parallel code generation part make the right answer. */
+/* { dg-final { scan-tree-dump-times "2 loops carried no dependency" 1 "graphit
+/* { dg-final { cleanup-tree-dump "graphite" } } */
+/* { dg-final { scan-tree-dump-times "loopfn.0" 5 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "loopfn.1" 5 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "parloops" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-5.c b
new file mode 100644
index 0000000..3460753
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/force-parallel-5.c
@@ -0,0 +1,31 @@
+/* Triangle loops. */
+void abort (void);
+
+#define N 500
+
+int foo(void)
+{
+ int i,j;
+ int A[3*N];
+
+ for (i = 1; i < N; i++)
+ for (j = 1; j < i; j++)
+ /* This loop carried no dependency, it fails
+ at code generation part.*/
+ A[j+N] = A[j] + 5;
+
+ return A[10];
+}
+
+int main()
+{
+ foo();
+
+ return 0;
+}
+/* Check that parallel code generation part make the right answer. */
+/* { dg-final { scan-tree-dump-times "1 loops carried no dependency" 1 "graphit
+/* { dg-final { cleanup-tree-dump "graphite" } } */
+/* { dg-final { scan-tree-dump-times "loopfn" 5 "optimized" { xfail *-*-* } } }
+/* { dg-final { cleanup-tree-dump "parloops" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/graphite_autopar.exp
index 093944c..71ebd49 100644
--- a/gcc/testsuite/gcc.dg/graphite/graphite_autopar/graphite_autopar.exp
+++ b/gcc/testsuite/gcc.dg/graphite/graphite_autopar/graphite_autopar.exp
@@ -45,7 +45,8 @@ set wait_to_run_files [lsort [glob -nocomplain $srcdir/$subdir
# Flags using for force-parallel-*.c files.
set DEFAULT_CFLAGS_FORCE_PARALLEL " -ansi -pedantic-errors -O2 \
-ftree-parallelize-loops=4 -fgraphite-force-parallel \
--fdump-tree-parloops-details -fdump-tree-optimized"
+-fdump-tree-parloops-details -fdump-tree-optimized \
+-fdump-tree-graphite-all"
set force_parallel_files \
[lsort [glob -nocomplain $srcdir/$subdir/force-parallel-*.c]]
dg-runtest $force_parallel_files "" $DEFAULT_CFLAGS_FORCE_PARALLEL

Li

Tobias Grosser

unread,
Jul 6, 2009, 3:50:56 AM7/6/09
to gcc-gr...@googlegroups.com
On Fri, 2009-07-03 at 22:56 +0800, Li Feng wrote:
> Hi,
>
> Currently I'm preparing testsuites for autopar,
> especially for loops with IF conditions and triangle
> loops.
>
> 1. IF conditions
> This works well for my test case, see test case 0.

Nice.


> 2. Triangle loops.
>
> - Dependency checking part works well with triangle
> loop, while the code generation part seems not, it will
> not generate parallel code (actually,
> I don't know whether this is reasonable or not), which
> will fail at if (!try_get_loop_niter (loop, &niter_desc))
> with saying "number of iterations not known".

It would be interesting to see why try_get_loop_niter() fails. And I do
not understand why Graphite can detect loops, where the number of
iterations is unknown. There seems to be different functions used in the
SCoP detection and in autopar.

> - A might be bug in SCoP detection
> For the test case 1, it will not recognize the SCoP.

If we cannot get the number of iterations, SCoP detection will not be
able to handle this loop.

> 3. Testcases will test both dependency checking and
> code generation.
> - The former testsuites only test whether it generate gmp
> code. Now I would like to dump some dependency checking
> information (sth. like "%d loops carried no dependency")
> to graphite dump file and checking whether
> this part works well (see the patch).

This is a good idea. However we should make sure, that future
optimizations do not generate more loops before we do dependency
checking. Otherwise these test cases would fail.
So please disable all graphite optimizations (strip mining) for this
test cases, or enable them explicitly if needed. (Already done)

Another nice test case would be to first to do strip mining and than
parallelize the code or do an interchange and than parallelize the code.
However I think the interchange code is not yet ready, and for strip
mining autopar needs to be able to handle outer loops.

> - Graphite pass trigger several times for the simple testcase 3.
> I'm wondering when this happens? For this testcase, there is
> only one loop that can parallel, but while it dump the
> information "1 loops carried no dependency" twice. Then I
> found out Graphite pass is trigger several times.

The Graphite pass is triggered once for every function. As your test
file defines to functions Graphite is triggered twice.

>
> [test cases]
> * test case 0
> for (i = 0; i < N; i++)
> {
> if (i < T)
> /* loop i1: carried no dependency. */
> A[i] = A[i+T];
> else
> /* loop i2: carried dependency. */
> A[i] = A[i+T+1];
> }
>
> * test case 1 (if I change i<=N and j <= i to
> i < N and j < i, this works well)
> #define N 500
> int foo(void)
> {
> int i,j;
> int A[3*N];
>
> for (i = 1; i < N; i++)
> for (j = 1; j < i; j++)
> /* This loop carried no dependency, it fails
> at code generation part.*/
> A[j+N] = A[j] + 5;

What is the failure?

Why do you add this to this file, and do not generate a new one? As long
as it is not required to be in one file, I prefer smaller files as it
makes debugging easier.

> for (i = 0; i <= N; i++)
> for (j = 0; j <= N; j++)
> Z[i][j] = Z[j+N][i+N+1];
>
> for (i = 0; i <= N; i++)
> - for (j = 0; j <= N; j++)
> - if (Z[i][j] != Z[j+N][i+N+1])
> + for (j = 0; j <=N; j++)
> + if (Z[i][j] != B[j+N][i+N+1])
> abort();
> }
>
> -int main(void)
> +int main()

Why do you remove the void?

What is the error message?

Please submit your patch to the regression tester.

Li Feng

unread,
Jul 6, 2009, 4:16:28 AM7/6/09
to gcc-gr...@googlegroups.com
Hi Tobi,
On Mon, Jul 6, 2009 at 3:50 PM, Tobias Grosser<gro...@fim.uni-passau.de> wrote:
>
> On Fri, 2009-07-03 at 22:56 +0800, Li Feng wrote:
>> Hi,
>>
>> Currently I'm preparing testsuites for autopar,
>> especially for loops with IF conditions and triangle
>> loops.
>>
>> 1. IF conditions
>> This works well for my test case, see test case 0.
>
> Nice.
>
>
>> 2. Triangle loops.
>>
>>     - Dependency checking part works well with triangle
>>       loop, while the code generation part seems not, it will
>>       not generate parallel code (actually,
>>       I don't know whether this is reasonable or not), which
>>       will fail at if (!try_get_loop_niter (loop, &niter_desc))
>>       with saying "number of iterations not known".
>
> It would be interesting to see why try_get_loop_niter() fails. And I do
> not understand why Graphite can detect loops, where the number of
> iterations is unknown. There seems to be different functions used in the
> SCoP detection and in autopar.

I'll try to look into this.

>
>>     - A might be bug in SCoP detection
>>       For the test case 1, it will not recognize the SCoP.
>
> If we cannot get the number of iterations, SCoP detection will not be
> able to handle this loop.

* test case 1 (if I change i<=N and j <= i to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
i < N and j < i, then SCoP detection can handle this loop,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
so this is strange.)
^^^^^^^^^^^^^^^^^^^^
#define N 500
int foo(void)
{
int i,j;
int A[3*N];

for (i = 1; i < N; i++)
for (j = 1; j < i; j++)
A[j+N] = A[j] + 5;

>
>> 3. Testcases will test both dependency checking and
>>     code generation.
>>     - The former testsuites only test whether it generate gmp
>>       code. Now I would like to dump some dependency checking
>>       information (sth. like "%d loops carried no dependency")
>>       to graphite dump file and checking whether
>>       this part works well (see the patch).
>
> This is a good idea. However we should make sure, that future
> optimizations do not generate more loops before we do dependency
> checking. Otherwise these test cases would fail.
> So please disable all graphite optimizations (strip mining) for this
> test cases, or enable them explicitly if needed. (Already done)
>
> Another nice test case would be to first to do strip mining and than
> parallelize the code or do an interchange and than parallelize the code.
> However I think the interchange code is not yet ready, and for strip
> mining autopar needs to be able to handle outer loops.
>

Good idea, and these test cases will be added when outer
loop parallelization done.

>>     - Graphite pass trigger several times for the simple testcase 3.
>>       I'm wondering when this happens? For this testcase, there is
>>       only one loop that can parallel, but while it dump the
>>       information "1 loops carried no dependency" twice. Then I
>>       found out Graphite pass is trigger several times.
>
> The Graphite pass is triggered once for every function. As your test
> file defines to functions Graphite is triggered twice.

Actually, it triggered 3times, so I'm thinking if the newly
created autopar loop (loopfn.0) trigger Graphite pass.
This is not a testcase, just initialization of array Z for the later
run time test. To make sure it returns a correct answer. And
to verify it runs a correct answer, make a copy of array Z to B.

>>    for (i = 0; i <= N; i++)
>>      for (j = 0; j <= N; j++)
>>        Z[i][j] = Z[j+N][i+N+1];
>>
>>    for (i = 0; i <= N; i++)
>> -    for (j = 0; j <= N; j++)
>> -      if (Z[i][j] != Z[j+N][i+N+1])
>> +    for (j = 0; j <=N; j++)
>> +      if (Z[i][j] != B[j+N][i+N+1])
>>         abort();
>>  }
>>
>> -int main(void)
>> +int main()
>
> Why do you remove the void?

Typo ;-)

>>  {
"number of iterations not known"

>
I have extended the testcases to 9. force-parallel-{1,2,...,9}
I will send these to regtester later.

>
>
>
> >
>

Li
Reply all
Reply to author
Forward
0 new messages