specs-feup / clava

C/C++ Source-to-Source Tool based on Clang
Apache License 2.0
74 stars 11 forks source link

Running AutoPar-Clava on a simple example of my own #58

Closed aubertc closed 2 years ago

aubertc commented 2 years ago

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:

aspectdef OmpParallelization

// Parallelize loop annotated with pragma
select function{"kernel_bicg"}.pragma.target end
apply
    Parallelize.forLoops([$target]);
end

// Print modified code
select function{'kernel_bicg'} end
apply
    println($function.code);
end

end

- Ran `java -jar Clava.jar AutoPar.lara test/bicg.c -o after/`

Clava is then outputting the following:

-==================================================-

  1. Initializing Interpreter -==================================================- -==================================================-
  2. Loading Weaver -==================================================- Importing internal scripts: _ larai/includes/scripts/dot.js _ larai/includes/scripts/dwarvUtils.js _ larai/includes/scripts/input.js _ larai/includes/scripts/LaraObject.js _ larai/includes/scripts/merge.js _ larai/includes/scripts/namedArguments.js _ larai/includes/scripts/output.js _ larai/includes/scripts/select.js _ larai/includes/scripts/toolExecution.js _ larai/includes/scripts/utils.js _ larai/includes/scripts/xilinx.js _ larai/includes/scripts/Enum.js _ lara/LaraCore.js _ clava/js/autopar/AddmsgError.js _ clava/js/autopar/allReplace.js _ clava/js/autopar/GetLoopIndex.js _ clava/js/autopar/orderedVarrefs3.js _ clava/js/autopar/RemoveStruct.js _ clava/js/autopar/SafeFunctionCalls.js _ clava/js/autopar/SearchStruct.js _ clava/js/DataHandler.js _ clava/js/HDF5.js _ clava/js/Types.js \ clava/antarex/AntarexTest.js Found 0 source files [ClavaMetrics] Code to AST: 0ms [ClavaMetrics] AST Processing: 30ms [ClavaMetrics] Current memory used (Java):21 MiB --- AST parsing report --- -==================================================- Elapsed Time: 1498ms -==================================================- -==================================================-
  3. Setting up LARA -==================================================- Language Specification folder: . Output directory: after Path included for import: [., /home/caubert/Downloads/clava] Resources included for import: [lara/analysis/Analyser.lara, lara/analysis/AnalyserResult.lara, lara/analysis/CheckBasedAnalyser.lara, lara/analysis/Checker.lara, lara/analysis/CheckResult.lara, lara/analysis/Fix.lara, lara/analysis/MessageGenerator.lara, lara/analysis/ResultFormatManager.lara, lara/analysis/ResultList.lara, lara/benchmark/BenchmarkSet.lara, lara/benchmark/BenchmarkInstance.lara, lara/cmake/CMaker.lara, lara/cmake/CMakerSources.lara, lara/cmake/CMakerUtils.lara, lara/cmake/compilers/CMakeCompiler.lara, lara/cmake/compilers/GenericCMakeCompiler.lara, lara/dse/DseLoop.lara, lara/dse/DseValues.lara, lara/dse/DseValuesList.lara, lara/dse/DseValuesSet.lara, lara/dse/DseVariant.lara, lara/dse/VariableVariant.lara, lara/graphs/Graphs.js, lara/graphs/GraphNode.js, lara/graphs/GraphEdge.js, lara/iterators/LaraIterator.lara, lara/iterators/LineIterator.lara, lara/metrics/EnergyMetric.lara, lara/metrics/ExecutionTimeMetric.lara, lara/metrics/FileSizeMetric.lara, lara/metrics/Metric.lara, lara/metrics/MetricResult.lara, lara/mutation/IterativeMutation.lara, lara/mutation/IterativeMutator.lara, lara/mutation/Mutation.lara, lara/mutation/MutationResult.lara, lara/mutation/Mutator.lara, lara/pass/Pass.js, lara/pass/PassResult.js, lara/units/SiModifier.lara, lara/units/SiUnit.lara, lara/units/Unit.lara, lara/units/TimeModifier.lara, lara/units/TimeUnit.lara, lara/units/EnergyUnit.lara, lara/units/UnitModifier.lara, lara/units/UnitWithModifier.lara, lara/_JavaTypes.lara, lara/Check.lara, lara/Collections.lara, lara/Csv.lara, lara/Debug.lara, lara/Io.lara, lara/Numbers.lara, lara/Platforms.lara, lara/Strings.lara, lara/System.lara, lara/JavaInterop.lara, lara/util/Accumulator.js, lara/util/Checkpoint.lara, lara/util/CodeInserter.lara, lara/util/Combinations.lara, lara/util/DataStore.lara, lara/util/IdGenerator.lara, lara/util/JpFilter.lara, lara/util/LineInserter.lara, lara/util/LocalFolder.lara, lara/util/PredefinedStrings.lara, lara/util/PrintOnce.lara, lara/util/ProcessExecutor.lara, lara/util/Replacer.lara, lara/util/SequentialCombinations.lara, lara/util/StringSet.lara, lara/util/TimeUnits.lara, lara/util/TupleId.lara, lara/code/EnergyBase.lara, lara/code/LoggerBase.lara, lara/code/TimerBase.lara, lara/CompilationBase.lara, weaver/util/WeaverDataStore.lara, weaver/Ast.lara, weaver/JoinPointsBase.lara, weaver/Query.lara, weaver/Selector.lara, weaver/Weaver.lara, weaver/WeaverJps.lara, weaver/WeaverLauncherBase.lara, weaver/WeaverOptions.lara, weaver/jp/JoinPoint.lara, weaver/jp/CommonJoinPointsBase.lara, weaver/jp/JoinPointIndex.lara, weaver/jp/JoinPointsCommonPath.lara, weaver/jp/ProgramJp.lara, weaver/jp/FileJp.lara, weaver/jp/StmtJp.lara, weaver/jp/DeclJp.lara, weaver/jp/ClassJp.lara, weaver/jp/FunctionJp.lara, weaver/jp/MethodJp.lara, weaver/jp/ConstructorJp.lara, weaver/jp/FieldJp.lara, weaver/jp/ExprJp.lara, weaver/jp/CallJp.lara, weaver/jp/MemberCallJp.lara, weaver/jp/ConstructorCallJp.lara, weaver/jp/VarRefJp.lara, weaver/jp/FieldRefJp.lara, weaver/jp/VarDeclJp.lara, weaver/jp/ParamJp.lara, weaver/jp/TypeJp.lara, weaver/jp/IfJp.lara, weaver/jp/SwitchJp.lara, weaver/jp/CaseJp.lara, weaver/jp/LoopJp.lara, weaver/jp/TernaryJp.lara, weaver/jp/BinaryJp.lara, weaver/jp/TryJp.lara, weaver/jp/CatchJp.lara, weaver/jp/ThrowJp.lara, weaver/jp/DefaultJp.lara, weaver/jp/BreakJp.lara, weaver/jp/ContinueJp.lara, weaver/jp/GotoJp.lara, weaver/jp/ThenJp.lara, weaver/jp/ElseJp.lara, weaver/jp/LambdaJp.lara, lara/MathExtra.lara, lcl/LaraCommonLanguage.lara, lcl/metrics/Metric.lara, lcl/metrics/Metrics.lara, lcl/metrics/ck/CBO.lara, lcl/metrics/ck/DIT.lara, lcl/metrics/ck/LCOM94.lara, lcl/metrics/ck/NOC.lara, lcl/metrics/ck/RFC.lara, lcl/metrics/ck/WMC.lara, lcl/metrics/ck/CKMetricsIndex.lara, lcl/metrics/lh/DAC.lara, lcl/metrics/lh/MPC.lara, lcl/metrics/lh/NOM.lara, lcl/metrics/lh/SIZE1.lara, lcl/metrics/lh/SIZE2.lara, lcl/metrics/lh/LHMetricsIndex.lara, lcl/metrics/om/CogniComplex.lara, lcl/metrics/om/CycloComplex.lara, lcl/metrics/om/LOC.lara, lcl/metrics/om/NOCl.lara, lcl/metrics/om/NOFi.lara, lcl/metrics/om/NOFu.lara, lcl/metrics/om/NOL.lara, lcl/metrics/om/OtherMetricsIndex.lara, lcl/ml/Code2Vec.js, clava/lara/benchmark/ClavaBenchmarkInstance.lara, clava/lara/code/Logger.lara, clava/lara/code/Energy.lara, clava/lara/code/Timer.lara, clava/lara/Compilation.lara, clava/weaver/jp/ClavaElseJp.lara, clava/weaver/jp/ClavaFileJp.lara, clava/weaver/jp/ClavaLoopJp.lara, clava/weaver/jp/ClavaIfJp.lara, clava/weaver/jp/ClavaBinaryJp.lara, clava/weaver/jp/ClavaConstructorCallJp.lara, clava/weaver/jp/ClavaConstructorJp.lara, clava/weaver/jp/ClavaParamJp.lara, clava/weaver/jp/ClavaVarRefJp.lara, clava/weaver/jp/ClavaVarDeclJp.lara, clava/weaver/jp/ClavaTypeJp.lara, clava/weaver/jp/ClavaFieldRefJp.lara, clava/weaver/jp/ClavaFieldJp.lara, clava/weaver/jp/ClavaMemberCallJp.lara, clava/weaver/jp/ClavaCallJp.lara, clava/weaver/jp/ClavaFunctionJp.lara, clava/weaver/jp/ClavaMethodJp.lara, clava/weaver/jp/ClavaClassJp.lara, clava/weaver/jp/ClavaJoinPoint.lara, clava/weaver/jp/CommonJoinPoints.lara, clava/weaver/JoinPoints.lara, clava/weaver/WeaverLauncher.lara, clava/clava/autopar/additionalConditionsCheck.lara, clava/clava/autopar/AddOpenMPDirectivesForLoop.lara, clava/clava/autopar/AddPragmaLoopIndex.lara, clava/clava/autopar/AutoParStats.lara, clava/clava/autopar/AutoParUtils.lara, clava/clava/autopar/BuildPetitFileInput.lara, clava/clava/autopar/checkForFunctionCalls.lara, clava/clava/autopar/checkForInvalidStmts.lara, clava/clava/autopar/checkForOpenMPCanonicalForm.lara, clava/clava/autopar/CheckForSafeFunctionCall.lara, clava/clava/autopar/checkvarreReduction.lara, clava/clava/autopar/ExecPetitDependencyTest.lara, clava/clava/autopar/FindReductionArrays.lara, clava/clava/autopar/get_varTypeAccess.lara, clava/clava/autopar/InlineFunctionCalls.lara, clava/clava/autopar/LoopInductionVariables.lara, clava/clava/autopar/NormalizedBinaryOp.lara, clava/clava/autopar/OmegaConfig.lara, clava/clava/autopar/Parallelize.lara, clava/clava/autopar/ParallelizeLoop.lara, clava/clava/autopar/RemoveNakedloops.lara, clava/clava/autopar/RemoveOpenMPfromInnerloop.lara, clava/clava/autopar/RunInlineFunctionCalls.lara, clava/clava/autopar/SetArrayAccessOpenMPscoping.lara, clava/clava/autopar/SetMemberAccessOpenMPscoping.lara, clava/clava/autopar/SetVariableAccess.lara, clava/clava/autopar/SetVarrefOpenMPscoping.lara, clava/clava/analysis/analysers/BoundsAnalyser.lara, clava/clava/analysis/analysers/BoundsResult.lara, clava/clava/analysis/analysers/DoubleFreeAnalyser.lara, clava/clava/analysis/analysers/DoubleFreeResult.lara, clava/clava/analysis/checkers/ChgrpChecker.lara, clava/clava/analysis/checkers/ChmodChecker.lara, clava/clava/analysis/checkers/ChownChecker.lara, clava/clava/analysis/checkers/CinChecker.lara, clava/clava/analysis/checkers/ExecChecker.lara, clava/clava/analysis/checkers/FprintfChecker.lara, clava/clava/analysis/checkers/FscanfChecker.lara, clava/clava/analysis/checkers/GetsChecker.lara, clava/clava/analysis/checkers/LambdaChecker.lara, clava/clava/analysis/checkers/MemcpyChecker.lara, clava/clava/analysis/checkers/PrintfChecker.lara, clava/clava/analysis/checkers/ScanfChecker.lara, clava/clava/analysis/checkers/SprintfChecker.lara, clava/clava/analysis/checkers/StrcatChecker.lara, clava/clava/analysis/checkers/StrcpyChecker.lara, clava/clava/analysis/checkers/SyslogChecker.lara, clava/clava/analysis/checkers/SystemChecker.lara, clava/clava/code/GlobalVariable.lara, clava/clava/code/StatementDecomposer.lara, clava/clava/code/StatementDecomposer.js, clava/clava/code/DecomposeResult.js, clava/clava/gprofer/Gprofer.lara, clava/clava/gprofer/_GproferAspects.lara, clava/clava/hdf5/Hdf5.lara, clava/clava/hls/HLSAnalysis.lara, clava/clava/hls/TraceInstrumentation.lara, clava/clava/hls/MathAnalysis.lara, clava/clava/hls/MathHInfo.lara, clava/clava/mpi/MpiAccessPattern.lara, clava/clava/mpi/MpiScatterGatherLoop.lara, clava/clava/mpi/MpiUtils.lara, clava/clava/mpi/patterns/IterationVariablePattern.lara, clava/clava/mpi/patterns/MpiAccessPatterns.lara, clava/clava/mpi/patterns/ScalarPattern.lara, clava/clava/opencl/OpenCLCall.lara, clava/clava/opencl/OpenCLCallVariables.lara, clava/clava/opencl/KernelReplacer.lara, clava/clava/opencl/KernelReplacerAuto.lara, clava/clava/parser/BatchParser.lara, clava/clava/pass/DecomposeDeclStmt.js, clava/clava/pass/DecomposeVarDeclarations.js, clava/clava/pass/SingleReturnFunction.js, clava/clava/stats/OpsBlock.lara, clava/clava/stats/OpsCost.lara, clava/clava/stats/OpsCounter.lara, clava/clava/stats/StaticOpsCounter.lara, clava/clava/memoi/MemoiProf.lara, clava/clava/memoi/MemoiGen.lara, clava/clava/memoi/_MemoiGenHelper.lara, clava/clava/memoi/MemoiTarget.lara, clava/clava/memoi/MemoiUtils.lara, clava/clava/memoi/MemoiAnalysis.lara, clava/clava/util/ClavaDataStore.lara, clava/clava/util/FileIterator.lara, clava/clava/util/SingleFile.lara, clava/clava/uve/UVE.lara, clava/clava/uve/DetectStream.lara, clava/clava/_ClavaJavaTypes.lara, clava/clava/Clava.lara, clava/clava/ClavaAspects.lara, clava/clava/ClavaCode.lara, clava/clava/ClavaJoinPoints.js, clava/clava/ClavaType.lara, clava/antarex/_Test.lara, clava/antarex/examon/Examon.lara, clava/antarex/examon/ExamonAspects.lara, clava/antarex/inline/inlineAspects.lara, clava/antarex/inline/inlineFuncs.lara, clava/antarex/libvc/LibVC.lara, clava/antarex/libvc/_internal/LibVCAspects.lara, clava/antarex/margot/codegen/MargotCodeGen.lara, clava/antarex/margot/codegen/_internal/MargotCodeGenAspects.lara, clava/antarex/margot/codegen/_internal/MargotStringsGen.lara, clava/antarex/margot/config/MargotBlock.lara, clava/antarex/margot/config/MargotConfig.lara, clava/antarex/margot/config/MargotDataFeature.lara, clava/antarex/margot/config/MargotEnergyDomain.lara, clava/antarex/margot/config/MargotKnob.lara, clava/antarex/margot/config/MargotState.lara, clava/antarex/margot/config/monitor/MargotCustomMonitor.lara, clava/antarex/margot/config/monitor/MargotEnergyMonitor.lara, clava/antarex/margot/config/monitor/MargotMonitor.lara, clava/antarex/margot/config/monitor/MargotThroughputMonitor.lara, clava/antarex/margot/config/monitor/MargotTimeMonitor.lara, clava/antarex/margot/dse/MargotDseInfo.lara, clava/antarex/margot/dse/metric/MargotMetric.lara, clava/antarex/memoi/Memoization.lara, clava/antarex/memoi/MemoizationAutoAspects.lara, clava/antarex/memoi/MemoizationAutoFuncs.lara, clava/antarex/memoi/MemoizationC.lara, clava/antarex/memoi/MemoizationCXX.lara, clava/antarex/memoi/MemoizationLibFuncs.lara, clava/antarex/memoi/MemoizationMath.lara, clava/antarex/multi/MultiVersionPointers.lara, clava/antarex/multi/MultiVersionPointersAspects.lara, clava/antarex/precision/CustomPrecision.lara, clava/antarex/precision/CustomPrecisionFunc.lara, clava/antarex/precision/rewTypes.lara, clava/antarex/precision/rewTypesFunc.lara, clava/antarex/split/extractCodeAspects.lara, clava/antarex/split/extractCodeFuncs.lara, clava/antarex/split/splitDeclarations.lara, clava/antarex/split/splitLoopAspects.lara, clava/antarex/split/splitLoopFuncs.lara, clava/antarex/utils/IdentReferences.lara, clava/antarex/utils/lowLevelFuncs.lara, clava/antarex/utils/mangling.lara, clava/antarex/utils/messages.lara, clava/antarex/utils/sysfile.lara] Running on: Linux Reading: /home/caubert/Downloads/clava/AutoPar.lara Parse Successful! -==================================================-
  4. Organizing Aspects -==================================================- Organized! -==================================================-
  5. Creating Aspect-IR -==================================================- Created! Processed 47 tokens from the LARA file. -==================================================-
  6. . Loading Aspect-IR -==================================================- -==================================================-
  7. Interpreting Aspects -==================================================- -==================================================- Elapsed Time: 1211ms -==================================================- -==================================================-
  8. Executing Main Aspect -==================================================- -==================================================- Elapsed Time: 186ms -==================================================- -==================================================- LARA total time: 4325ms -==================================================-

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!

aubertc commented 2 years ago

So, actually, I believe I have to either

Is this correct? I am sorry but I could not find the documentation to use an "off-the-shelf" .lara file.

Thanks!

joaobispo commented 2 years ago

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

aubertc commented 2 years ago

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
aubertc commented 2 years ago

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!

joaobispo commented 2 years ago

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):

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:

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).

aubertc commented 2 years ago

Thanks a lot, that's a great level of support :-)

A couple of comments:

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 ;-)

 // 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?

aubertc commented 2 years ago

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
joaobispo commented 2 years ago

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.

aubertc commented 2 years ago

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?

joaobispo commented 2 years ago

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);
   }   
}
aubertc commented 2 years ago

Thanks a lot, I'll look at it soon and get back to you when I have tried it.

aubertc commented 2 years ago

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 :-)