2014-05-11 01:02:09 +08:00
|
|
|
<ompts:test>
|
|
|
|
<ompts:testdescription>Test which checks the guided option of the omp for schedule directive.</ompts:testdescription>
|
|
|
|
<ompts:ompversion>2.0</ompts:ompversion>
|
|
|
|
<ompts:directive>omp for schedule(guided)</ompts:directive>
|
|
|
|
<ompts:dependences>omp flush,omp for nowait,omp critical,omp single</ompts:dependences>
|
|
|
|
<ompts:testcode>
|
|
|
|
/* Test for guided scheduling
|
|
|
|
* Ensure threads get chunks interleavely first
|
|
|
|
* Then judge the chunk sizes are decreasing to a stable value
|
|
|
|
* Modified by Chunhua Liao
|
|
|
|
* For example, 100 iteration on 2 threads, chunksize 7
|
|
|
|
* one line for each dispatch, 0/1 means thread id
|
|
|
|
* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24
|
|
|
|
* 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 18
|
|
|
|
* 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14
|
|
|
|
* 1 1 1 1 1 1 1 1 1 1 10
|
|
|
|
* 0 0 0 0 0 0 0 0 8
|
|
|
|
* 1 1 1 1 1 1 1 7
|
|
|
|
* 0 0 0 0 0 0 0 7
|
|
|
|
* 1 1 1 1 1 1 1 7
|
|
|
|
* 0 0 0 0 0 5
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "omp_testsuite.h"
|
|
|
|
#include "omp_my_sleep.h"
|
|
|
|
|
|
|
|
#define NUMBER_OF_THREADS 10
|
|
|
|
#define CFSMAX_SIZE 1000
|
|
|
|
#define MAX_TIME 0.005
|
|
|
|
|
|
|
|
#ifdef SLEEPTIME
|
|
|
|
#undef SLEEPTIME
|
|
|
|
#define SLEEPTIME 0.0001
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int <ompts:testcode:functionname>omp_for_schedule_guided</ompts:testcode:functionname> (FILE * logFile)
|
|
|
|
{
|
|
|
|
<ompts:orphan:vars>
|
|
|
|
int * tids;
|
|
|
|
int * chunksizes;
|
|
|
|
int notout;
|
|
|
|
int maxiter;
|
|
|
|
</ompts:orphan:vars>
|
|
|
|
|
|
|
|
int threads;
|
|
|
|
int i;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
tids = (int *) malloc (sizeof (int) * (CFSMAX_SIZE + 1));
|
|
|
|
maxiter = 0;
|
|
|
|
result = 1;
|
|
|
|
notout = 1;
|
|
|
|
|
|
|
|
/* Testing if enought threads are available for this check. */
|
|
|
|
#pragma omp parallel
|
|
|
|
{
|
|
|
|
#pragma omp single
|
|
|
|
{
|
|
|
|
threads = omp_get_num_threads ();
|
|
|
|
} /* end of single */
|
|
|
|
} /* end of parallel */
|
|
|
|
|
|
|
|
if (threads < 2) {
|
|
|
|
printf ("This test only works with at least two threads .\n");
|
|
|
|
fprintf (logFile, "This test only works with at least two threads. Available were only %d thread(s).\n", threads);
|
|
|
|
return (0);
|
|
|
|
} /* end if */
|
|
|
|
|
|
|
|
|
|
|
|
/* Now the real parallel work:
|
|
|
|
*
|
|
|
|
* Each thread will start immediately with the first chunk.
|
|
|
|
*/
|
|
|
|
#pragma omp parallel shared(tids,maxiter)
|
|
|
|
{ /* begin of parallel */
|
|
|
|
<ompts:orphan>
|
|
|
|
double count;
|
|
|
|
int tid;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
tid = omp_get_thread_num ();
|
|
|
|
|
|
|
|
#pragma omp for nowait <ompts:check>schedule(guided)</ompts:check>
|
|
|
|
for(j = 0; j < CFSMAX_SIZE; ++j)
|
|
|
|
{
|
|
|
|
count = 0.;
|
|
|
|
#pragma omp flush(maxiter)
|
|
|
|
if (j > maxiter)
|
|
|
|
{
|
|
|
|
#pragma omp critical
|
|
|
|
{
|
|
|
|
maxiter = j;
|
|
|
|
} /* end of critical */
|
|
|
|
}
|
|
|
|
/*printf ("thread %d sleeping\n", tid);*/
|
|
|
|
#pragma omp flush(maxiter,notout)
|
|
|
|
while (notout && (count < MAX_TIME) && (maxiter == j))
|
|
|
|
{
|
|
|
|
#pragma omp flush(maxiter,notout)
|
|
|
|
my_sleep (SLEEPTIME);
|
|
|
|
count += SLEEPTIME;
|
|
|
|
#ifdef VERBOSE
|
|
|
|
printf(".");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef VERBOSE
|
|
|
|
if (count > 0.) printf(" waited %lf s\n", count);
|
|
|
|
#endif
|
|
|
|
/*printf ("thread %d awake\n", tid);*/
|
|
|
|
tids[j] = tid;
|
|
|
|
#ifdef VERBOSE
|
|
|
|
printf("%d finished by %d\n",j,tid);
|
|
|
|
#endif
|
|
|
|
} /* end of for */
|
|
|
|
|
|
|
|
notout = 0;
|
|
|
|
#pragma omp flush(maxiter,notout)
|
|
|
|
</ompts:orphan>
|
|
|
|
} /* end of parallel */
|
|
|
|
|
|
|
|
/*******************************************************
|
|
|
|
* evaluation of the values *
|
|
|
|
*******************************************************/
|
|
|
|
{
|
|
|
|
int determined_chunksize = 1;
|
|
|
|
int last_threadnr = tids[0];
|
|
|
|
int global_chunknr = 0;
|
|
|
|
int local_chunknr[NUMBER_OF_THREADS];
|
|
|
|
int openwork = CFSMAX_SIZE;
|
|
|
|
int expected_chunk_size;
|
|
|
|
double c = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < NUMBER_OF_THREADS; i++)
|
|
|
|
local_chunknr[i] = 0;
|
|
|
|
|
|
|
|
tids[CFSMAX_SIZE] = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* determine the number of global chunks
|
|
|
|
*/
|
|
|
|
/*fprintf(logFile,"# global_chunknr thread local_chunknr chunksize\n"); */
|
|
|
|
for(i = 1; i <= CFSMAX_SIZE; ++i)
|
|
|
|
{
|
|
|
|
if (last_threadnr==tids[i]) {
|
|
|
|
determined_chunksize++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* fprintf (logFile, "%d\t%d\t%d\t%d\n", global_chunknr,last_threadnr, local_chunknr[last_threadnr], m); */
|
|
|
|
global_chunknr++;
|
|
|
|
local_chunknr[last_threadnr]++;
|
|
|
|
last_threadnr = tids[i];
|
|
|
|
determined_chunksize = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* now allocate the memory for saving the sizes of the global chunks */
|
|
|
|
chunksizes = (int*)malloc(global_chunknr * sizeof(int));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Evaluate the sizes of the global chunks
|
|
|
|
*/
|
|
|
|
global_chunknr = 0;
|
|
|
|
determined_chunksize = 1;
|
|
|
|
last_threadnr = tids[0];
|
|
|
|
for (i = 1; i <= CFSMAX_SIZE; ++i)
|
|
|
|
{
|
|
|
|
/* If the threadnumber was the same as before increase the detected chunksize for this chunk
|
|
|
|
* otherwise set the detected chunksize again to one and save the number of the next thread in last_threadnr.
|
|
|
|
*/
|
|
|
|
if (last_threadnr == tids[i]) {
|
|
|
|
determined_chunksize++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
chunksizes[global_chunknr] = determined_chunksize;
|
|
|
|
global_chunknr++;
|
|
|
|
local_chunknr[last_threadnr]++;
|
|
|
|
last_threadnr = tids[i];
|
|
|
|
determined_chunksize = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE
|
|
|
|
fprintf (logFile, "found\texpected\tconstant\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* identify the constant c for the exponential decrease of the chunksize */
|
|
|
|
expected_chunk_size = openwork / threads;
|
|
|
|
c = (double) chunksizes[0] / expected_chunk_size;
|
|
|
|
|
|
|
|
for (i = 0; i < global_chunknr; i++)
|
|
|
|
{
|
|
|
|
/* calculate the new expected chunksize */
|
|
|
|
if (expected_chunk_size > 1)
|
|
|
|
expected_chunk_size = c * openwork / threads;
|
|
|
|
|
|
|
|
#ifdef VERBOSE
|
|
|
|
fprintf (logFile, "%8d\t%8d\t%lf\n", chunksizes[i], expected_chunk_size, c * chunksizes[i]/expected_chunk_size);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* check if chunksize is inside the rounding errors */
|
|
|
|
if (abs (chunksizes[i] - expected_chunk_size) >= 2) {
|
|
|
|
result = 0;
|
|
|
|
#ifndef VERBOSE
|
|
|
|
fprintf (logFile, "Chunksize differed from expected value: %d instead of %d\n", chunksizes[i], expected_chunk_size);
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
} /* end if */
|
|
|
|
|
|
|
|
#ifndef VERBOSE
|
|
|
|
if (expected_chunk_size - chunksizes[i] < 0 )
|
|
|
|
fprintf (logFile, "Chunksize did not decrease: %d instead of %d\n", chunksizes[i],expected_chunk_size);
|
|
|
|
#endif
|
|
|
|
|
2014-06-02 02:28:36 +08:00
|
|
|
/* calculating the remaining amount of work */
|
2014-05-11 01:02:09 +08:00
|
|
|
openwork -= chunksizes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
</ompts:testcode>
|
|
|
|
</ompts:test>
|
|
|
|
|