PandA-2024.02
polybench.c
Go to the documentation of this file.
1 
10 /* polybench.c: this file is part of PolyBench/C */
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <assert.h>
17 #include <time.h>
18 #include <sys/time.h>
19 #include <sys/resource.h>
20 #include <sched.h>
21 #include <math.h>
22 #ifdef _OPENMP
23 # include <omp.h>
24 #endif
25 
26 #if defined(POLYBENCH_PAPI)
27 # undef POLYBENCH_PAPI
28 # include "polybench.h"
29 # define POLYBENCH_PAPI
30 #else
31 # include "polybench.h"
32 #endif
33 
34 /* By default, collect PAPI counters on thread 0. */
35 #ifndef POLYBENCH_THREAD_MONITOR
36 # define POLYBENCH_THREAD_MONITOR 0
37 #endif
38 
39 /* Total LLC cache size. By default 32+MB.. */
40 #ifndef POLYBENCH_CACHE_SIZE_KB
41 # define POLYBENCH_CACHE_SIZE_KB 32770
42 #endif
43 
44 
47 
48 #ifdef POLYBENCH_PAPI
49 # include <papi.h>
50 # define POLYBENCH_MAX_NB_PAPI_COUNTERS 96
51  char* _polybench_papi_eventlist[] = {
52 #include "papi_counters.list"
53  NULL
54  };
55  int polybench_papi_eventset;
56  int polybench_papi_eventlist[POLYBENCH_MAX_NB_PAPI_COUNTERS];
57  long_long polybench_papi_values[POLYBENCH_MAX_NB_PAPI_COUNTERS];
58 
59 #endif
60 
61 /*
62  * Allocation table, to enable inter-array padding. All data allocated
63  * with polybench_alloc_data should be freed with polybench_free_data.
64  *
65  */
66 #define NB_INITIAL_TABLE_ENTRIES 512
68 {
69  void** user_view;
70  void** real_ptr;
73 };
76 
77 /* Timer code (gettimeofday). */
79 /* Timer code (RDTSC). */
80 unsigned long long int polybench_c_start, polybench_c_end;
81 
82 static
83 double rtclock()
84 {
85 #if defined(POLYBENCH_TIME) || defined(POLYBENCH_GFLOPS)
86  struct timeval Tp;
87  int stat;
88  stat = gettimeofday (&Tp, NULL);
89  if (stat != 0)
90  printf ("Error return from gettimeofday: %d", stat);
91  return (Tp.tv_sec + Tp.tv_usec * 1.0e-6);
92 #else
93  return 0;
94 #endif
95 }
96 
97 
98 #ifdef POLYBENCH_CYCLE_ACCURATE_TIMER
99 static
100 unsigned long long int rdtsc()
101 {
102  unsigned long long int ret = 0;
103  unsigned int cycles_lo;
104  unsigned int cycles_hi;
105  __asm__ volatile ("RDTSC" : "=a" (cycles_lo), "=d" (cycles_hi));
106  ret = (unsigned long long int)cycles_hi << 32 | cycles_lo;
107 
108  return ret;
109 }
110 #endif
111 
113 {
114  int cs = POLYBENCH_CACHE_SIZE_KB * 1024 / sizeof(double);
115  double* flush = (double*) calloc (cs, sizeof(double));
116  int i;
117  double tmp = 0.0;
118 #ifdef _OPENMP
119 #pragma omp parallel for reduction(+:tmp) private(i)
120 #endif
121  for (i = 0; i < cs; i++)
122  tmp += flush[i];
123  assert (tmp <= 10.0);
124  free (flush);
125 }
126 
127 
128 #ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
129 void polybench_linux_fifo_scheduler()
130 {
131  /* Use FIFO scheduler to limit OS interference. Program must be run
132  as root, and this works only for Linux kernels. */
133  struct sched_param schedParam;
134  schedParam.sched_priority = sched_get_priority_max (SCHED_FIFO);
135  sched_setscheduler (0, SCHED_FIFO, &schedParam);
136 }
137 
138 
139 void polybench_linux_standard_scheduler()
140 {
141  /* Restore to standard scheduler policy. */
142  struct sched_param schedParam;
143  schedParam.sched_priority = sched_get_priority_max (SCHED_OTHER);
144  sched_setscheduler (0, SCHED_OTHER, &schedParam);
145 }
146 #endif
147 
148 #ifdef POLYBENCH_PAPI
149 
150 static
151 void test_fail(char *file, int line, char *call, int retval)
152 {
153  char buf[128];
154 
155  memset(buf, '\0', sizeof(buf));
156  if (retval != 0)
157  fprintf (stdout,"%-40s FAILED\nLine # %d\n", file, line);
158  else
159  {
160  fprintf (stdout,"%-40s SKIPPED\n", file);
161  fprintf (stdout,"Line # %d\n", line);
162  }
163  if (retval == PAPI_ESYS)
164  {
165  sprintf (buf, "System error in %s", call);
166  perror (buf);
167  }
168  else if (retval > 0)
169  fprintf (stdout,"Error: %s\n", call);
170  else if (retval == 0)
171  fprintf (stdout,"Error: %s\n", call);
172  else
173  {
174  char errstring[PAPI_MAX_STR_LEN];
175  // PAPI 5.4.3 has changed the API for PAPI_perror.
176  #if defined (PAPI_VERSION) && ((PAPI_VERSION_MAJOR(PAPI_VERSION) == 5 && PAPI_VERSION_MINOR(PAPI_VERSION) >= 4) || PAPI_VERSION_MAJOR(PAPI_VERSION) > 5)
177  fprintf (stdout, "Error in %s: %s\n", call, PAPI_strerror(retval));
178  #else
179  PAPI_perror (retval, errstring, PAPI_MAX_STR_LEN);
180  fprintf (stdout,"Error in %s: %s\n", call, errstring);
181  #endif
182  }
183  fprintf (stdout,"\n");
184  if (PAPI_is_initialized ())
185  PAPI_shutdown ();
186  exit (1);
187 }
188 
189 
190 void polybench_papi_init()
191 {
192 # ifdef _OPENMP
193 #pragma omp parallel
194  {
195 #pragma omp master
196  {
197  if (omp_get_max_threads () < polybench_papi_counters_threadid)
198  polybench_papi_counters_threadid = omp_get_max_threads () - 1;
199  }
200 #pragma omp barrier
201 
202  if (omp_get_thread_num () == polybench_papi_counters_threadid)
203  {
204 # endif
205  int retval;
206  polybench_papi_eventset = PAPI_NULL;
207  if ((retval = PAPI_library_init (PAPI_VER_CURRENT)) != PAPI_VER_CURRENT)
208  test_fail (__FILE__, __LINE__, "PAPI_library_init", retval);
209  if ((retval = PAPI_create_eventset (&polybench_papi_eventset))
210  != PAPI_OK)
211  test_fail (__FILE__, __LINE__, "PAPI_create_eventset", retval);
212  int k;
213  for (k = 0; _polybench_papi_eventlist[k]; ++k)
214  {
215  if ((retval =
216  PAPI_event_name_to_code (_polybench_papi_eventlist[k],
217  &(polybench_papi_eventlist[k])))
218  != PAPI_OK)
219  test_fail (__FILE__, __LINE__, "PAPI_event_name_to_code", retval);
220  }
221  polybench_papi_eventlist[k] = 0;
222 
223 
224 # ifdef _OPENMP
225  }
226  }
227 #pragma omp barrier
228 # endif
229 }
230 
231 
232 void polybench_papi_close()
233 {
234 # ifdef _OPENMP
235 #pragma omp parallel
236  {
237  if (omp_get_thread_num () == polybench_papi_counters_threadid)
238  {
239 # endif
240  int retval;
241  if ((retval = PAPI_destroy_eventset (&polybench_papi_eventset))
242  != PAPI_OK)
243  test_fail (__FILE__, __LINE__, "PAPI_destroy_eventset", retval);
244  if (PAPI_is_initialized ())
245  PAPI_shutdown ();
246 # ifdef _OPENMP
247  }
248  }
249 #pragma omp barrier
250 # endif
251 }
252 
253 int polybench_papi_start_counter(int evid)
254 {
255 # ifndef POLYBENCH_NO_FLUSH_CACHE
257 # endif
258 
259 # ifdef _OPENMP
260 # pragma omp parallel
261  {
262  if (omp_get_thread_num () == polybench_papi_counters_threadid)
263  {
264 # endif
265 
266  int retval = 1;
267  char descr[PAPI_MAX_STR_LEN];
268  PAPI_event_info_t evinfo;
269  PAPI_event_code_to_name (polybench_papi_eventlist[evid], descr);
270  if (PAPI_add_event (polybench_papi_eventset,
271  polybench_papi_eventlist[evid]) != PAPI_OK)
272  test_fail (__FILE__, __LINE__, "PAPI_add_event", 1);
273  if (PAPI_get_event_info (polybench_papi_eventlist[evid], &evinfo)
274  != PAPI_OK)
275  test_fail (__FILE__, __LINE__, "PAPI_get_event_info", retval);
276  if ((retval = PAPI_start (polybench_papi_eventset)) != PAPI_OK)
277  test_fail (__FILE__, __LINE__, "PAPI_start", retval);
278 # ifdef _OPENMP
279  }
280  }
281 #pragma omp barrier
282 # endif
283  return 0;
284 }
285 
286 
287 void polybench_papi_stop_counter(int evid)
288 {
289 # ifdef _OPENMP
290 # pragma omp parallel
291  {
292  if (omp_get_thread_num () == polybench_papi_counters_threadid)
293  {
294 # endif
295  int retval;
296  long_long values[1];
297  values[0] = 0;
298  if ((retval = PAPI_read (polybench_papi_eventset, &values[0]))
299  != PAPI_OK)
300  test_fail (__FILE__, __LINE__, "PAPI_read", retval);
301 
302  if ((retval = PAPI_stop (polybench_papi_eventset, NULL)) != PAPI_OK)
303  test_fail (__FILE__, __LINE__, "PAPI_stop", retval);
304 
305  polybench_papi_values[evid] = values[0];
306 
307  if ((retval = PAPI_remove_event
308  (polybench_papi_eventset,
309  polybench_papi_eventlist[evid])) != PAPI_OK)
310  test_fail (__FILE__, __LINE__, "PAPI_remove_event", retval);
311 # ifdef _OPENMP
312  }
313  }
314 #pragma omp barrier
315 # endif
316 }
317 
318 
319 void polybench_papi_print()
320 {
321  int verbose = 0;
322 # ifdef _OPENMP
323 # pragma omp parallel
324  {
325  if (omp_get_thread_num() == polybench_papi_counters_threadid)
326  {
327 #ifdef POLYBENCH_PAPI_VERBOSE
328  verbose = 1;
329 #endif
330  if (verbose)
331  printf ("On thread %d:\n", polybench_papi_counters_threadid);
332 #endif
333  int evid;
334  for (evid = 0; polybench_papi_eventlist[evid] != 0; ++evid)
335  {
336  if (verbose)
337  printf ("%s=", _polybench_papi_eventlist[evid]);
338  printf ("%llu ", polybench_papi_values[evid]);
339  if (verbose)
340  printf ("\n");
341  }
342  printf ("\n");
343 # ifdef _OPENMP
344  }
345  }
346 #pragma omp barrier
347 # endif
348 }
349 
350 #endif
351 /* ! POLYBENCH_PAPI */
352 
354 {
355 #ifndef POLYBENCH_NO_FLUSH_CACHE
357 #endif
358 #ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
359  polybench_linux_fifo_scheduler ();
360 #endif
361 }
362 
363 
365 {
367 #ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
369 #else
370  polybench_c_start = rdtsc ();
371 #endif
372 }
373 
374 
376 {
377 #ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
379 #else
380  polybench_c_end = rdtsc ();
381 #endif
382 #ifdef POLYBENCH_LINUX_FIFO_SCHEDULER
383  polybench_linux_standard_scheduler ();
384 #endif
385 }
386 
387 
389 {
390 #ifdef POLYBENCH_GFLOPS
392  {
393  printf ("[PolyBench][WARNING] Program flops not defined, use polybench_set_program_flops(value)\n");
394  printf ("%0.6lf\n", polybench_t_end - polybench_t_start);
395  }
396  else
397  printf ("%0.2lf\n",
399  (double)(polybench_t_end - polybench_t_start)) / 1000000000);
400 #else
401 # ifndef POLYBENCH_CYCLE_ACCURATE_TIMER
402  printf ("%0.6f\n", polybench_t_end - polybench_t_start);
403 # else
404  printf ("%Ld\n", polybench_c_end - polybench_c_start);
405 # endif
406 #endif
407 }
408 
409 /*
410  * These functions are used only if the user defines a specific
411  * inter-array padding. It grows a global structure,
412  * _polybench_alloc_table, which keeps track of the data allocated via
413  * polybench_alloc_data (on which inter-array padding is applied), so
414  * that the original, non-shifted pointer can be recovered when
415  * calling polybench_free_data.
416  *
417  */
418 #ifdef POLYBENCH_ENABLE_INTARRAY_PAD
419 static
420 void grow_alloc_table()
421 {
422  if (_polybench_alloc_table == NULL ||
423  (_polybench_alloc_table->nb_entries % NB_INITIAL_TABLE_ENTRIES) != 0 ||
424  _polybench_alloc_table->nb_avail_entries != 0)
425  {
426  /* Should never happen if the API is properly used. */
427  fprintf (stderr, "[ERROR] Inter-array padding requires to use polybench_alloc_data and polybench_free_data\n");
428  exit (1);
429  }
430  size_t sz = _polybench_alloc_table->nb_entries;
432  _polybench_alloc_table->user_view =
433  realloc (_polybench_alloc_table->user_view, sz * sizeof(void*));
434  assert(_polybench_alloc_table->user_view != NULL);
435  _polybench_alloc_table->real_ptr =
436  realloc (_polybench_alloc_table->real_ptr, sz * sizeof(void*));
437  assert(_polybench_alloc_table->real_ptr != NULL);
438  _polybench_alloc_table->nb_avail_entries = NB_INITIAL_TABLE_ENTRIES;
439 }
440 
441 static
442 void* register_padded_pointer(void* ptr, size_t orig_sz, size_t padded_sz)
443 {
444  if (_polybench_alloc_table == NULL)
445  {
446  fprintf (stderr, "[ERROR] Inter-array padding requires to use polybench_alloc_data and polybench_free_data\n");
447  exit (1);
448  }
449  if (_polybench_alloc_table->nb_avail_entries == 0)
450  grow_alloc_table ();
451  int id = _polybench_alloc_table->nb_entries++;
452  _polybench_alloc_table->real_ptr[id] = ptr;
453  _polybench_alloc_table->user_view[id] = ptr + (padded_sz - orig_sz);
454 
455  return _polybench_alloc_table->user_view[id];
456 }
457 
458 
459 static
460 void
461 free_data_from_alloc_table (void* ptr)
462 {
463  if (_polybench_alloc_table != NULL && _polybench_alloc_table->nb_entries > 0)
464  {
465  int i;
466  for (i = 0; i < _polybench_alloc_table->nb_entries; ++i)
467  if (_polybench_alloc_table->user_view[i] == ptr ||
468  _polybench_alloc_table->real_ptr[i] == ptr)
469  break;
470  if (i != _polybench_alloc_table->nb_entries)
471  {
472  free (_polybench_alloc_table->real_ptr[i]);
473  for (; i < _polybench_alloc_table->nb_entries - 1; ++i)
474  {
475  _polybench_alloc_table->user_view[i] =
476  _polybench_alloc_table->user_view[i + 1];
477  _polybench_alloc_table->real_ptr[i] =
478  _polybench_alloc_table->real_ptr[i + 1];
479  }
480  _polybench_alloc_table->nb_entries--;
481  _polybench_alloc_table->nb_avail_entries++;
482  if (_polybench_alloc_table->nb_entries == 0)
483  {
484  free (_polybench_alloc_table->user_view);
485  free (_polybench_alloc_table->real_ptr);
486  free (_polybench_alloc_table);
487  _polybench_alloc_table = NULL;
488  }
489  }
490  }
491 }
492 
493 static
494 void check_alloc_table_state()
495 {
496  if (_polybench_alloc_table == NULL)
497  {
498  _polybench_alloc_table = (struct polybench_data_ptrs*)
499  malloc (sizeof(struct polybench_data_ptrs));
500  assert(_polybench_alloc_table != NULL);
501  _polybench_alloc_table->user_view =
502  (void**) malloc (sizeof(void*) * NB_INITIAL_TABLE_ENTRIES);
503  assert(_polybench_alloc_table->user_view != NULL);
504  _polybench_alloc_table->real_ptr =
505  (void**) malloc (sizeof(void*) * NB_INITIAL_TABLE_ENTRIES);
506  assert(_polybench_alloc_table->real_ptr != NULL);
507  _polybench_alloc_table->nb_entries = 0;
508  _polybench_alloc_table->nb_avail_entries = NB_INITIAL_TABLE_ENTRIES;
509  }
510 }
511 
512 #endif // !POLYBENCH_ENABLE_INTARRAY_PAD
513 
514 
515 static
516 void*
517 xmalloc(size_t alloc_sz)
518 {
519  void* ret = NULL;
520  /* By default, post-pad the arrays. Safe behavior, but likely useless. */
522  size_t padded_sz = alloc_sz + polybench_inter_array_padding_sz;
523  int err = posix_memalign (&ret, 4096, padded_sz);
524  if (! ret || err)
525  {
526  fprintf (stderr, "[PolyBench] posix_memalign: cannot allocate memory");
527  exit (1);
528  }
529  /* Safeguard: this is invoked only if polybench.c has been compiled
530  with inter-array padding support from polybench.h. If so, move
531  the starting address of the allocation and return it to the
532  user. The original pointer is registered in an allocation table
533  internal to polybench.c. Data must then be freed using
534  polybench_free_data, which will inspect the allocation table to
535  free the original pointer.*/
536 #ifdef POLYBENCH_ENABLE_INTARRAY_PAD
537  /* This moves the 'ret' pointer by (padded_sz - alloc_sz) positions, and
538  registers it in the lookup table for future free using
539  polybench_free_data. */
540  ret = register_padded_pointer(ret, alloc_sz, padded_sz);
541 #endif
542 
543  return ret;
544 }
545 
546 
547 void polybench_free_data(void* ptr)
548 {
549 #ifdef POLYBENCH_ENABLE_INTARRAY_PAD
550  free_data_from_alloc_table (ptr);
551 #else
552  free (ptr);
553 #endif
554 }
555 
556 
557 void* polybench_alloc_data(unsigned long long int n, int elt_size)
558 {
559 #ifdef POLYBENCH_ENABLE_INTARRAY_PAD
560  check_alloc_table_state ();
561 #endif
562 
564  size_t val = n;
565  val *= elt_size;
566  void* ret = xmalloc (val);
567 
568  return ret;
569 }
#define NULL
void polybench_timer_print()
Definition: polybench.c:388
static void * xmalloc(size_t alloc_sz)
Definition: polybench.c:517
void polybench_free_data(void *ptr)
Definition: polybench.c:547
#define POLYBENCH_THREAD_MONITOR
This version is stamped on May 10, 2016.
Definition: polybench.c:36
#define POLYBENCH_CACHE_SIZE_KB
Definition: polybench.c:41
void * polybench_alloc_data(unsigned long long int n, int elt_size)
Definition: polybench.c:557
double polybench_t_end
Definition: polybench.c:78
static double rtclock()
Definition: polybench.c:83
void line(int x1, int y1, int x2, int y2, unsigned int color)
Definition: main.c:110
static size_t polybench_inter_array_padding_sz
Definition: polybench.c:75
void polybench_flush_cache()
Definition: polybench.c:112
static struct polybench_data_ptrs * _polybench_alloc_table
Definition: polybench.c:74
static const uint32_t k[]
Definition: sha-256.c:22
void polybench_timer_start()
Definition: polybench.c:364
double polybench_t_start
Definition: polybench.c:78
int polybench_papi_counters_threadid
Definition: polybench.c:45
unsigned long long int polybench_c_end
Definition: polybench.c:80
double polybench_program_total_flops
Definition: polybench.c:46
#define POLYBENCH_INTER_ARRAY_PADDING_FACTOR
Definition: polybench.h:41
#define NB_INITIAL_TABLE_ENTRIES
Definition: polybench.c:66
void polybench_timer_stop()
Definition: polybench.c:375
unsigned long long int polybench_c_start
Definition: polybench.c:80
void polybench_prepare_instruments()
Definition: polybench.c:353

Generated on Mon Feb 12 2024 13:02:50 for PandA-2024.02 by doxygen 1.8.13