blob: 148460c975dc38cd8f69204d5ce37b50cdc66c67 [file] [edit]
/**
* This version is stamped on May 10, 2016
*
* Contact:
* Louis-Noel Pouchet <pouchet.ohio-state.edu>
* Tomofumi Yuki <tomofumi.yuki.fr>
*
* Web address: http://polybench.sourceforge.net
*/
/*
* polybench.h: this file is part of PolyBench/C
*
* Polybench header for instrumentation.
*
* Programs must be compiled with `-I utilities utilities/polybench.c'
*
* Optionally, one can define:
*
* -DPOLYBENCH_TIME, to report the execution time,
* OR (exclusive):
* -DPOLYBENCH_PAPI, to use PAPI H/W counters (defined in polybench.c)
*
*
* See README or utilities/polybench.c for additional options.
*
*/
#ifndef POLYBENCH_H
# define POLYBENCH_H
# include <stdlib.h>
/* Array padding. By default, none is used. */
# ifndef POLYBENCH_PADDING_FACTOR
/* default: */
# define POLYBENCH_PADDING_FACTOR 0
# endif
/* Inter-array padding, for use with . By default, none is used. */
# ifndef POLYBENCH_INTER_ARRAY_PADDING_FACTOR
/* default: */
# define POLYBENCH_INTER_ARRAY_PADDING_FACTOR 0
# undef POLYBENCH_ENABLE_INTARRAY_PAD
# else
# define POLYBENCH_ENABLE_INTARRAY_PAD
# endif
/* C99 arrays in function prototype. By default, do not use. */
# ifdef POLYBENCH_USE_C99_PROTO
# define POLYBENCH_C99_SELECT(x,y) y
# else
/* default: */
# define POLYBENCH_C99_SELECT(x,y) x
# endif
/* Scalar loop bounds in SCoPs. By default, use parametric loop bounds. */
# ifdef POLYBENCH_USE_SCALAR_LB
# define POLYBENCH_LOOP_BOUND(x,y) x
# else
/* default: */
# define POLYBENCH_LOOP_BOUND(x,y) y
# endif
/* Use the 'restrict' keyword to declare that the different arrays do not
* alias. By default, we do not use it as it is only supported in C99 and
* even here several compilers do not properly get it.
*/
# ifdef POLYBENCH_USE_RESTRICT
# define POLYBENCH_RESTRICT restrict
# else
/* default: */
# define POLYBENCH_RESTRICT
# endif
/* Macros to reference an array. Generic for heap and stack arrays
(C99). Each array dimensionality has his own macro, to be used at
declaration or as a function argument.
Example:
int b[x] => POLYBENCH_1D_ARRAY(b, x)
int A[N][N] => POLYBENCH_2D_ARRAY(A, N, N)
*/
# ifndef POLYBENCH_STACK_ARRAYS
# define POLYBENCH_ARRAY(x) *x
# ifdef POLYBENCH_ENABLE_INTARRAY_PAD
# define POLYBENCH_FREE_ARRAY(x) polybench_free_data((void*)x);
# else
# define POLYBENCH_FREE_ARRAY(x) free((void*)x);
# endif
# define POLYBENCH_DECL_VAR(x) (*x)
# else
# define POLYBENCH_ARRAY(x) x
# define POLYBENCH_FREE_ARRAY(x)
# define POLYBENCH_DECL_VAR(x) x
# endif
/* Macros for using arrays in the function prototypes. */
# define POLYBENCH_1D(var, dim1,ddim1) var[POLYBENCH_RESTRICT POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_2D(var, dim1, dim2, ddim1, ddim2) var[POLYBENCH_RESTRICT POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_3D(var, dim1, dim2, dim3, ddim1, ddim2, ddim3) var[POLYBENCH_RESTRICT POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_4D(var, dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4) var[POLYBENCH_RESTRICT POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim4,ddim4) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_5D(var, dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5) var[POLYBENCH_RESTRICT POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim4,ddim4) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim5,ddim5) + POLYBENCH_PADDING_FACTOR]
/* Macros for using arrays within the functions. */
# define POLYBENCH_1D_F(var, dim1,ddim1) var[POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_2D_F(var, dim1, dim2, ddim1, ddim2) var[POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_3D_F(var, dim1, dim2, dim3, ddim1, ddim2, ddim3) var[POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_4D_F(var, dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4) var[POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim4,ddim4) + POLYBENCH_PADDING_FACTOR]
# define POLYBENCH_5D_F(var, dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5) var[POLYBENCH_C99_SELECT(dim1,ddim1) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim2,ddim2) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim3,ddim3) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim4,ddim4) + POLYBENCH_PADDING_FACTOR][POLYBENCH_C99_SELECT(dim5,ddim5) + POLYBENCH_PADDING_FACTOR]
/* Macros to allocate heap arrays.
Example:
polybench_alloc_2d_array(N, M, double) => allocates N x M x sizeof(double)
and returns a pointer to the 2d array
*/
# define POLYBENCH_ALLOC_1D_ARRAY(n1, type) \
(type(*)[n1 + POLYBENCH_PADDING_FACTOR])polybench_alloc_data (n1 + POLYBENCH_PADDING_FACTOR, sizeof(type))
# define POLYBENCH_ALLOC_2D_ARRAY(n1, n2, type) \
(type(*)[n1 + POLYBENCH_PADDING_FACTOR][n2 + POLYBENCH_PADDING_FACTOR])polybench_alloc_data ((n1 + POLYBENCH_PADDING_FACTOR) * (n2 + POLYBENCH_PADDING_FACTOR), sizeof(type))
# define POLYBENCH_ALLOC_3D_ARRAY(n1, n2, n3, type) \
(type(*)[n1 + POLYBENCH_PADDING_FACTOR][n2 + POLYBENCH_PADDING_FACTOR][n3 + POLYBENCH_PADDING_FACTOR])polybench_alloc_data ((n1 + POLYBENCH_PADDING_FACTOR) * (n2 + POLYBENCH_PADDING_FACTOR) * (n3 + POLYBENCH_PADDING_FACTOR), sizeof(type))
# define POLYBENCH_ALLOC_4D_ARRAY(n1, n2, n3, n4, type) \
(type(*)[n1 + POLYBENCH_PADDING_FACTOR][n2 + POLYBENCH_PADDING_FACTOR][n3 + POLYBENCH_PADDING_FACTOR][n4 + POLYBENCH_PADDING_FACTOR])polybench_alloc_data ((n1 + POLYBENCH_PADDING_FACTOR) * (n2 + POLYBENCH_PADDING_FACTOR) * (n3 + POLYBENCH_PADDING_FACTOR) * (n4 + POLYBENCH_PADDING_FACTOR), sizeof(type))
# define POLYBENCH_ALLOC_5D_ARRAY(n1, n2, n3, n4, n5, type) \
(type(*)[n1 + POLYBENCH_PADDING_FACTOR][n2 + POLYBENCH_PADDING_FACTOR][n3 + POLYBENCH_PADDING_FACTOR][n4 + POLYBENCH_PADDING_FACTOR][n5 + POLYBENCH_PADDING_FACTOR])polybench_alloc_data ((n1 + POLYBENCH_PADDING_FACTOR) * (n2 + POLYBENCH_PADDING_FACTOR) * (n3 + POLYBENCH_PADDING_FACTOR) * (n4 + POLYBENCH_PADDING_FACTOR) * (n5 + POLYBENCH_PADDING_FACTOR), sizeof(type))
/* Macros for array declaration. */
# ifndef POLYBENCH_STACK_ARRAYS
# define POLYBENCH_1D_ARRAY_DECL(var, type, dim1, ddim1) \
type POLYBENCH_1D_F(POLYBENCH_DECL_VAR(var), dim1, ddim1); \
var = POLYBENCH_ALLOC_1D_ARRAY(POLYBENCH_C99_SELECT(dim1, ddim1), type);
# define POLYBENCH_2D_ARRAY_DECL(var, type, dim1, dim2, ddim1, ddim2) \
type POLYBENCH_2D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, ddim1, ddim2); \
var = POLYBENCH_ALLOC_2D_ARRAY(POLYBENCH_C99_SELECT(dim1, ddim1), POLYBENCH_C99_SELECT(dim2, ddim2), type);
# define POLYBENCH_3D_ARRAY_DECL(var, type, dim1, dim2, dim3, ddim1, ddim2, ddim3) \
type POLYBENCH_3D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, ddim1, ddim2, ddim3); \
var = POLYBENCH_ALLOC_3D_ARRAY(POLYBENCH_C99_SELECT(dim1, ddim1), POLYBENCH_C99_SELECT(dim2, ddim2), POLYBENCH_C99_SELECT(dim3, ddim3), type);
# define POLYBENCH_4D_ARRAY_DECL(var, type, dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4) \
type POLYBENCH_4D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4); \
var = POLYBENCH_ALLOC_4D_ARRAY(POLYBENCH_C99_SELECT(dim1, ddim1), POLYBENCH_C99_SELECT(dim2, ddim2), POLYBENCH_C99_SELECT(dim3, ddim3), POLYBENCH_C99_SELECT(dim4, ddim4), type);
# define POLYBENCH_5D_ARRAY_DECL(var, type, dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5) \
type POLYBENCH_5D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5); \
var = POLYBENCH_ALLOC_5D_ARRAY(POLYBENCH_C99_SELECT(dim1, ddim1), POLYBENCH_C99_SELECT(dim2, ddim2), POLYBENCH_C99_SELECT(dim3, ddim3), POLYBENCH_C99_SELECT(dim4, ddim4), POLYBENCH_C99_SELECT(dim5, ddim5), type);
# else
# define POLYBENCH_1D_ARRAY_DECL(var, type, dim1, ddim1) \
type POLYBENCH_1D_F(POLYBENCH_DECL_VAR(var), dim1, ddim1);
# define POLYBENCH_2D_ARRAY_DECL(var, type, dim1, dim2, ddim1, ddim2) \
type POLYBENCH_2D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, ddim1, ddim2);
# define POLYBENCH_3D_ARRAY_DECL(var, type, dim1, dim2, dim3, ddim1, ddim2, ddim3) \
type POLYBENCH_3D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, ddim1, ddim2, ddim3);
# define POLYBENCH_4D_ARRAY_DECL(var, type, dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4) \
type POLYBENCH_4D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, dim4, ddim1, ddim2, ddim3, ddim4);
# define POLYBENCH_5D_ARRAY_DECL(var, type, dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5) \
type POLYBENCH_5D_F(POLYBENCH_DECL_VAR(var), dim1, dim2, dim3, dim4, dim5, ddim1, ddim2, ddim3, ddim4, ddim5);
# endif
/* Dead-code elimination macros. Use argc/argv for the run-time check. */
# ifndef POLYBENCH_DUMP_ARRAYS
# define POLYBENCH_DCE_ONLY_CODE if (argc > 42 && ! strcmp(argv[0], ""))
# else
# define POLYBENCH_DCE_ONLY_CODE
# endif
#define POLYBENCH_DUMP_TARGET stderr
#define POLYBENCH_DUMP_START fprintf(POLYBENCH_DUMP_TARGET, "==BEGIN DUMP_ARRAYS==\n")
#define POLYBENCH_DUMP_FINISH fprintf(POLYBENCH_DUMP_TARGET, "==END DUMP_ARRAYS==\n")
#define POLYBENCH_DUMP_BEGIN(s) fprintf(POLYBENCH_DUMP_TARGET, "begin dump: %s", s)
#define POLYBENCH_DUMP_END(s) fprintf(POLYBENCH_DUMP_TARGET, "\nend dump: %s\n", s)
# define polybench_prevent_dce(func) \
POLYBENCH_DCE_ONLY_CODE \
func
/* Performance-related instrumentation. See polybench.c */
# define polybench_start_instruments
# define polybench_stop_instruments
# define polybench_print_instruments
/* PAPI support. */
# ifdef POLYBENCH_PAPI
extern const unsigned int polybench_papi_eventlist[];
# undef polybench_start_instruments
# undef polybench_stop_instruments
# undef polybench_print_instruments
# define polybench_set_papi_thread_report(x) \
polybench_papi_counters_threadid = x;
# define polybench_start_instruments \
polybench_prepare_instruments(); \
polybench_papi_init(); \
int evid; \
for (evid = 0; polybench_papi_eventlist[evid] != 0; evid++) \
{ \
if (polybench_papi_start_counter(evid)) \
continue; \
# define polybench_stop_instruments \
polybench_papi_stop_counter(evid); \
} \
polybench_papi_close(); \
# define polybench_print_instruments polybench_papi_print();
# endif
/* Timing support. */
# if defined(POLYBENCH_TIME) || defined(POLYBENCH_GFLOPS)
# undef polybench_start_instruments
# undef polybench_stop_instruments
# undef polybench_print_instruments
# define polybench_start_instruments polybench_timer_start();
# define polybench_stop_instruments polybench_timer_stop();
# define polybench_print_instruments polybench_timer_print();
extern double polybench_program_total_flops;
extern void polybench_timer_start();
extern void polybench_timer_stop();
extern void polybench_timer_print();
# endif
/* Function declaration. */
# ifdef POLYBENCH_TIME
extern void polybench_timer_start();
extern void polybench_timer_stop();
extern void polybench_timer_print();
# endif
/* PAPI support. */
# ifdef POLYBENCH_PAPI
extern int polybench_papi_start_counter(int evid);
extern void polybench_papi_stop_counter(int evid);
extern void polybench_papi_init();
extern void polybench_papi_close();
extern void polybench_papi_print();
# endif
/* Function prototypes. */
extern void* polybench_alloc_data(unsigned long long int n, int elt_size);
extern void polybench_free_data(void* ptr);
/* PolyBench internal functions that should not be directly called by */
/* the user, unless when designing customized execution profiling */
/* approaches. */
extern void polybench_flush_cache();
extern void polybench_prepare_instruments();
/*
LLVM: I'm appending the content of the file polybench.c here. It'll avoid us
to have to copy it to the folder being compiled in the LLVM test suite.
*/
/**
* This version is stamped on May 10, 2016
*
* Contact:
* Louis-Noel Pouchet <pouchet.ohio-state.edu>
* Tomofumi Yuki <tomofumi.yuki.fr>
*
* Web address: http://polybench.sourceforge.net
*/
/* polybench.c: this file is part of PolyBench/C */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include <math.h>
#ifdef _OPENMP
# include <omp.h>
#endif
#if defined(POLYBENCH_PAPI)
# undef POLYBENCH_PAPI
# include "polybench.h"
# define POLYBENCH_PAPI
#else
# include "polybench.h"
#endif
/* By default, collect PAPI counters on thread 0. */
#ifndef POLYBENCH_THREAD_MONITOR
# define POLYBENCH_THREAD_MONITOR 0
#endif
/* Total LLC cache size. By default 32+MB.. */
#ifndef POLYBENCH_CACHE_SIZE_KB
# define POLYBENCH_CACHE_SIZE_KB 32770
#endif
int polybench_papi_counters_threadid = POLYBENCH_THREAD_MONITOR;
double polybench_program_total_flops = 0;
#ifdef POLYBENCH_PAPI
# include <papi.h>
# define POLYBENCH_MAX_NB_PAPI_COUNTERS 96
char* _polybench_papi_eventlist[] = {
#include "papi_counters.list"
NULL
};
int polybench_papi_eventset;
int polybench_papi_eventlist[POLYBENCH_MAX_NB_PAPI_COUNTERS];
long_long polybench_papi_values[POLYBENCH_MAX_NB_PAPI_COUNTERS];
#endif
/*
* Allocation table, to enable inter-array padding. All data allocated
* with polybench_alloc_data should be freed with polybench_free_data.
*
*/
#define NB_INITIAL_TABLE_ENTRIES 512
struct polybench_data_ptrs
{
void** user_view;
void** real_ptr;
int nb_entries;
int nb_avail_entries;
};
static struct polybench_data_ptrs* _polybench_alloc_table = NULL;
static size_t polybench_inter_array_padding_sz = 0;
/* Timer code (gettimeofday). */
double polybench_t_start, polybench_t_end;
/* Timer code (RDTSC). */
unsigned long long int polybench_c_start, polybench_c_end;
static
double rtclock()
{
#if defined(POLYBENCH_TIME) || defined(POLYBENCH_GFLOPS)
struct timeval Tp;
int stat;
stat = gettimeofday (&Tp, NULL);
if (stat != 0)
printf ("Error return from gettimeofday: %d", stat);
return (Tp.tv_sec + Tp.tv_usec * 1.0e-6);
#else
return 0;
#endif
}
#ifdef POLYBENCH_CYCLE_ACCURATE_TIMER
static
unsigned long long int rdtsc()
{
unsigned long long int ret = 0;
unsigned int cycles_lo;
unsigned int cycles_hi;
__asm__ volatile ("RDTSC" : "=a" (cycles_lo), "=d" (cycles_hi));
ret = (unsigned long long int)cycles_hi << 32 | cycles_lo;
return ret;
}
#endif
void polybench_flush_cache()
{
int cs = POLYBENCH_CACHE_SIZE_KB * 1024 / sizeof(double);
double* flush = (double*) calloc (cs, sizeof(double));
int i;
double tmp = 0.0;
#ifdef _OPENMP
#pragma omp parallel for reduction(+:tmp) private(i)
#endif
for (i = 0; i < cs; i++)
tmp += flush[i];
assert (tmp <= 10.0);
free (flush);
}
#ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
void polybench_linux_fifo_scheduler()
{
/* Use FIFO scheduler to limit OS interference. Program must be run
as root, and this works only for Linux kernels. */
struct sched_param schedParam;
schedParam.sched_priority = sched_get_priority_max (SCHED_FIFO);
sched_setscheduler (0, SCHED_FIFO, &schedParam);
}
void polybench_linux_standard_scheduler()
{
/* Restore to standard scheduler policy. */
struct sched_param schedParam;
schedParam.sched_priority = sched_get_priority_max (SCHED_OTHER);
sched_setscheduler (0, SCHED_OTHER, &schedParam);
}
#endif
#ifdef POLYBENCH_PAPI
static
void test_fail(char *file, int line, char *call, int retval)
{
char buf[128];
memset(buf, '\0', sizeof(buf));
if (retval != 0)
fprintf (stdout,"%-40s FAILED\nLine # %d\n", file, line);
else
{
fprintf (stdout,"%-40s SKIPPED\n", file);
fprintf (stdout,"Line # %d\n", line);
}
if (retval == PAPI_ESYS)
{
sprintf (buf, "System error in %s", call);
perror (buf);
}
else if (retval > 0)
fprintf (stdout,"Error: %s\n", call);
else if (retval == 0)
fprintf (stdout,"Error: %s\n", call);
else
{
char errstring[PAPI_MAX_STR_LEN];
// PAPI 5.4.3 has changed the API for PAPI_perror.
#if defined (PAPI_VERSION) && ((PAPI_VERSION_MAJOR(PAPI_VERSION) == 5 && PAPI_VERSION_MINOR(PAPI_VERSION) >= 4) || PAPI_VERSION_MAJOR(PAPI_VERSION) > 5)
fprintf (stdout, "Error in %s: %s\n", call, PAPI_strerror(retval));
#else
PAPI_perror (retval, errstring, PAPI_MAX_STR_LEN);
fprintf (stdout,"Error in %s: %s\n", call, errstring);
#endif
}
fprintf (stdout,"\n");
if (PAPI_is_initialized ())
PAPI_shutdown ();
exit (1);
}
void polybench_papi_init()
{
# ifdef _OPENMP
#pragma omp parallel
{
#pragma omp master
{
if (omp_get_max_threads () < polybench_papi_counters_threadid)
polybench_papi_counters_threadid = omp_get_max_threads () - 1;
}
#pragma omp barrier
if (omp_get_thread_num () == polybench_papi_counters_threadid)
{
# endif
int retval;
polybench_papi_eventset = PAPI_NULL;
if ((retval = PAPI_library_init (PAPI_VER_CURRENT)) != PAPI_VER_CURRENT)
test_fail (__FILE__, __LINE__, "PAPI_library_init", retval);
if ((retval = PAPI_create_eventset (&polybench_papi_eventset))
!= PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_create_eventset", retval);
int k;
for (k = 0; _polybench_papi_eventlist[k]; ++k)
{
if ((retval =
PAPI_event_name_to_code (_polybench_papi_eventlist[k],
&(polybench_papi_eventlist[k])))
!= PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_event_name_to_code", retval);
}
polybench_papi_eventlist[k] = 0;
# ifdef _OPENMP
}
}
#pragma omp barrier
# endif
}
void polybench_papi_close()
{
# ifdef _OPENMP
#pragma omp parallel
{
if (omp_get_thread_num () == polybench_papi_counters_threadid)
{
# endif
int retval;
if ((retval = PAPI_destroy_eventset (&polybench_papi_eventset))
!= PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_destroy_eventset", retval);
if (PAPI_is_initialized ())
PAPI_shutdown ();
# ifdef _OPENMP
}
}
#pragma omp barrier
# endif
}
int polybench_papi_start_counter(int evid)
{
# ifndef POLYBENCH_NO_FLUSH_CACHE
polybench_flush_cache();
# endif
# ifdef _OPENMP
# pragma omp parallel
{
if (omp_get_thread_num () == polybench_papi_counters_threadid)
{
# endif
int retval = 1;
char descr[PAPI_MAX_STR_LEN];
PAPI_event_info_t evinfo;
PAPI_event_code_to_name (polybench_papi_eventlist[evid], descr);
if (PAPI_add_event (polybench_papi_eventset,
polybench_papi_eventlist[evid]) != PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_add_event", 1);
if (PAPI_get_event_info (polybench_papi_eventlist[evid], &evinfo)
!= PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_get_event_info", retval);
if ((retval = PAPI_start (polybench_papi_eventset)) != PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_start", retval);
# ifdef _OPENMP
}
}
#pragma omp barrier
# endif
return 0;
}
void polybench_papi_stop_counter(int evid)
{
# ifdef _OPENMP
# pragma omp parallel
{
if (omp_get_thread_num () == polybench_papi_counters_threadid)
{
# endif
int retval;
long_long values[1];
values[0] = 0;
if ((retval = PAPI_read (polybench_papi_eventset, &values[0]))
!= PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_read", retval);
if ((retval = PAPI_stop (polybench_papi_eventset, NULL)) != PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_stop", retval);
polybench_papi_values[evid] = values[0];
if ((retval = PAPI_remove_event
(polybench_papi_eventset,
polybench_papi_eventlist[evid])) != PAPI_OK)
test_fail (__FILE__, __LINE__, "PAPI_remove_event", retval);
# ifdef _OPENMP
}
}
#pragma omp barrier
# endif
}
void polybench_papi_print()
{
int verbose = 0;
# ifdef _OPENMP
# pragma omp parallel
{
if (omp_get_thread_num() == polybench_papi_counters_threadid)
{
#ifdef POLYBENCH_PAPI_VERBOSE
verbose = 1;
#endif
if (verbose)
printf ("On thread %d:\n", polybench_papi_counters_threadid);
#endif
int evid;
for (evid = 0; polybench_papi_eventlist[evid] != 0; ++evid)
{
if (verbose)
printf ("%s=", _polybench_papi_eventlist[evid]);
printf ("%llu ", polybench_papi_values[evid]);
if (verbose)
printf ("\n");
}
printf ("\n");
# ifdef _OPENMP
}
}
#pragma omp barrier
# endif
}
#endif
/* ! POLYBENCH_PAPI */
void polybench_prepare_instruments()
{
#ifndef POLYBENCH_NO_FLUSH_CACHE
polybench_flush_cache ();
#endif
#ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
polybench_linux_fifo_scheduler ();
#endif
}
void polybench_timer_start()
{
polybench_prepare_instruments ();
#ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
polybench_t_start = rtclock ();
#else
polybench_c_start = rdtsc ();
#endif
}
void polybench_timer_stop()
{
#ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
polybench_t_end = rtclock ();
#else
polybench_c_end = rdtsc ();
#endif
#ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
polybench_linux_standard_scheduler ();
#endif
}
void polybench_timer_print()
{
#ifdef POLYBENCH_GFLOPS
if (polybench_program_total_flops == 0)
{
printf ("[PolyBench][WARNING] Program flops not defined, use polybench_set_program_flops(value)\n");
printf ("%0.6lf\n", polybench_t_end - polybench_t_start);
}
else
printf ("%0.2lf\n",
(polybench_program_total_flops /
(double)(polybench_t_end - polybench_t_start)) / 1000000000);
#else
# ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
printf ("%0.6f\n", polybench_t_end - polybench_t_start);
# else
printf ("%Ld\n", polybench_c_end - polybench_c_start);
# endif
#endif
}
/*
* These functions are used only if the user defines a specific
* inter-array padding. It grows a global structure,
* _polybench_alloc_table, which keeps track of the data allocated via
* polybench_alloc_data (on which inter-array padding is applied), so
* that the original, non-shifted pointer can be recovered when
* calling polybench_free_data.
*
*/
#ifdef POLYBENCH_ENABLE_INTARRAY_PAD
static
void grow_alloc_table()
{
if (_polybench_alloc_table == NULL ||
(_polybench_alloc_table->nb_entries % NB_INITIAL_TABLE_ENTRIES) != 0 ||
_polybench_alloc_table->nb_avail_entries != 0)
{
/* Should never happen if the API is properly used. */
fprintf (stderr, "[ERROR] Inter-array padding requires to use polybench_alloc_data and polybench_free_data\n");
exit (1);
}
size_t sz = _polybench_alloc_table->nb_entries;
sz += NB_INITIAL_TABLE_ENTRIES;
_polybench_alloc_table->user_view =
realloc (_polybench_alloc_table->user_view, sz * sizeof(void*));
assert(_polybench_alloc_table->user_view != NULL);
_polybench_alloc_table->real_ptr =
realloc (_polybench_alloc_table->real_ptr, sz * sizeof(void*));
assert(_polybench_alloc_table->real_ptr != NULL);
_polybench_alloc_table->nb_avail_entries = NB_INITIAL_TABLE_ENTRIES;
}
static
void* register_padded_pointer(void* ptr, size_t orig_sz, size_t padded_sz)
{
if (_polybench_alloc_table == NULL)
{
fprintf (stderr, "[ERROR] Inter-array padding requires to use polybench_alloc_data and polybench_free_data\n");
exit (1);
}
if (_polybench_alloc_table->nb_avail_entries == 0)
grow_alloc_table ();
int id = _polybench_alloc_table->nb_entries++;
_polybench_alloc_table->real_ptr[id] = ptr;
_polybench_alloc_table->user_view[id] = ptr + (padded_sz - orig_sz);
return _polybench_alloc_table->user_view[id];
}
static
void
free_data_from_alloc_table (void* ptr)
{
if (_polybench_alloc_table != NULL && _polybench_alloc_table->nb_entries > 0)
{
int i;
for (i = 0; i < _polybench_alloc_table->nb_entries; ++i)
if (_polybench_alloc_table->user_view[i] == ptr ||
_polybench_alloc_table->real_ptr[i] == ptr)
break;
if (i != _polybench_alloc_table->nb_entries)
{
free (_polybench_alloc_table->real_ptr[i]);
for (; i < _polybench_alloc_table->nb_entries - 1; ++i)
{
_polybench_alloc_table->user_view[i] =
_polybench_alloc_table->user_view[i + 1];
_polybench_alloc_table->real_ptr[i] =
_polybench_alloc_table->real_ptr[i + 1];
}
_polybench_alloc_table->nb_entries--;
_polybench_alloc_table->nb_avail_entries++;
if (_polybench_alloc_table->nb_entries == 0)
{
free (_polybench_alloc_table->user_view);
free (_polybench_alloc_table->real_ptr);
free (_polybench_alloc_table);
_polybench_alloc_table = NULL;
}
}
}
}
static
void check_alloc_table_state()
{
if (_polybench_alloc_table == NULL)
{
_polybench_alloc_table = (struct polybench_data_ptrs*)
malloc (sizeof(struct polybench_data_ptrs));
assert(_polybench_alloc_table != NULL);
_polybench_alloc_table->user_view =
(void**) malloc (sizeof(void*) * NB_INITIAL_TABLE_ENTRIES);
assert(_polybench_alloc_table->user_view != NULL);
_polybench_alloc_table->real_ptr =
(void**) malloc (sizeof(void*) * NB_INITIAL_TABLE_ENTRIES);
assert(_polybench_alloc_table->real_ptr != NULL);
_polybench_alloc_table->nb_entries = 0;
_polybench_alloc_table->nb_avail_entries = NB_INITIAL_TABLE_ENTRIES;
}
}
#endif // !POLYBENCH_ENABLE_INTARRAY_PAD
static
void*
xmalloc(size_t alloc_sz)
{
void* ret = NULL;
/* By default, post-pad the arrays. Safe behavior, but likely useless. */
polybench_inter_array_padding_sz += POLYBENCH_INTER_ARRAY_PADDING_FACTOR;
size_t padded_sz = alloc_sz + polybench_inter_array_padding_sz;
int err = posix_memalign (&ret, 4096, padded_sz);
if (! ret || err)
{
fprintf (stderr, "[PolyBench] posix_memalign: cannot allocate memory");
exit (1);
}
/* Safeguard: this is invoked only if polybench.c has been compiled
with inter-array padding support from polybench.h. If so, move
the starting address of the allocation and return it to the
user. The original pointer is registered in an allocation table
internal to polybench.c. Data must then be freed using
polybench_free_data, which will inspect the allocation table to
free the original pointer.*/
#ifdef POLYBENCH_ENABLE_INTARRAY_PAD
/* This moves the 'ret' pointer by (padded_sz - alloc_sz) positions, and
registers it in the lookup table for future free using
polybench_free_data. */
ret = register_padded_pointer(ret, alloc_sz, padded_sz);
#endif
return ret;
}
void polybench_free_data(void* ptr)
{
#ifdef POLYBENCH_ENABLE_INTARRAY_PAD
free_data_from_alloc_table (ptr);
#else
free (ptr);
#endif
}
void* polybench_alloc_data(unsigned long long int n, int elt_size)
{
#ifdef POLYBENCH_ENABLE_INTARRAY_PAD
check_alloc_table_state ();
#endif
/// FIXME: detect overflow!
size_t val = n;
val *= elt_size;
void* ret = xmalloc (val);
return ret;
}
/* To avoid calling printf M*M times (and make it run
for a long time), we split the output into an encoded string,
and print it as a simple char pointer, M times. */
static inline
void print_element(double el, int pos, char *out)
{
union {
double datum;
char bytes[8];
} block;
block.datum = el;
/* each nibble as a char, within the printable range */
#ifdef __BIG_ENDIAN__
*(out+pos+15) = (block.bytes[0]&0xF0>>4)+'0';
*(out+pos+14) = (block.bytes[0]&0x0F) +'0';
*(out+pos+13) = (block.bytes[1]&0xF0>>4)+'0';
*(out+pos+12) = (block.bytes[1]&0x0F) +'0';
*(out+pos+11) = (block.bytes[2]&0xF0>>4)+'0';
*(out+pos+10) = (block.bytes[2]&0x0F) +'0';
*(out+pos+9) = (block.bytes[3]&0xF0>>4)+'0';
*(out+pos+8) = (block.bytes[3]&0x0F) +'0';
*(out+pos+7) = (block.bytes[4]&0xF0>>4)+'0';
*(out+pos+6) = (block.bytes[4]&0x0F) +'0';
*(out+pos+5) = (block.bytes[5]&0xF0>>4)+'0';
*(out+pos+4) = (block.bytes[5]&0x0F) +'0';
*(out+pos+3) = (block.bytes[6]&0xF0>>4)+'0';
*(out+pos+2) = (block.bytes[6]&0x0F) +'0';
*(out+pos+1) = (block.bytes[7]&0xF0>>4)+'0';
*(out+pos) = (block.bytes[7]&0x0F) +'0';
#else
*(out+pos) = (block.bytes[0]&0xF0>>4)+'0';
*(out+pos+1) = (block.bytes[0]&0x0F) +'0';
*(out+pos+2) = (block.bytes[1]&0xF0>>4)+'0';
*(out+pos+3) = (block.bytes[1]&0x0F) +'0';
*(out+pos+4) = (block.bytes[2]&0xF0>>4)+'0';
*(out+pos+5) = (block.bytes[2]&0x0F) +'0';
*(out+pos+6) = (block.bytes[3]&0xF0>>4)+'0';
*(out+pos+7) = (block.bytes[3]&0x0F) +'0';
*(out+pos+8) = (block.bytes[4]&0xF0>>4)+'0';
*(out+pos+9) = (block.bytes[4]&0x0F) +'0';
*(out+pos+10) = (block.bytes[5]&0xF0>>4)+'0';
*(out+pos+11) = (block.bytes[5]&0x0F) +'0';
*(out+pos+12) = (block.bytes[6]&0xF0>>4)+'0';
*(out+pos+13) = (block.bytes[6]&0x0F) +'0';
*(out+pos+14) = (block.bytes[7]&0xF0>>4)+'0';
*(out+pos+15) = (block.bytes[7]&0x0F) +'0';
#endif
}
#endif /* !POLYBENCH_H */