Open aubertc opened 2 years ago
The code that is being replaced are macros. You could say this is a limitation of the C/C++ language, that perform those transformations during the pre-processor phase, and that when the code is parsed, those changes already happened.
Clava parses the code (with the help of Clang) into an Abstract-Syntax Tree (AST), and then regenerates the code from the AST. We try to revert some of the changes introduced by the pre-processor (e.g. re-insert #include directives, comments), but not generally.
Usually this is not a problem, since we tend to use Clava to apply a set of transformations before the compiler (as it happens with the CMake package), so we are not worried about the macros being resolved, the generated code is "temporary". I suspect the timer instructions are being deleted because they are controlled by #define directives that are not being set (you can use the flag -fs
to pass any set of C/C++ compiler flags that you would pass to Clang/gcc).
However, there is a possible solution, that requires some work, which is to recreate the source files directly, in a textual manner. The function Parallelize.getForLoopPragmas can be used to calculate the OpenMP pragmas, without changing the code. You will receive an object that maps loop ids to the corresponding OpenMP pragma, and with the $loop
node, you can also access the corresponding $file
(using $loop.ancestor('file')
), which contains the path to the original file. You can also access the line where the loop appears ($loop.line
), so you have all the information for textually recreating the source file, inserting the pragmas before the lines of the loops.
Tip: this is fairly easy to do if you read the source file as a list of strings, one per line, and insert the corresponding pragmas in reverse order, as new elements of the list.
Thanks a lot, that is very useful.
We try to revert some of the changes introduced by the pre-processor (e.g. re-insert #include directives, comments), but not generally.
Ok, that's what threw me off: I thought all the original source code was restored, hence my confusion.
However, there is a possible solution, that requires some work,
Thanks a lot for drafting it, I think for the time being I will "simply" copy-and-paste the pragma
directive back into the original source code.
But then I have another question, somewhat related (I can open a different issue if you prefer) about the fdtd-2d.c file from the Polybench/C suite.
static
void kernel_fdtd_2d(int tmax,
int nx,
int ny,
DATA_TYPE POLYBENCH_2D(ex,NX,NY,nx,ny),
DATA_TYPE POLYBENCH_2D(ey,NX,NY,nx,ny),
DATA_TYPE POLYBENCH_2D(hz,NX,NY,nx,ny),
DATA_TYPE POLYBENCH_1D(_fict_,TMAX,tmax))
to
static void kernel_fdtd_2d(int tmax, int nx, int ny, double ex[1000][1200], double ey[1000][1200], double hz[1000][1200], double _fict_[500]) {
and that raises a question: following our discussion, I understand why clava is "hard-coding" the values for NX
and NY
, but why is it "hard-coding" the values for LARGE_DATASET
? This creates complication if I try to extract those directives (that contains reduction(- : hz[:1000][:1200]
) for smaller datasets.
Ok, that's what threw me off: I thought all the original source code was restored, hence my confusion.
This is more of an issue of C/C++ regarding the preprocessor and code generation from AST (if you want to check the "real" C/C++ code that goes to the parser after the text-substitution of the preprocessor is done, try compiling the code with the flag -E
, e.g., gcc -E foo.c
). We have equivalent tools for other languages (e.g. Java, JavaScript) where it is much easier to obtain code very close to the original (without regards for the original formatting).
about the fdtd-2d.c file from the Polybench/C suite. Why is not included in https://github.com/specs-feup/specs-lara/tree/master/ANTAREX/AutoPar/Polybench ?
I had not noticed this. It is indeed strange, since we even have results for fdtd-2d
in the AutoPar papers. I will have to check this, and consider updating the dataset.
why is it "hard-coding" the values for LARGE_DATASET?
I think this is happening because LARGE_DATASET is the default dataset in Polybench, for instance in the file fdtd-2d.h
there is this code:
/* Default to LARGE_DATASET. */
# if !defined(MINI_DATASET) && !defined(SMALL_DATASET) && !defined(MEDIUM_DATASET) && !defined(LARGE_DATASET) && !defined(EXTRALARGE_DATASET)
# define LARGE_DATASET
# endif
If you do not set a specific dataset (e.g. flag -DSMALL_DATASET
for the small dataset), LARGE_DATASET is used. For the Clava use case I've mentioned, where it applies transformations just before the compiler, this usually is not a problem, since the pragmas are generated just before compilation, and you can control the dataset size in the Polybench benchmark using compilation flags.
If you want to manually extract the pragmas and insert them in the source code, you should also manually replace the hardcoded values with the corresponding macros (e.g. NX
, NY
).
If I compare e.g. the original file of the 3mm.c test of the PolyBench suite with the expected output, then there are some changes outside of the
kernel_3mm
function.For instance, the header:
https://github.com/specs-feup/specs-lara/blob/06b1422430e13b6b55c1f864bb0dfd9fa2293f20/ANTAREX/AutoPar/Polybench/3mm/3mm.c#L26-L30
has some variables replaced by their values:
https://github.com/specs-feup/specs-lara/blob/06b1422430e13b6b55c1f864bb0dfd9fa2293f20/ANTAREX/AutoPar/Polybench/3mm/expected_output.c#L20
My understanding was that any edit to the polybench source files should happen inside that function definition, and not outside.
Is this unavoidable? Is there, at least, a workaround to not delete the timer instructions (at https://github.com/specs-feup/specs-lara/blob/06b1422430e13b6b55c1f864bb0dfd9fa2293f20/ANTAREX/AutoPar/Polybench/3mm/3mm.c#L159-L161 , that are simply removed in https://github.com/specs-feup/specs-lara/blob/06b1422430e13b6b55c1f864bb0dfd9fa2293f20/ANTAREX/AutoPar/Polybench/3mm/expected_output.c#L122-L124 )?