OpenMP support

From Free Pascal wiki
Revision as of 10:31, 26 July 2006 by Vincent (talk | contribs) (added nested procedure syntax)

What is OpenMP?

OpenMP is an API accessed by language directives to do multi threaded programming, see also http://www.openmp.org. Currently, there is only OpenMP syntax defined for C and Fortran. This page tries to collect some stuff to settle down pascal syntax for it.

Pascal syntax for OpenMP

Proposal 1

Foreword

At first, I must admit that some parts of the OpenMP specification I still don't understand. They did a terrible good job throwing away all common terms ever used in multi threading context, and invented their own ones.

Syntax vs. Compiler directives

OpenMP for C and C++ is implemented by using compiler directives mainly due to the reasons of source code compatibility (or: standards compliance). So a conforming program is intended to behave the same regardless if the actual compiler compiling the program supports those special pragmas or not.

For FreePascal I don't think this is the way to go, because first it changes comments into code and second, it makes the program far less readable. For C programs this doesn't seem to be an issue, if you get my meaning. But in my opinion, readability is a far more important issue than compatibility to older/different compilers. If all else fails, a preprocessor could be provided to strip out the parallel specific stuff, as has been suggested by Marco.

Well, enough talk, I start with the easier directives which are luckily the more fundamental ones.

parallel

The parallel construct can only be used for a structured block. That means in Pascal it should be enclosed in some sort of begin/end pair anyway. So with this in mind, even the clauses that go with the original parallel construct could possibly be supported in a clean and structured way. So if you take a look at the A.4.1.c example of the OpenMP 2.5 specification, the Pascal version could look like this:

  procedure SubDomain (var x       : array of Float;
                           istart  : Integer;
                           ipoints : Integer)
  var
     i : Integer;
  begin
     for i := 0 to ipoints - 1 do
        x[istart + i] := 123.456;
  end {SubDomain};
  
  procedure Sub (var x : array of Float);
  // Variables declared here should have shared context.
  // This would include the function's parameters then...
  begin
     parallel
        // Variables declared here have private context.
        iam     : Integer;
        nt      : Integer;
        ipoints : Integer;
     begin // of parallel section
        iam := OMP.Get_Thread_Num;  // OMP library calls.
        nt  := OMP.Get_Num_Threads;
        
        ipoints := Length (x) div nt; // size of partition
        istart  := iam * ipoints;     // starting array index
        
        if iam = Pred (nt) then
           ipoints := Length (x) - istart; // last thread may do more
        
        SubDomain (x, istart, ipoints);
     end {parallel};
  end {Sub};
  
  var
     arr = array[0 .. 9999] of Float;
  begin  // Main program
     Sub (arr);
  end.

I don't like the idea of declaring variables inside the actual statments, this looks very unpascalish. Maybe we can find a way around it. --FPK 10:22, 26 July 2006 (CEST)

I agree with Florian that this is not the way to go. Why not require all parallelizable code to be in local functions ? After all, that's almost what you are doing: declaring a local function. That would be a simple extension of the current syntax. You have access to all local variables; all you'd need is to add a parallel keyword to the local function declaration.

More constructs

To be continued...

V.hoefler


Proposal 2: Using local functions

Instead of using new block types (like parallel), it uses a nested procedure, with the parallel modifier.

parallel

  procedure SubDomain (var x       : array of Float;
                           istart  : Integer;
                           ipoints : Integer); 
  var
     i : Integer;
  begin
     for i := 0 to ipoints - 1 do
        x[istart + i] := 123.456;
  end {SubDomain};
  
  procedure Sub (var x : array of Float);
  // Variables declared here should have shared context.
  // This would include the function's parameters then...
    procedure ParallelBlock; parallel;
    var     
        iam     : Integer;
        nt      : Integer;
        ipoints : Integer;
    begin
         iam := OMP.Get_Thread_Num;  // OMP library calls.
         nt  := OMP.Get_Num_Threads;
         
         ipoints := Length (x) div nt; // size of partition
         istart  := iam * ipoints;     // starting array index
         
         if iam = Pred (nt) then
            ipoints := Length (x) - istart; // last thread may do more
        
         SubDomain (x, istart, ipoints);
    end;

  begin
       ParallelBlock;
  end {Sub};
  
  var
     arr = array[0 .. 9999] of Float;
  begin  // Main program
     Sub (arr);
  end.


Proposal 3

<not yet done>