Skip to content

Separate OpenMP from Pyccel's core functionalities and connect it as a Plugin#2338

Open
rmahjoubi wants to merge 186 commits intodevelfrom
rewrite-omp
Open

Separate OpenMP from Pyccel's core functionalities and connect it as a Plugin#2338
rmahjoubi wants to merge 186 commits intodevelfrom
rewrite-omp

Conversation

@rmahjoubi
Copy link
Copy Markdown
Member

This PR reintroduces OpenMP in Pyccel as a standalone plugin, interfacing with Pyccel via a plugins utility.

Plugins Utility

The plugins module provides the basic classes from which every plugin should inherit, and it's the main interface to the plugins from Pyccel.

Core Functionality

  • Via the plugins module, a Pyccel class instance can register itself to be patched with the plugin's functionalities, then each plugin picks its targets from the registered objects
  • Currently, the plugins are loaded and used in no particular order; when a plugin fails to load, a warning is raised and the loader resumes with the rest
  • When an object registers itself with the plugins, every plugin that is targeting the object will patch it in the order the loading happened
  • When an object unregisters itself from the plugins, every plugin that is targeting the object undoes its patches in the order the loading happened
  • Some plugins may need to change their behavior after set_options is called; for the changes to take place, set_options should be called with refresh set to True

OpenMP Plugin

Plugin Behavior

  • The plugin keeps track of any applied versions and only applies other versions when specified in the options; any applied version persists until the unregister method is called

Classes

  • Treating TextX objects is done in the syntactic stage via classes that inherit from OmpTxNode, which itself inherits from OmpNode; visiting these classes results in instances of their respective classes that inherit from OmpNode
  • Each OpenMP version has dedicated syntactic/semantic parsers and printers
  • Printers use the raw statement of an OpenMP object provided in the comment; the segmentation of these statements allows for the suppression or tweaking of printing of segments correlated to the desired OpenMP object

the support for exit is limited to calls with integral arguments
or without arguments (same as exit(0))
Replace every class in the ast/omp.py with new classes
the new classes have the same name as the textx grammar rules
because these classes are used as the base classes for the textx
instead of the ones found in pyccel/parser/syntax/openmp.py
the version field will be used to store the version of the omp grammer
used for a Construct/Clause
this is done by making the grammer sets a version field for the Clause/Construct if there are multile versions of the grammer
the grammer is not finished an only supports parallel constructs and its clauses
instead of hardcoding the rules in the syntactic/semantic/printing stages we just delegate the work to the omp class new functions
there will be 5 functions _visit_syntatic, _visit_semantic, _cprint, _fprint, _pprint
those functions will be called from the syntactic/semantic/printing stages
and the omp class will be responsible for checking the if everything is corrent and provide the correct printing
this way we can support multiple version of omp withouth having to
duplicate the code and just use inheritance and override the methods
to change the behavior of the previous version
- add a version setter for the OmpAnnotatedComment class to be able to check if the syntax is supported by the version of omp
- fixing liter errors
@rmahjoubi
Copy link
Copy Markdown
Member Author

/bot run linux intel macosx windows

@rmahjoubi
Copy link
Copy Markdown
Member Author

/bot run linux

@EmilyBourne EmilyBourne marked this pull request as ready for review July 24, 2025 19:31
@pyccel-bot
Copy link
Copy Markdown

pyccel-bot bot commented Jul 24, 2025

I can't seem to find your checklist to confirm that you have completed all necessary tasks. Please request one using /bot checklist.

@github-actions github-actions bot marked this pull request as draft July 24, 2025 19:32
@rmahjoubi
Copy link
Copy Markdown
Member Author

/bot run intel macosx windows

@rmahjoubi
Copy link
Copy Markdown
Member Author

/bot run coverage

Copy link
Copy Markdown

@pyccel-bot pyccel-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job ! Your PR is using all the code it added/changed.

@rmahjoubi
Copy link
Copy Markdown
Member Author

rmahjoubi commented Jul 24, 2025

Here is your checklist. Please tick items off when you have completed them or determined that they are not necessary for this pull request:

  • Write a clear PR description
  • Add tests to check your code works as expected
  • Update documentation if necessary
  • Update Changelog
  • Ensure any relevant issues are linked
  • Ensure new tests are passing
  • Update AUTHORS file

@rmahjoubi rmahjoubi marked this pull request as ready for review July 24, 2025 23:08
@rmahjoubi rmahjoubi requested a review from EmilyBourne July 24, 2025 23:21
Copy link
Copy Markdown

@pyccel-bot pyccel-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job ! Your PR is using all the code it added/changed.

@github-actions github-actions bot marked this pull request as draft July 25, 2025 10:11
@rmahjoubi rmahjoubi marked this pull request as ready for review July 25, 2025 16:02
Copy link
Copy Markdown

