blob: 89555e537facaf66b4147cf878ff62355ea33e35 [file] [edit]
// Stress the kernel launch environment (KLE) of concurrent launches.
//
// A cross-team reduction gives the launch a KLE, which carries that launch's
// own reduction buffer. The KLE is copied to the device synchronously, which the
// plugin may do by storing it in place where device memory is host-writable.
// Either has to hold up when launches overlap: every launch needs its own KLE,
// and a launch's KLE has to be visible to the device before its kernel runs
// and stay intact until it finishes. Otherwise a launch reduces into another
// launch's buffer, or reads a KLE that has not landed yet. Every launch here
// accumulates a distinct value, so either shows up as a wrong sum.
//
// RUN: %libomptarget-compile-generic -fopenmp-offload-mandatory
// RUN: %libomptarget-run-generic
// RUN: %libomptarget-compileopt-generic -fopenmp-offload-mandatory
// RUN: %libomptarget-run-generic
// RUN: rm -rf %t.rr && mkdir -p %t.rr
// RUN: env LIBOMPTARGET_RECORD=1 LIBOMPTARGET_RECORD_DIR=%t.rr \
// RUN: %libomptarget-run-generic
//
// REQUIRES: gpu
// UNSUPPORTED: intelgpu
#include <omp.h>
#include <stdio.h>
#define NUM_LAUNCHES 32
#define N 4096
// Launch k accumulates k + 1 per element.
static long expected(int k) { return (long)(k + 1) * N; }
static int check(const char *Phase, long *Results) {
int Errors = 0;
for (int k = 0; k < NUM_LAUNCHES; k++)
if (Results[k] != expected(k)) {
fprintf(stderr, "%s: launch %d reduced to %ld, expected %ld\n", Phase, k,
Results[k], expected(k));
Errors++;
}
return Errors;
}
int main(void) {
static long Results[NUM_LAUNCHES];
int Errors = 0;
// Launches issued back to back without an intervening synchronization, so
// that several launches are in flight at once.
for (int k = 0; k < NUM_LAUNCHES; k++) {
Results[k] = 0;
#pragma omp target teams distribute parallel for map(tofrom : Results[k : 1]) \
reduction(+ : Results[k]) firstprivate(k) nowait
for (int i = 0; i < N; i++)
Results[k] += k + 1;
}
#pragma omp taskwait
Errors += check("nowait", Results);
// Same, but with the launches and the synchronizations spread over several
// host threads: a thread finalizing its queue must not disturb the launch
// environment of a launch another thread still has in flight.
#pragma omp parallel for num_threads(8)
for (int k = 0; k < NUM_LAUNCHES; k++) {
long Sum = 0;
#pragma omp target teams distribute parallel for map(tofrom : Sum) \
reduction(+ : Sum) firstprivate(k)
for (int i = 0; i < N; i++)
Sum += k + 1;
Results[k] = Sum;
}
Errors += check("threaded", Results);
if (Errors)
return 1;
printf("PASS\n");
return 0;
}