Skip to content

Coding Standards

Joshua Hoke Davis edited this page Jan 23, 2020 · 2 revisions

Here we describe the conventions we should follow for all test cases. Please follow these rules for each of the different elements when coding. We borrow heavily from LLVM coding standards and adapt it to our necessities. This document is still under construction and it might change according to our necessities should they be different in the future.

Folder structure

In the repository we are following the folder structure of LLVM, this way it will be easier to integrate the test with the llvm main trunk. Since we plan to test the offloading capabilities of OpenMP 4.5, all our test cases are within /libomptarget/test/offloading. Inside, there is a folder per OpenMP directive, and within each folder as many tests as necessary, respecting the naming convention.

Test cases filenames

Filenames should all start with test_ follow by the main directive, follow by other possible directives or clauses that are used and are important for the test, follow by a short description of the test. There should be no spaces in the filename, instead spaces should be replaced by underscores (_). For example, the file test_target_data_if.c is the source code for a test that uses the target data construct and test the if clause.

File headers

All files should contain a header similar to the following header. This header should be located after the // RUN:... commands. It should contain a description of what the test does, what is the version of OpenMP we are using and which API standard we are using, the name of the file, and a more descriptive title.

#!C
//===-- test_target_data_map.c - test of the map clause in target data ----===//
// 
// OpenMP API Version 4.5 Nov 2015
// 
// This file is a test for the target data construct when used with the map
// clause. This clause should create the mapping of variables into the device
// and do the data movement or allocation depending on the map type modifier
// from, to, fromto and alloc. This test has a function for each of this type
// modifier. This test uses arrays of size N which values are modified in the 
// device and tested in the host. Creation and data movement of the data inside 
// the array is according to the used type modifier.
//
//===----------------------------------------------------------------------===//

Includes

After the header, all necessary includes should be grouped together. The order of these includes should be:

  1. Main module header file
  2. Local or private headers files
  3. other third party libraries
  4. OpenMP library
  5. System and standard C/C++ libraries.

It is fine to group different includes together by separating them from the first block.

Here is an example:

#!C
#include "applicationInclude.h"
#include <mkl.h>
#include <omp.h>
#include <stdlib>
#include <stdio>

Comments

  • Prefer the use of C++ style comments // ...
  • Every OpenMP structured block should have comments at the closing bracket explaining which OpenMP sectio it is closing, like this:
#!C
#pragma omp target data map(from : h_array_h[0 : N])  \
    map(from : h_array_s[0 : N])                      \
    map(from : isHost)
  {
#pragma omp target
    {

    } /*end target*/
  } /*end target data*/
  • Create a comment before function explaining the purpose of this function. Don't leave any spaces between the comment and the function.
#!C
// Test for OpenMP 4.5 target data map(from: )
int test_map_from() { 
}

Indentation

  • We use spaces for indentation. Avoid tabs
  • Use (2) two spaces inside code blocks. For example:
#!C
int function (int a) {
  int a;
  int b; 
  {
    int c = a + b;
    printf("c = %d\n",c);
  }
}

Spaces before parenthesis, in function parameters list, and others.

  • A space should be used before a parenthesis when used in any control flow statement (e.g. if, for and while). However, avoid using spaces when calling a function. Use a space between the closing parenthesis and the opening bracket of the code section.
  • In a function list, use spaces after each comma, when declaring the function and also when calling it. If there is only a single parameter, do not add any space
  • Use spaces around (+) and (-) arithmetic operators, assignment operators and logical operators. Don't use spaces around (*) and (/) arithmetic operators or when using pre and post increment operators.

Here is an example:

#!C
int myFunction(int a, int b) {
  int c = 3;
  int d;

  d = myOtherFunc(a, b, c);
  if (c > d) {
    return a;
  } else if (d < a && c == 3) {
    printf("here is a test\n");
    return a*b + c;
  }
  return 0;
}

OpenMP formatting

Here we discuss formatting that is OpenMP specific.

Pragma location

The openmp pragma should have no indentation. It should start at the beginning of the line. If the #pragma omp line is too long, it can be split by using \ at the end of the line and continuing in the following line. in this case, you should leave 8 spaces starting the following lines. This way the new line should align with the previous line start after the #pragma compiler clause. If you use more than two lines make sure that the \ at the end of the line are aligned

#!C
#pragma omp target data if(size > SIZE_THRESHOLD) map(to: size)  \
        map(tofrom: c[0:size])                                   \
        map(to: a[0:size], b[0:size], i)

clauses with arguments

If your clause takes arguments (e.g. map and if). You should leave no space between the clause and the parenthesis. For example: map(...) or if(...).

map clause. modifier and sizes

  • When using the map clause, if you are including a map-type-modifier (e.g. to, from and tofrom), do not have any space between the modifier and the colon. But leave one space after the colon.
  • When specifying an array size. leave no space between the array name and its brackets, and leave no space around the colon.
  • Multiple arguments should be coma separated with the same rule as for function arguments.

For example:

#!C
#pragma omp target data map(tofrom: array[0:N], array2, array3[:4])

Template for test

#!C

// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu

//===-- test_target_data_map.c - test of the map clause in target data ----===//
// 
// OpenMP API Version 4.5 Nov 2015
// 
// This file is a test for the target data construct when used with the map
// clause. This clause should create the mapping of variables into the device
// and do the data movement or allocation depending on the map type modifier
// from, to, fromto and alloc. This test has a function for each of this type
// modifier. This test uses arrays of size N which values are modified in the 
// device and tested in the host. Creation and data movement of the data inside 
// the array is according to the used type modifier.
//
//===----------------------------------------------------------------------===//

#include <omp.h>
#include <stdio.h>

// Test for OpenMP 4.5 target data map(from: )
int test_map_from() {
  printf("test_map_from\n");

  int sum = 0, sum2 = 0, errors = 0, isHost = 0;

  // host arrays: heap and stack
  int *h_array_h = (int *)malloc(N*sizeof(int));
  int h_array_s[N];

#pragma omp target data map(from : h_array_h[0 : N])  \
    map(from : h_array_s[0 : N])                      \
    map(from : isHost)
  {
#pragma omp target
    {
      isHost = omp_is_initial_device();
      for (int i = 0; i < N; ++i) {
        h_array_h[i] = 1;
        h_array_s[i] = 2;
      }
    } // end target
  } // end target data

  // checking results
  for (int i = 0; i < N; ++i) {
    sum += h_array_h[i];
    sum2 += h_array_s[i];
  }
  
  free(h_array_h);
  errors = (N != sum) || (2*N != sum2);
  if (!errors)
    printf("Test passed on %s\n", (isHost ? "host" : "device"));
  else
    printf("Test failed on %s: sum=%d, sum2=%d, N=%d\n", (isHost ? "host" : "device"), sum, sum2, N);

  return errors;
}