@pyccel-bot pyccel-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job ! Your PR is using all the code it added/changed.

@EmilyBourne
Copy link
Copy Markdown
Member

@rmahjoubi
image

@rmahjoubi
Copy link
Copy Markdown
Member Author

image

@EmilyBourne I'm not sure about this error, as original_method is an argument to the constructor of the OmpPatchInfo class. I think this might disappear if we run the Codacy tests again.

@rmahjoubi
Copy link
Copy Markdown
Member Author

/bot run linux

Copy link
Copy Markdown
Member

@EmilyBourne EmilyBourne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think there is anyway to split this PR? It really is enormous and quite hard to review. I would love to split it into a Plugin part and an OpenMP part but I guess that would be tricky for testing? Could we have fake plugin for the tests in tests/plugin to get round this?

Comment thread developer_docs/plugins.md

## Overview

The Pyccel plugin system allows Pyccel's functionality to be extended through plugins. Plugins can modify the behaviour of existing classes by patching their methods or adding new methods. This is particularly useful for adding support for new language features, optimisations, or code generation targets without modifying the core codebase.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plugins can modify the behaviour of existing classes by patching their methods or adding new methods

Is this true for all classes or only certain classes (SyntaxParser, SemanticParser, Codegen) ?

Comment thread developer_docs/plugins.md

1. `register(instances)` - Register instances with the plugin. This method should apply patches to the provided instances.
2. `refresh()` - Refresh all registered targets. This method should reapply existing patches to registered targets and apply any new patches, if necessary.
3. `deregister(instances)` - Deregister instances from the plugin. This method should remove all patches applied to the provided instances.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you had decided to remove the deregister functionality given that new class instances are created when we run Pyccel anyway?

Comment thread developer_docs/plugins.md
1. `register(instances)` - Register instances with the plugin. This method should apply patches to the provided instances.
2. `refresh()` - Refresh all registered targets. This method should reapply existing patches to registered targets and apply any new patches, if necessary.
3. `deregister(instances)` - Deregister instances from the plugin. This method should remove all patches applied to the provided instances.
4. `set_options(options)` - Set options for the plugin. This method should update the plugin's behaviour based on the provided options.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there also be a get_options method? Maybe get_options_kwargs and get_parser_options to handle options passed via epyccel or pyccel?

Comment thread developer_docs/plugins.md
Comment on lines +103 to +105
def load_plugins(self, plugins_dir=None):
"""Discover and load all plugins from the plugins directory."""
# ...
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you timed this? What exactly is loaded here? Will it result in the grammar for all OpenMP versions being calculated? The call to redbaron is usually quite costly so if we can avoid it we probably should

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is plugins_dir pyccel/plugins/MyPlugin/ or pyccel/plugins/?

Comment thread developer_docs/plugins.md
Comment on lines +149 to +168
def register(self, registry):
"""Apply patches to the target."""
target = registry.target

# Example: Patch the 'parse' method
original_method = getattr(target, 'parse', None)

def parse(self, *args, **kwargs):
# Do something before the original method
print("Before parsing")

# Call the original method
result = original_method(self, *args, **kwargs)

# Do something after the original method
print("After parsing")

return result

# Apply the patch
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Maybe add a comment stating that functions should usually be defined in the module not the function otherwise people are likely to take this as the best practice example

OmpTxIntegerExpr: value=InnerContent | ParenthesisContent;
OmpTxConstantPositiveInteger: value=/[0-9]+/;
OmpTxList: throw_away+=ID[','];
ParenthesizedExpression: (('(' ParenthesizedExpression ')') | /[^()]*/)*; // TODO: find a better way to do this as this will not escape the parenthesis inside of a string
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate more on this TODO? Maybe I can help? Usually .tx files are designed to handle parsing in a way that is more explicit than regexes to avoid this kind of issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you are just missing something that matches a string?

OmpTxList: throw_away+=ID[','];
ParenthesizedExpression: (('(' ParenthesizedExpression ')') | /[^()]*/)*; // TODO: find a better way to do this as this will not escape the parenthesis inside of a string
DataSharingAttribute: ('shared' | 'none' | 'private' | 'firstprivate');
ReductionOperator: ('+' | '-' | '*' | '&' | '|' | '^' | '&&' | '||' | 'min' | 'max'); // TODO: those are only the implicitly declared ones for C and C++. Add the others for Fortran and support user-defined ones (see specs https://www.openmp.org/spec-html/5.0/openmpsu107.html#x140-581002)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgotten TODO

Comment thread pyccel/plugins/Openmp/omp.py
Comment on lines +80 to +82
position : tuple
The start and end positions of the OpenMP syntax in the source code,
used to print errors.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Please add a comment about this

Comment thread pyccel/plugins/Openmp/plugin.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants