summaryrefslogtreecommitdiffstats
path: root/testsuites/smptests
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-12-18 10:24:34 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-02-02 15:01:19 +0100
commit0c5d22f50931f300180e0479e0a674ede416a5a6 (patch)
tree43fc5fb6f23814c987e112a501c4eab2555ebec9 /testsuites/smptests
parentspsyslock01: Fix object compare (diff)
downloadrtems-0c5d22f50931f300180e0479e0a674ede416a5a6.tar.bz2
smptests/smpopenmp01: New test
Diffstat (limited to 'testsuites/smptests')
-rw-r--r--testsuites/smptests/Makefile.am1
-rw-r--r--testsuites/smptests/configure.ac1
-rw-r--r--testsuites/smptests/smpopenmp01/Makefile.am20
-rw-r--r--testsuites/smptests/smpopenmp01/init.c354
-rw-r--r--testsuites/smptests/smpopenmp01/smpopenmp01.doc11
-rw-r--r--testsuites/smptests/smpopenmp01/smpopenmp01.py42
-rw-r--r--testsuites/smptests/smpopenmp01/smpopenmp01.scn81
7 files changed, 510 insertions, 0 deletions
diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am
index 08228ed5b5..03b29a1d71 100644
--- a/testsuites/smptests/Makefile.am
+++ b/testsuites/smptests/Makefile.am
@@ -30,6 +30,7 @@ _SUBDIRS += smpmigration02
_SUBDIRS += smpmrsp01
_SUBDIRS += smpmutex01
_SUBDIRS += smpmutex02
+_SUBDIRS += smpopenmp01
_SUBDIRS += smpschedaffinity03
_SUBDIRS += smpschedaffinity04
_SUBDIRS += smpschedaffinity05
diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac
index 78996b23ab..f8b5fe28b2 100644
--- a/testsuites/smptests/configure.ac
+++ b/testsuites/smptests/configure.ac
@@ -55,6 +55,7 @@ AC_CHECK_DECLS([pthread_getattr_np],[],[],[[
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
+smpopenmp01/Makefile
smp01/Makefile
smp02/Makefile
smp03/Makefile
diff --git a/testsuites/smptests/smpopenmp01/Makefile.am b/testsuites/smptests/smpopenmp01/Makefile.am
new file mode 100644
index 0000000000..08505791d6
--- /dev/null
+++ b/testsuites/smptests/smpopenmp01/Makefile.am
@@ -0,0 +1,20 @@
+rtems_tests_PROGRAMS = smpopenmp01
+smpopenmp01_SOURCES = init.c
+
+dist_rtems_tests_DATA = smpopenmp01.scn smpopenmp01.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+AM_CFLAGS += -fopenmp
+
+LINK_OBJS = $(smpopenmp01_OBJECTS)
+LINK_LIBS = $(smpopenmp01_LDLIBS)
+
+smpopenmp01$(EXEEXT): $(smpopenmp01_OBJECTS) $(smpopenmp01_DEPENDENCIES)
+ @rm -f smpopenmp01$(EXEEXT)
+ $(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpopenmp01/init.c b/testsuites/smptests/smpopenmp01/init.c
new file mode 100644
index 0000000000..5d4ab1243d
--- /dev/null
+++ b/testsuites/smptests/smpopenmp01/init.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2017 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+/*
+ * This OpenMP micro benchmark is based on mailing list posts from Jakub
+ * Jelinek.
+ *
+ * Subject: [gomp3] libgomp performance improvements
+ * https://gcc.gnu.org/ml/gcc-patches/2008-03/msg00930.html
+ *
+ * Subject: [gomp3] Use private futexes if possible
+ * https://gcc.gnu.org/ml/gcc-patches/2008-03/msg01126.html
+ *
+ * This file can be compiled on Linux, etc. using:
+ *
+ * cc -std=c11 -O2 -fopenmp init.c
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <omp.h>
+#include <stdio.h>
+
+#ifdef __rtems__
+#include <pthread.h>
+#include <tmacros.h>
+
+const char rtems_test_name[] = "SMPOPENMP 1";
+
+#define CPU_COUNT_MAX 32
+#endif /* __rtems__ */
+
+static void work(void)
+{
+ __asm__ volatile ("" : : : "memory");
+}
+
+static void barrier_bench(void)
+{
+ #pragma omp parallel
+ for (int i = 0; i < 10000; ++i) {
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ #pragma omp barrier
+ work();
+ }
+}
+
+static void parallel_bench(void)
+{
+ for (int i = 0; i < 20000; ++i) {
+ #pragma omp parallel
+ work();
+ }
+}
+
+static void static_bench(void)
+{
+ for (int i = 0; i < 1000; ++i) {
+ #pragma omp parallel for schedule (static)
+ for (int j = 0; j < 100; ++j) {
+ work();
+ }
+ }
+}
+
+static void dynamic_bench(void)
+{
+ #pragma omp parallel for schedule (dynamic)
+ for (int i = 0; i < 100000; ++i) {
+ work();
+ }
+}
+
+static void guided_bench(void)
+{
+ #pragma omp parallel for schedule (guided)
+ for (int i = 0; i < 100000; ++i) {
+ work();
+ }
+}
+
+static void runtime_bench(void)
+{
+ #pragma omp parallel for schedule (runtime)
+ for (int i = 0; i < 100000; ++i) {
+ work();
+ }
+}
+
+static void single_bench(void)
+{
+ #pragma omp parallel
+ for (int i = 0; i < 10000; ++i) {
+ #pragma omp single
+ work();
+ }
+}
+
+static void all(void)
+{
+ barrier_bench();
+ parallel_bench();
+ static_bench();
+ dynamic_bench();
+ guided_bench();
+ runtime_bench();
+ single_bench();
+}
+
+static void do_bench(const char *name, void (*bench)(void), int n)
+{
+ double start;
+ double delta;
+
+ (*bench)();
+ start = omp_get_wtime();
+ for (int i = 0; i < n; ++i) {
+ (*bench)();
+ }
+ delta = omp_get_wtime() - start;
+ printf("\t\t<%sBench unit=\"s\">%f</%sBench>\n", name, delta, name);
+}
+
+static void microbench(int num_threads, int n)
+{
+ printf("\t<Microbench numThreads=\"%i\" majorLoopCount=\"%i\">\n", num_threads, n);
+ omp_set_num_threads(num_threads);
+ do_bench("Barrier", barrier_bench, n);
+ do_bench("Parallel", parallel_bench, n);
+ do_bench("Static", static_bench, n);
+ do_bench("Dynamic", dynamic_bench, n);
+ do_bench("Guided", guided_bench, n);
+ do_bench("Runtime", runtime_bench, n);
+ do_bench("Single", single_bench, n);
+ printf("\t</Microbench>\n");
+}
+
+static int estimate_3s_runtime_with_one_proc(void)
+{
+ double start;
+ double delta;
+ int n;
+
+ omp_set_num_threads(1);
+ all();
+ start = omp_get_wtime();
+ all();
+ delta = omp_get_wtime() - start;
+
+ if (delta > 0.0 && delta <= 1.0) {
+ n = (int) (3.0 / delta);
+ } else {
+ n = 1;
+ }
+
+ return n;
+}
+
+static void test(void)
+{
+ int num_procs;
+ int n;
+
+ printf("<SMPOpenMP01>\n");
+
+ n = estimate_3s_runtime_with_one_proc();
+ num_procs = omp_get_num_procs();
+ omp_set_num_threads(num_procs);
+
+ for (int i = 1; i <= num_procs; ++i) {
+ microbench(i, n);
+ }
+
+ printf("</SMPOpenMP01>\n");
+}
+
+#ifdef __rtems__
+
+static void Init(rtems_task_argument arg)
+{
+ rtems_status_code sc;
+ cpu_set_t cpu_set;
+
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+
+ CPU_ZERO(&cpu_set);
+ CPU_SET(0, &cpu_set);
+
+ sc = rtems_task_set_affinity(RTEMS_SELF, sizeof(cpu_set), &cpu_set);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ test();
+ TEST_END();
+ rtems_test_exit(0);
+}
+
+typedef struct {
+ pthread_mutex_t mtx;
+ pthread_cond_t cnd;
+ bool cpus_used[CPU_COUNT_MAX];
+} test_context;
+
+static test_context test_instance;
+
+static uint32_t find_free_cpu(test_context *ctx)
+{
+ uint32_t i;
+ uint32_t n;
+
+ n = rtems_get_processor_count();
+
+ pthread_mutex_lock(&ctx->mtx);
+
+ do {
+ for (i = 1; i < n; ++i) {
+ if (!ctx->cpus_used[i]) {
+ ctx->cpus_used[i] = true;
+ break;
+ }
+ }
+
+ if (i == n) {
+ pthread_cond_wait(&ctx->cnd, &ctx->mtx);
+ }
+ } while (i == n);
+
+ pthread_mutex_unlock(&ctx->mtx);
+
+ return i;
+}
+
+static void begin_extension(Thread_Control *th)
+{
+ rtems_id th_id;
+
+ th_id = th->Object.id;
+
+ if (rtems_object_id_get_api(th_id) == OBJECTS_POSIX_API) {
+ rtems_status_code sc;
+ rtems_id sched_id;
+ uint32_t cpu_index;
+ cpu_set_t cpu_set;
+ rtems_task_priority prio;
+
+ cpu_index = find_free_cpu(&test_instance);
+
+ sc = rtems_scheduler_ident_by_processor(cpu_index, &sched_id);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_set_priority(th_id, RTEMS_CURRENT_PRIORITY, &prio);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ sc = rtems_task_set_scheduler(th_id, sched_id, prio);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ CPU_ZERO(&cpu_set);
+ CPU_SET((int) cpu_index, &cpu_set);
+
+ sc = rtems_task_set_affinity(th_id, sizeof(cpu_set), &cpu_set);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ }
+}
+
+static void terminate_extension(Thread_Control *th)
+{
+ rtems_id th_id;
+
+ th_id = th->Object.id;
+
+ if (rtems_object_id_get_api(th_id) == OBJECTS_POSIX_API) {
+ rtems_status_code sc;
+ cpu_set_t cpu_set;
+ uint32_t cpu_index;
+ test_context *ctx;
+
+ sc = rtems_task_get_affinity(th_id, sizeof(cpu_set), &cpu_set);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ cpu_index = CPU_FFS(&cpu_set) - 1;
+
+ ctx = &test_instance;
+
+ pthread_mutex_lock(&ctx->mtx);
+ rtems_test_assert(ctx->cpus_used[cpu_index]);
+ ctx->cpus_used[cpu_index] = false;
+ pthread_cond_broadcast(&ctx->cnd);
+ pthread_mutex_unlock(&ctx->mtx);
+ }
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT_MAX
+
+#define CONFIGURE_UNLIMITED_OBJECTS
+#define CONFIGURE_UNIFIED_WORK_AREAS
+
+#define CONFIGURE_INITIAL_EXTENSIONS \
+ { \
+ .thread_begin = begin_extension, \
+ .thread_terminate = terminate_extension \
+ }, \
+ RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
+
+#else /* __rtems__ */
+
+int main(void)
+{
+ test();
+ return 0;
+}
+
+#endif /* __rtems__ */
diff --git a/testsuites/smptests/smpopenmp01/smpopenmp01.doc b/testsuites/smptests/smpopenmp01/smpopenmp01.doc
new file mode 100644
index 0000000000..688cccd03a
--- /dev/null
+++ b/testsuites/smptests/smpopenmp01/smpopenmp01.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: smpopenmp01
+
+directives:
+
+ - None
+
+concepts:
+
+ - OpenMP micro benchmark.
diff --git a/testsuites/smptests/smpopenmp01/smpopenmp01.py b/testsuites/smptests/smpopenmp01/smpopenmp01.py
new file mode 100644
index 0000000000..139aedd4af
--- /dev/null
+++ b/testsuites/smptests/smpopenmp01/smpopenmp01.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2017 embedded brains GmbH. All rights reserved.
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+import re
+import libxml2
+from libxml2 import xmlNode
+import matplotlib.pyplot as plt
+data = open('smpopenmp01.scn').read()
+data = re.sub(r'\*\*\*.*', '', data)
+doc = libxml2.parseDoc(data)
+ctx = doc.xpathNewContext()
+
+plt.title('OpenMP Microbench')
+plt.xlabel('Number of Threads')
+plt.ylabel('Relative Duration')
+
+def m(n):
+ return float(n.getContent())
+
+def p(bench):
+ d = map(m, ctx.xpathEval('/SMPOpenMP01/Microbench/' + bench))
+ y = [x / d[0] for x in d]
+ x = range(1, len(y) + 1)
+ plt.xticks(x)
+ plt.plot(x, y, label = bench, marker = 'o')
+
+p('BarrierBench')
+p('ParallelBench')
+p('StaticBench')
+p('DynamicBench')
+p('GuidedBench')
+p('RuntimeBench')
+p('SingleBench')
+plt.legend(loc = 'best')
+plt.show()
diff --git a/testsuites/smptests/smpopenmp01/smpopenmp01.scn b/testsuites/smptests/smpopenmp01/smpopenmp01.scn
new file mode 100644
index 0000000000..9a21ff5a9a
--- /dev/null
+++ b/testsuites/smptests/smpopenmp01/smpopenmp01.scn
@@ -0,0 +1,81 @@
+*** BEGIN OF TEST SMPOPENMP 1 ***
+*** TEST VERSION: 5.0.0.4c8cffc19865eaa3b033ce2776bcce9992f24b18
+*** TEST STATE: EXPECTED-PASS
+*** TEST BUILD: RTEMS_POSIX_API RTEMS_SMP
+*** TEST TOOLS: 7.3.0 20180125 (RTEMS 5, RSB 6d9c77c77d271d1fc2dfe8493d6713930b52a6dd, Newlib 3.0.0)
+<SMPOpenMP01>
+ <Microbench numThreads="1" majorLoopCount="20">
+ <BarrierBench unit="s">0.720318</BarrierBench>
+ <ParallelBench unit="s">1.121403</ParallelBench>
+ <StaticBench unit="s">0.059288</StaticBench>
+ <DynamicBench unit="s">0.440113</DynamicBench>
+ <GuidedBench unit="s">0.003230</GuidedBench>
+ <RuntimeBench unit="s">0.440121</RuntimeBench>
+ <SingleBench unit="s">0.116486</SingleBench>
+ </Microbench>
+ <Microbench numThreads="2" majorLoopCount="20">
+ <BarrierBench unit="s">0.416734</BarrierBench>
+ <ParallelBench unit="s">0.259013</ParallelBench>
+ <StaticBench unit="s">0.015311</StaticBench>
+ <DynamicBench unit="s">0.196751</DynamicBench>
+ <GuidedBench unit="s">0.002367</GuidedBench>
+ <RuntimeBench unit="s">0.199640</RuntimeBench>
+ <SingleBench unit="s">0.077629</SingleBench>
+ </Microbench>
+ <Microbench numThreads="3" majorLoopCount="20">
+ <BarrierBench unit="s">0.748332</BarrierBench>
+ <ParallelBench unit="s">0.387318</ParallelBench>
+ <StaticBench unit="s">0.021244</StaticBench>
+ <DynamicBench unit="s">0.141558</DynamicBench>
+ <GuidedBench unit="s">0.001544</GuidedBench>
+ <RuntimeBench unit="s">0.142693</RuntimeBench>
+ <SingleBench unit="s">0.117683</SingleBench>
+ </Microbench>
+ <Microbench numThreads="4" majorLoopCount="20">
+ <BarrierBench unit="s">0.552830</BarrierBench>
+ <ParallelBench unit="s">0.323241</ParallelBench>
+ <StaticBench unit="s">0.017796</StaticBench>
+ <DynamicBench unit="s">0.099475</DynamicBench>
+ <GuidedBench unit="s">0.001259</GuidedBench>
+ <RuntimeBench unit="s">0.100053</RuntimeBench>
+ <SingleBench unit="s">0.091069</SingleBench>
+ </Microbench>
+ <Microbench numThreads="5" majorLoopCount="20">
+ <BarrierBench unit="s">0.882791</BarrierBench>
+ <ParallelBench unit="s">0.452561</ParallelBench>
+ <StaticBench unit="s">0.023620</StaticBench>
+ <DynamicBench unit="s">0.094107</DynamicBench>
+ <GuidedBench unit="s">0.000989</GuidedBench>
+ <RuntimeBench unit="s">0.093911</RuntimeBench>
+ <SingleBench unit="s">0.130070</SingleBench>
+ </Microbench>
+ <Microbench numThreads="6" majorLoopCount="20">
+ <BarrierBench unit="s">0.670385</BarrierBench>
+ <ParallelBench unit="s">0.393587</ParallelBench>
+ <StaticBench unit="s">0.021141</StaticBench>
+ <DynamicBench unit="s">0.072322</DynamicBench>
+ <GuidedBench unit="s">0.000937</GuidedBench>
+ <RuntimeBench unit="s">0.069804</RuntimeBench>
+ <SingleBench unit="s">0.104107</SingleBench>
+ </Microbench>
+ <Microbench numThreads="7" majorLoopCount="20">
+ <BarrierBench unit="s">1.031511</BarrierBench>
+ <ParallelBench unit="s">0.466571</ParallelBench>
+ <StaticBench unit="s">0.024944</StaticBench>
+ <DynamicBench unit="s">0.069194</DynamicBench>
+ <GuidedBench unit="s">0.000814</GuidedBench>
+ <RuntimeBench unit="s">0.069596</RuntimeBench>
+ <SingleBench unit="s">0.133137</SingleBench>
+ </Microbench>
+ <Microbench numThreads="8" majorLoopCount="20">
+ <BarrierBench unit="s">0.761015</BarrierBench>
+ <ParallelBench unit="s">0.452577</ParallelBench>
+ <StaticBench unit="s">0.023979</StaticBench>
+ <DynamicBench unit="s">0.061193</DynamicBench>
+ <GuidedBench unit="s">0.000799</GuidedBench>
+ <RuntimeBench unit="s">0.061519</RuntimeBench>
+ <SingleBench unit="s">0.114285</SingleBench>
+ </Microbench>
+</SMPOpenMP01>
+
+*** END OF TEST SMPOPENMP 1 ***