Closed aubertc closed 2 years ago
So, actually, I believe I have to either
pragram loopX
(for X = 1, 2, 3, …) to "flag" them.Is this correct? I am sorry but I could not find the documentation to use an "off-the-shelf" .lara file.
Thanks!
Hello @aubertc , first thanks for the feedback and for trying to use the tool.
I'm on my way now to give a class, so I will give you a brief answer now, but from what I see the problem is related to this:
Found 0 source files
You need to specify paths to source files to process. You can do that with the flag -p:
java -jar Clava.jar AutoPar.lara -o after/ -p test/bicg.c
Please take into account that you need to provide complete versions of C/C++ code. This means that if bigc.c
has includes other than system includes, you need to provide them also, with the flag -ih:
java -jar Clava.jar AutoPar.lara -o after/ -p test/bicg.c -ih include
Thanks a lot! I have made some progress indeed, but now I'm struggling to get the library right.
Running
java -jar /opt/clava/Clava/Clava.jar Autopar.lara -p bicg.c -o after/
returns
/opt/clava/resources/polybench-c-4.2.1-beta/linear-algebra/kernels/bicg/bicg.c:18:10: fatal error: 'polybench.h' file not found
#include <polybench.h>
Please take into account that you need to provide complete versions of C/C++ code. This means that if bigc.c has includes other than system includes, you need to provide them also, with the flag -ih:
java -jar Clava.jar AutoPar.lara -o after/ -p test/bicg.c -ih include
Is include
supposed to be the library's path?
I have tried with
java -jar /opt/clava/Clava/Clava.jar Autopar.lara -p bicg.c -ih ../../../utilities/polybench.h -o after/
from
/opt/clava/resources/polybench-c-4.2.1-beta/linear-algebra/kernels/bicg
but got a
Caused by: java.lang.RuntimeException: Could not open folder '/opt/clava/resources/polybench-c-4.2.1-beta/linear-algebra/kernels/bicg/../../../utilities/polybench.h'
but the path is correct:
ls /opt/clava/resources/polybench-c-4.2.1-beta/linear-algebra/kernels/bicg/../../../utilities/
benchmark_list create_cpped_version.pl makefile-gen.pl polybench.c polybench.R run-all.pl time_benchmark.sh
clean.pl header-gen.pl papi_counters.list polybench.h polybench.spec template-for-new-benchmark.c
Ok, I got it, include
is supposed to be a folder:
java -jar /opt/clava/Clava/Clava.jar Autopar.lara -p bicg.c -ih ../../../utilities/ -o after/
"works" in the sense that I get a different error ;-)
Relevant bit:
--- AST parsing report ---
Parallelizing 1 for loops...
Parallelization finished
Apply exception: -> org.lara.interpreter.utils.ExceptionUtils.throwApplyException(ExceptionUtils.java:35)
Exception message: [JSException] TypeError: Cannot read property "kind" from null
Stack Trace:
--------------
--------------
org.lara.interpreter.exception.AspectDefException: Exception apply OmpParallelization_apply_0_0(to OmpParallelization_select_0)
I have used the "original" big.c file from polybench-c-4.2.1-beta, very similar to this one, where the only pragma directives are #pragma scop
and #pragma endscop
. I suppose I am suppose to "tag" each loop with e.g. #pragma loop 1
if I want to parallelize it, correct?
Is there any way from AutoPar.lara
to indicate "parallelize all loops inside the #pragma scop
scope", without having to tag them? My goal right now is to reproduce what you obtained and shared at https://zenodo.org/record/1889368
Thanks!
According to the output you posted, it seems the parallelization is happening, the error happens after the parallelization:
Parallelizing 1 for loops...
Parallelization finished
It seems In order to replicate this problem, it would be better if you could provide a replication package (e.g. .lara file + C source + launch instructions). However, there is a simpler way to replicate those results.
We have developed a CMake package which can apply Lara scripts in the code of a CMake project, and we have a CMake project that replicates the results found here. Instructions for replication (Linux-only):
sudo
(necessary for installing the Clava CMake package)ANTAREX/AutoPar
, create a build folder (e.g. mkdir build
), enter the build foldercmake ..
). This will call Clava and perform the auto-parallelization for all examples. It can take a while, since there are several examples, and some are quite big (e.g. thousands of lines of code). If you want to just parallelize bicg, do the following:
#add_subdirectory(NAS)
)bicg
.After running cmake ..
(or simply make
, after the first time you run CMake, in case your default is Unix Makefiles), the parallelized version of bicg
should be in the build folder, in a path similar to build/Polybench/bicg/bicg_clava_weave/woven/bicg.c
As a side note, we are currently moving away from .lara files, in favor of pure .js files, that way it is possible to use modern JavaScript. This is supported in the last version of Clava, just passing a .js file instead of a .lara file should work. However, in this case you have to use JS APIs instead of the DSL constructs (e.g. Query.search()
instead of select
).
Thanks a lot, that's a great level of support :-)
A couple of comments:
/opt/clava/specs-lara/ANTAREX/AutoPar/Polybench/bicg/bicg.c:18:10: fatal error: 'polybench.h' file not found
#include <polybench.h>
^~~~~~~~~~~~~
1 error generated.
Comment all lines from 4 to 31 in specs-lara/ANTAREX/AutoPar/Polybench/CMakeLists.txt , except for line 9, which corresponds to bicg.
add_subdirectory(utilities)
should not be commented ;-)
kernel_
: // Only parallelize loops inside Polybench kernel functions
if(!$function.name.startsWith("kernel_")) {
Isn't there a way of saying "everything between #pragma scop
and #pragma endscop
"? (I guess this will be easier to do with .js files…).
/opt/clava/specs-lara/ANTAREX/AutoPar$ java -jar /opt/clava/Clava/Clava.jar Polybench/PolybenchAutopar.lara -p Polybench/bicg/bicg.c -ih Polybench/utilities/ -o after/
with the same PolybenchAutopar.lara file gives me almost the expected output, but the
#pragma omp parallel for default(shared) private(j) firstprivate(m, i, r, A, p) reduction(+ : q[i])
directive is not commented. Why this difference? Is CMake doing some additional magic behind the scene?
Is CMake doing some additional magic behind the scene?
Ok, I get it, Polybench/CheckOpenMPPragmas.lara
is doing that magic. But if I try to do something like
java -jar /opt/clava/Clava/Clava.jar Polybench/CheckOpenMPPragmas.lara -p after/woven_code/bicg.c -ih Polybench/utilities/ -ih Polybench/bicg/ -o after_openmp/
then I'm getting
org.lara.interpreter.exception.AspectDefException: TypeError: Cannot read property "toString" from undefined
Thanks for the feedback!
add_subdirectory(utilities) should not be commented ;-)
You are right, fixed it in the documentation.
Isn't there a way of saying "everything between #pragma scop and #pragma endscop"? (I guess this will be easier to do with .js files…).
Yes, you can do with code like this, that could be encapsulated by a function that receives the strings that represent the pragma "delimiters" and returns the array with the statements:
for(var startPragma of Query.search("pragma", "scop")) {
var stmtsBetweenPragmas = [];
// Get first stmt below the pragma that is not another pragma or comment
var startStmt = startPragma.target;
stmtsBetweenPragmas.push(startStmt);
// Iterate over right sibling, looking for the end pragma
for(var currentStmt of startStmt.siblingsRight) {
// Wrapper stmts wrap comments and pragmas, which are not stmts per se
if(currentStmt.instanceOf("wrapperStmt")) {
// Found end pragma
if(currentStmt.kind === "pragma" && currentStmt.content.name === "endscop") {
break;
}
}
// Otherwise continue adding statements
stmtsBetweenPragmas.push(currentStmt);
}
}
This code should work both in .lara and .js files, provided that you include the import for the class Query
. If you are in a .lara, you can add import weaver.Query;
at the beginning of the file; if you are in a .js, add laraImport("weaver.Query")
.
However, I think this functionality is useful enough to be provided out-of-the-box, so I've updated Clava to add the attribute to $pragma.targetNodes
, which can be used in two ways:
// Returns the first pragma that if finds that has the name scop
var $pragma = Query.search("pragma", "scop").first();
// Nodes between #pragma scop and #pragma endscop
var nodesBetweenScopAndEndscop = $pragma.targetNodes("endscop");
// Nodes after #pragma scop
var nodesAfterScop = $pragma.targetNodes;
directive is not commented. Why this difference? Is CMake doing some additional magic behind the scene?
As you realized, there is some extra processing done by other file, Polybench/CheckOpenMPPragmas.lara
. Because nested OpenMP pragmas usually lead to degraded performance, it is applying a very simply heuristic, that comments nested pragmas.
then I'm getting
org.lara.interpreter.exception.AspectDefException: TypeError: Cannot read property "toString" from undefined
This is because CheckOpenMPPragmas.lara
receives a non-optional input, that throws the exception when used:
aspectdef CheckOpenMPPragmas
input expectedCodeFile, generateOutputs = false end
To set inputs with the command line, use the flag -av
:
java -jar /opt/clava/Clava/Clava.jar Polybench/CheckOpenMPPragmas.lara -av {expectedCodeFile='expected_output.c',generateOutputs=true} -p after/woven_code/bicg.c -ih Polybench/utilities/ -ih Polybench/bicg/ -o after_openmp/
With this input configuration, it will generated a file with the expected output, instead of comparing the generated code with the provided file. This is a special file for testing the outputs, you can disabled it by commenting the line in CMakeLists.txt
that calls it.
Hi!
However, I think this functionality is useful enough to be provided out-of-the-box, so I've updated Clava to add the attribute to $pragma.targetNodes, which can be used in two ways:
I'm glad if my questions triggered some nice additions :-)
This is because CheckOpenMPPragmas.lara receives a non-optional input, that throws the exception when used:
I don't get it. expected_output.c
is the expected output, but how do you run CheckOpenMPPragmas.lara
the first time?
My question was "what is the lara instructions to comment the pragma directives inside loops", but it looks like CheckOpenMPPragmas.lara
is doing more than that?
expected_output.c is the expected output, but how do you run CheckOpenMPPragmas.lara the first time?
With the second parameter, generateOutputs
, which by default is false
, but when set to true
writes to the file expected_output.c
.
My question was "what is the lara instructions to comment the pragma directives inside loops", but it looks like CheckOpenMPPragmas.lara is doing more than that?
Yes, CheckOpenMPPragmas.lara
is doing two things, commenting the nested pragmas, and testing the expected output. The folder ANTAREX/AutoPar
is in fact a set of integration tests for AutoPar, which runs periodically in our CI server.
The code that comments the nested pragmas corresponds to these lines:
select pragma{"omp"}.target end
apply
// Comment OpenMP pragmas that are inside a loop that already has an OpenMP pragma
if($target.instanceOf("loop")) {
if(!hasForAncestorWithOmp($target)) {
continue;
}
$pragma.insert replace "// " + $pragma.code;
}
end
Using the JavaScript API, the equivalent code would be something like:
for(var $pragma of Query.search("pragma", "omp")) {
var $target = $pragma.target;
// Must have a target. If inserted by AutoPar, will have a target
if($target === undefined) {
continue;
}
// Comment OpenMP pragmas that are inside a loop that already has an OpenMP pragma
if($target.instanceOf("loop")) {
// Use function hasForAncestorWithOmp defined in the same file to check if this is a nested OpenMP pragma
if(!hasForAncestorWithOmp($target)) {
continue;
}
// Replace pragma with a comment that contains its own code
$pragma.replaceWith("// " + $pragma.code);
}
}
Thanks a lot, I'll look at it soon and get back to you when I have tried it.
Ok, so I came up with the following lara file:
import clava.autopar.Parallelize;
import clava.autopar.AutoParStats;
import lara.Io;
import lara.Check;
function hasForAncestorWithOmp($target) {
// Find ancestor that is a loop
$loopParent = $target.ancestor('loop');
// No loop parent found, return
if($loopParent === undefined) {
return false;
}
// Check if parent has an OpenMP pragma
for(var $parentPragma of $loopParent.pragmas) {
// Found OpenMP pragma, return
if($parentPragma.name === "omp") {
return true;
}
}
// No OpenMP pragma found, check parent for
return hasForAncestorWithOmp($loopParent);
}
aspectdef PolybenchAutopar
// Reset stats
AutoParStats.reset();
var $loops = [];
select file.function.loop end
apply
// Only parallelize loops inside Polybench kernel functions
if(!$function.name.startsWith("kernel_")) {
continue;
}
// Set name
AutoParStats.get().setName(Io.removeExtension($file.name));
$loops.push($loop);
end
Parallelize.forLoops($loops);
select pragma{"omp"}.target end
apply
// Comment OpenMP pragmas that are inside a loop that already has an OpenMP pragma
if($target.instanceOf("loop")) {
if(!hasForAncestorWithOmp($target)) {
continue;
}
$pragma.insert replace "// " + $pragma.code;
}
end
var currentCode = "<not initialized>";
select file end
apply
var filename = $file.name;
if(!filename.endsWith(".c")) {
continue;
}
if(filename === "polybench.c") {
continue;
}
currentCode = $file.code;
break;
end
// Generate outputs and return
Io.writeFile(filename, currentCode);
return;
end
that optimizes all the loops inside the function whose name starts with kernel_
, then comment the inner-most pragma
directives and output the file.
It is probably not the prettiest, but it works, in the sense that I can reproduce exactly your examples.
Thanks a lot for your support, I really appreciate it, and it is nice to be able to reproduce your examples exactly. This builds up my confidence in running your program on my own files and seeing how much clava can make me gain :-)
Hi!
Thanks for maintaining this tool and your documentation. Unfortunately, I don't understand how to run
AutoPar-Clava
on a file of my own. I started first by trying to run it on a file from the Polybench suite, but was not successful.What I have done so far:
AutoPar.lara
file (vaguely inspired by this example):aspectdef OmpParallelization
end
-==================================================-
But my test folder remains empty.
I can see on this archive that you removed the
prama scop
instructions from the polybench code, but I don't understand which<aspect.lara>
file I am supposed to provide to parallelize this example.Thanks!