Compare commits
105 changed files with 11292 additions and 3505 deletions
123
CLANG_default.mk
Normal file
123
CLANG_default.mk
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
# Basic Defintions for using GNU-compiler suite sequentially
|
||||||
|
# requires setting of COMPILER=CLANG_
|
||||||
|
|
||||||
|
#CLANGPATH=//usr/lib/llvm-10/bin/
|
||||||
|
CC = ${CLANGPATH}clang
|
||||||
|
CXX = ${CLANGPATH}clang++
|
||||||
|
#CXX = ${CLANGPATH}clang++ -lomptarget -fopenmp-targets=nvptx64-nvidia-cuda --cuda-path=/opt/pgi/linux86-64/2017/cuda/8.0
|
||||||
|
#F77 = gfortran
|
||||||
|
LINKER = ${CXX}
|
||||||
|
|
||||||
|
#http://clang.llvm.org/docs/UsersManual.html#options-to-control-error-and-warning-messages
|
||||||
|
WARNINGS += -Weverything -Wno-c++98-compat -Wno-sign-conversion -Wno-date-time -Wno-shorten-64-to-32 -Wno-padded -ferror-limit=1
|
||||||
|
WARNINGS += -Wdocumentation -Wconversion -Wshadow -Wfloat-conversion -pedantic
|
||||||
|
#-fsyntax-only -Wdocumentation -Wconversion -Wshadow -Wfloat-conversion -pedantic
|
||||||
|
|
||||||
|
CXXFLAGS += -O3 -std=c++17 -ferror-limit=1 ${WARNINGS}
|
||||||
|
# don't use -Ofast
|
||||||
|
# -ftrapv
|
||||||
|
LINKFLAGS += -O3
|
||||||
|
|
||||||
|
# different libraries in Ubuntu or manajaró
|
||||||
|
ifndef UBUNTU
|
||||||
|
UBUNTU=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
# BLAS, LAPACK
|
||||||
|
LINKFLAGS += -llapack -lblas
|
||||||
|
# -lopenblas
|
||||||
|
ifeq ($(UBUNTU),1)
|
||||||
|
# ubuntu
|
||||||
|
else
|
||||||
|
# on archlinux
|
||||||
|
LINKFLAGS += -lcblas
|
||||||
|
endif
|
||||||
|
|
||||||
|
# interprocedural optimization
|
||||||
|
CXXFLAGS += -flto
|
||||||
|
LINKFLAGS += -flto
|
||||||
|
|
||||||
|
# very good check
|
||||||
|
# http://clang.llvm.org/extra/clang-tidy/
|
||||||
|
# good check, see: http://llvm.org/docs/CodingStandards.html#include-style
|
||||||
|
SWITCH_OFF=,-readability-magic-numbers,-readability-redundant-control-flow,-readability-redundant-member-init
|
||||||
|
SWITCH_OFF+=,-readability-redundant-member-init,-readability-isolate-declaration
|
||||||
|
#READABILITY=,readability*${SWITCH_OFF}
|
||||||
|
#TIDYFLAGS = -checks=llvm-*,-llvm-header-guard -header-filter=.* -enable-check-profile -extra-arg="-std=c++17" -extra-arg="-fopenmp"
|
||||||
|
TIDYFLAGS = -checks=llvm-*,-llvm-header-guard${READABILITY} -header-filter=.* -enable-check-profile -extra-arg="-std=c++17" -extra-arg="-fopenmp"
|
||||||
|
#TIDYFLAGS += -checks='modernize*
|
||||||
|
# ???
|
||||||
|
#TIDYFLAGS = -checks='cert*' -header-filter=.*
|
||||||
|
# MPI checks ??
|
||||||
|
#TIDYFLAGS = -checks='mpi*'
|
||||||
|
# ??
|
||||||
|
#TIDYFLAGS = -checks='performance*' -header-filter=.*
|
||||||
|
#TIDYFLAGS = -checks='portability-*' -header-filter=.*
|
||||||
|
#TIDYFLAGS = -checks='readability-*' -header-filter=.*
|
||||||
|
|
||||||
|
default: ${PROGRAM}
|
||||||
|
|
||||||
|
${PROGRAM}: ${OBJECTS}
|
||||||
|
$(LINKER) $^ ${LINKFLAGS} -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f ${PROGRAM} ${OBJECTS}
|
||||||
|
|
||||||
|
clean_all:: clean
|
||||||
|
@rm -f *_ *~ *.bak *.log *.out *.tar
|
||||||
|
|
||||||
|
codecheck: tidy_check
|
||||||
|
tidy_check:
|
||||||
|
clang-tidy ${SOURCES} ${TIDYFLAGS} -- ${SOURCES}
|
||||||
|
# see also http://clang-developers.42468.n3.nabble.com/Error-while-trying-to-load-a-compilation-database-td4049722.html
|
||||||
|
|
||||||
|
run: clean ${PROGRAM}
|
||||||
|
# time ./${PROGRAM} ${PARAMS}
|
||||||
|
./${PROGRAM} ${PARAMS}
|
||||||
|
|
||||||
|
# tar the current directory
|
||||||
|
MY_DIR = `basename ${PWD}`
|
||||||
|
tar: clean_all
|
||||||
|
@echo "Tar the directory: " ${MY_DIR}
|
||||||
|
@cd .. ;\
|
||||||
|
tar cf ${MY_DIR}.tar ${MY_DIR} *default.mk ;\
|
||||||
|
cd ${MY_DIR}
|
||||||
|
# tar cf `basename ${PWD}`.tar *
|
||||||
|
|
||||||
|
doc:
|
||||||
|
doxygen Doxyfile
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
.f.o:
|
||||||
|
$(F77) -c $(FFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
##################################################################################################
|
||||||
|
# some tools
|
||||||
|
# Cache behaviour (CXXFLAGS += -g tracks down to source lines; no -pg in linkflags)
|
||||||
|
cache: ${PROGRAM}
|
||||||
|
valgrind --tool=callgrind --simulate-cache=yes ./$^ ${PARAMS}
|
||||||
|
# kcachegrind callgrind.out.<pid> &
|
||||||
|
kcachegrind `ls -1tr callgrind.out.* |tail -1`
|
||||||
|
|
||||||
|
# Check for wrong memory accesses, memory leaks, ...
|
||||||
|
# use smaller data sets
|
||||||
|
mem: ${PROGRAM}
|
||||||
|
valgrind -v --leak-check=yes --tool=memcheck --undef-value-errors=yes --track-origins=yes --log-file=$^.addr.out --show-reachable=yes ./$^ ${PARAMS}
|
||||||
|
|
||||||
|
# Simple run time profiling of your code
|
||||||
|
# CXXFLAGS += -g -pg
|
||||||
|
# LINKFLAGS += -pg
|
||||||
|
prof: ${PROGRAM}
|
||||||
|
perf record ./$^ ${PARAMS}
|
||||||
|
perf report
|
||||||
|
# gprof -b ./$^ > gp.out
|
||||||
|
# kprof -f gp.out -p gprof &
|
||||||
|
|
||||||
|
codecheck: tidy_check
|
||||||
196
GCC_default.mk
Normal file
196
GCC_default.mk
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
# Basic Defintions for using GNU-compiler suite sequentially
|
||||||
|
# requires setting of COMPILER=GCC_
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
F77 = gfortran
|
||||||
|
LINKER = ${CXX}
|
||||||
|
|
||||||
|
WARNINGS = -Wall -pedantic -Wextra -Weffc++ -Woverloaded-virtual -Wfloat-equal -Wshadow \
|
||||||
|
-Wredundant-decls -fmax-errors=1
|
||||||
|
# -Wunreachable-code -Winline
|
||||||
|
CXXFLAGS += -ffast-math -O3 -march=native -std=c++17 ${WARNINGS}
|
||||||
|
#CXXFLAGS += -Ofast -funroll-all-loops -std=c++17 ${WARNINGS}
|
||||||
|
#-msse3
|
||||||
|
# -ftree-vectorizer-verbose=2 -DNDEBUG
|
||||||
|
# -ftree-vectorizer-verbose=5
|
||||||
|
# -ftree-vectorize -fdump-tree-vect-blocks=foo.dump -fdump-tree-pre=stderr
|
||||||
|
|
||||||
|
# CFLAGS = -ffast-math -O3 -DNDEBUG -msse3 -fopenmp -fdump-tree-vect-details
|
||||||
|
# CFLAGS = -ffast-math -O3 -funroll-loops -DNDEBUG -msse3 -fopenmp -ftree-vectorizer-verbose=2
|
||||||
|
# #CFLAGS = -ffast-math -O3 -DNDEBUG -msse3 -fopenmp
|
||||||
|
# FFLAGS = -ffast-math -O3 -DNDEBUG -msse3 -fopenmp
|
||||||
|
# LFLAGS = -ffast-math -O3 -DNDEBUG -msse3 -fopenmp
|
||||||
|
LINKFLAGS += -O3
|
||||||
|
|
||||||
|
#architecture
|
||||||
|
#CPU = -march=znver2
|
||||||
|
CXXFLAGS += ${CPU}
|
||||||
|
LINKFLAGS += ${CPU}
|
||||||
|
|
||||||
|
# different libraries in Ubuntu or manajaró
|
||||||
|
ifndef UBUNTU
|
||||||
|
UBUNTU=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
# BLAS, LAPACK
|
||||||
|
ifeq ($(UBUNTU),1)
|
||||||
|
LINKFLAGS += -llapack -lblas
|
||||||
|
# -lopenblas
|
||||||
|
else
|
||||||
|
# on archlinux
|
||||||
|
LINKFLAGS += -llapack -lopenblas -lcblas
|
||||||
|
endif
|
||||||
|
|
||||||
|
# interprocedural optimization
|
||||||
|
#CXXFLAGS += -flto
|
||||||
|
#LINKFLAGS += -flto
|
||||||
|
|
||||||
|
# for debugging purpose (save code)
|
||||||
|
# -fsanitize=leak # only one out the three can be used
|
||||||
|
# -fsanitize=address
|
||||||
|
# -fsanitize=thread
|
||||||
|
SANITARY = -fsanitize=address -fsanitize=undefined -fsanitize=null -fsanitize=return \
|
||||||
|
-fsanitize=bounds -fsanitize=alignment -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow \
|
||||||
|
-fsanitize=bool -fsanitize=enum -fsanitize=vptr
|
||||||
|
#CXXFLAGS += ${SANITARY}
|
||||||
|
#LINKFLAGS += ${SANITARY}
|
||||||
|
|
||||||
|
# profiling tools
|
||||||
|
#CXXFLAGS += -pg
|
||||||
|
#LINKFLAGS += -pg
|
||||||
|
|
||||||
|
|
||||||
|
default: ${PROGRAM}
|
||||||
|
|
||||||
|
${PROGRAM}: ${OBJECTS}
|
||||||
|
$(LINKER) $^ ${LINKFLAGS} -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f ${PROGRAM} ${OBJECTS}
|
||||||
|
|
||||||
|
clean_all:: clean
|
||||||
|
-@rm -f *_ *~ *.bak *.log *.out *.tar *.orig *.optrpt
|
||||||
|
-@rm -rf html
|
||||||
|
|
||||||
|
run: clean ${PROGRAM}
|
||||||
|
#run: ${PROGRAM}
|
||||||
|
# time ./${PROGRAM} ${PARAMS}
|
||||||
|
./${PROGRAM} ${PARAMS}
|
||||||
|
|
||||||
|
# tar the current directory
|
||||||
|
MY_DIR = `basename ${PWD}`
|
||||||
|
tar: clean_all
|
||||||
|
@echo "Tar the directory: " ${MY_DIR}
|
||||||
|
@cd .. ;\
|
||||||
|
tar cf ${MY_DIR}.tar ${MY_DIR} *default.mk ;\
|
||||||
|
cd ${MY_DIR}
|
||||||
|
# tar cf `basename ${PWD}`.tar *
|
||||||
|
#find . -size +10M > large_files
|
||||||
|
#--exclude-from ${MY_DIR}/large_files
|
||||||
|
|
||||||
|
zip: clean
|
||||||
|
@echo "Zip the directory: " ${MY_DIR}
|
||||||
|
@cd .. ;\
|
||||||
|
zip -r ${MY_DIR}.zip ${MY_DIR} *default.mk ;\
|
||||||
|
cd ${MY_DIR}
|
||||||
|
|
||||||
|
doc:
|
||||||
|
doxygen Doxyfile
|
||||||
|
|
||||||
|
#########################################################################
|
||||||
|
.SUFFIXES: .f90
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||||
|
# $(CXX) -c $(CXXFLAGS) -o $@ $< 2>&1 | tee -a $<.log
|
||||||
|
# $(CXX) -c $(CXXFLAGS) -o $@ $< 2>&1 | tee -a $(<:.cpp=.log)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
.f.o:
|
||||||
|
$(F77) -c $(FFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
.f90.o:
|
||||||
|
$(F77) -c $(FFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
##################################################################################################
|
||||||
|
# some tools
|
||||||
|
# Cache behaviour (CXXFLAGS += -g tracks down to source lines; no -pg in linkflags)
|
||||||
|
cache: ${PROGRAM}
|
||||||
|
valgrind --tool=callgrind --simulate-cache=yes ./$^ ${PARAMS}
|
||||||
|
# kcachegrind callgrind.out.<pid> &
|
||||||
|
kcachegrind `ls -1tr callgrind.out.* |tail -1`
|
||||||
|
|
||||||
|
# Check for wrong memory accesses, memory leaks, ...
|
||||||
|
# use smaller data sets
|
||||||
|
# no "-pg" in compile/link options
|
||||||
|
mem: ${PROGRAM}
|
||||||
|
valgrind -v --leak-check=yes --tool=memcheck --undef-value-errors=yes --track-origins=yes --log-file=$^.addr.out --show-reachable=yes ./$^ ${PARAMS}
|
||||||
|
# Graphical interface
|
||||||
|
# valkyrie
|
||||||
|
|
||||||
|
# Simple run time profiling of your code
|
||||||
|
CXXFLAGS += -g -pg
|
||||||
|
LINKFLAGS += -pg
|
||||||
|
prof: ${PROGRAM}
|
||||||
|
./$^ ${PARAMS}
|
||||||
|
gprof -b ./$^ > gp.out
|
||||||
|
# kprof -f gp.out -p gprof &
|
||||||
|
|
||||||
|
# sudo apt install gprofng-gui
|
||||||
|
# https://parallel.computer/presentations/PPoPP2023/2023-Ruud-Slides.pdf
|
||||||
|
# read §3 in https://sourceware.org/binutils/docs/gprofng.html
|
||||||
|
# /usr/bin/gp-collect-app -o test.1.er -p on -S on /home/ghaase/Lectures/Math2CPP/Codes/seq/jacobi_oo_stl/main.GCC_
|
||||||
|
prof2: ${PROGRAM}
|
||||||
|
gprofng collect app -h auto ./$^ ${PARAMS}
|
||||||
|
# gprofng display text -functions `ls -1tdr test.*.er |tail -1`
|
||||||
|
gprofng display text -script gprofng_script2 `ls -1tdr test.*.er |tail -1`
|
||||||
|
# gprofng display text -script gprofng_script2 test.*.er
|
||||||
|
# gprofng display gui &
|
||||||
|
|
||||||
|
prof3: ${PROGRAM}
|
||||||
|
perf record ./$^ ${PARAMS}
|
||||||
|
perf report
|
||||||
|
# perf in Ubuntu 20.04: https://www.howtoforge.com/how-to-install-perf-performance-analysis-tool-on-ubuntu-20-04/
|
||||||
|
# * install
|
||||||
|
# * sudo vi /etc/sysctl.conf
|
||||||
|
# add kernel.perf_event_paranoid = 0
|
||||||
|
|
||||||
|
#Trace your heap:
|
||||||
|
#> heaptrack ./main.GCC_
|
||||||
|
#> heaptrack_gui heaptrack.main.GCC_.<pid>.gz
|
||||||
|
heap: ${PROGRAM}
|
||||||
|
heaptrack ./$^ ${PARAMS}
|
||||||
|
heaptrack_gui `ls -1tr heaptrack.$^.* |tail -1` &
|
||||||
|
|
||||||
|
codecheck: $(SOURCES)
|
||||||
|
cppcheck --enable=all --inconclusive --std=c++17 --suppress=missingIncludeSystem $^
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# get the detailed status of all optimization flags
|
||||||
|
info:
|
||||||
|
echo "detailed status of all optimization flags"
|
||||||
|
$(CXX) --version
|
||||||
|
$(CXX) -Q $(CXXFLAGS) --help=optimizers
|
||||||
|
lscpu
|
||||||
|
inxi -C
|
||||||
|
lstopo
|
||||||
|
|
||||||
|
# Excellent hardware info
|
||||||
|
# hardinfo
|
||||||
|
# Life monitoring of CPU frequency etc.
|
||||||
|
# sudo i7z
|
||||||
|
|
||||||
|
# Memory consumption
|
||||||
|
# vmstat -at -SM 3
|
||||||
|
# xfce4-taskmanager
|
||||||
|
|
||||||
|
|
||||||
|
# https://www.tecmint.com/check-linux-cpu-information/
|
||||||
|
#https://www.tecmint.com/monitor-cpu-and-gpu-temperature-in-ubuntu/
|
||||||
|
|
||||||
|
# Debugging:
|
||||||
|
# https://wiki.archlinux.org/index.php/Debugging
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
//#####################################
|
|
||||||
// G.Haase
|
|
||||||
// See https://sourceforge.net/p/predef/wiki/Compilers/
|
|
||||||
// http://www.cplusplus.com/doc/tutorial/preprocessor/
|
|
||||||
// also: export OMP_DISPLAY_ENV=VERBOSE
|
|
||||||
//#####################################
|
|
||||||
/** Checks for compilers, its versions, threads etc.
|
|
||||||
*
|
|
||||||
@param[in] argc number of command line arguemnts
|
|
||||||
@param[in] argv command line arguments as array of C-strings
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
void check_env(T argc, char const *argv[])
|
|
||||||
{
|
|
||||||
std::cout << "\n#######################################################################\n";
|
|
||||||
std::cout << "Code :";
|
|
||||||
for (T k = 0; k < argc; ++k) std::cout << " " << argv[k];
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
// compiler: https://sourceforge.net/p/predef/wiki/Compilers/
|
|
||||||
std::cout << "Compiler: ";
|
|
||||||
#if defined __INTEL_COMPILER
|
|
||||||
#pragma message(" ########## INTEL ###############")
|
|
||||||
std::cout << "INTEL " << __INTEL_COMPILER;
|
|
||||||
// Ignore warnings for #pragma acc unrecognice
|
|
||||||
#pragma warning disable 161
|
|
||||||
// Ignore warnings for #pragma omp unrecognice
|
|
||||||
#pragma warning disable 3180
|
|
||||||
|
|
||||||
#elif defined __PGI
|
|
||||||
#pragma message(" ########## PGI ###############")
|
|
||||||
std::cout << "PGI " << __PGIC__ << "." << __PGIC_MINOR__ << "." << __PGIC_PATCHLEVEL__;
|
|
||||||
#elif defined __clang__
|
|
||||||
#pragma message(" ########## CLANG ###############")
|
|
||||||
std::cout << "CLANG " << __clang_major__ << "." << __clang_minor__ << "."; // << __clang_patchlevel__;
|
|
||||||
#elif defined __GNUC__
|
|
||||||
#pragma message(" ########## Gnu ###############")
|
|
||||||
std::cout << "Gnu " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
|
|
||||||
#else
|
|
||||||
#pragma message(" ########## unknown Compiler ###############")
|
|
||||||
std::cout << "unknown";
|
|
||||||
#endif
|
|
||||||
std::cout << " C++ standard: " << __cplusplus << std::endl;
|
|
||||||
|
|
||||||
// Parallel environments
|
|
||||||
std::cout << "Parallel: ";
|
|
||||||
#if defined MPI_VERSION
|
|
||||||
#pragma message(" ########## MPI ###############")
|
|
||||||
#ifdef OPEN_MPI
|
|
||||||
std::cout << "OpenMPI ";
|
|
||||||
#else
|
|
||||||
std::cout << "MPI ";
|
|
||||||
#endif
|
|
||||||
std::cout << MPI_VERSION << "." << MPI_SUBVERSION << " ";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
//https://www.openmp.org/specifications/
|
|
||||||
//https://stackoverflow.com/questions/1304363/how-to-check-the-version-of-openmp-on-linux
|
|
||||||
std::unordered_map<unsigned, std::string> const map{
|
|
||||||
{200505, "2.5"}, {200805, "3.0"}, {201107, "3.1"}, {201307, "4.0"}, {201511, "4.5"}, {201611, "5.0"}, {201811, "5.0"}};
|
|
||||||
#pragma message(" ########## OPENMP ###############")
|
|
||||||
//std::cout << _OPENMP;
|
|
||||||
std::cout << "OpenMP ";
|
|
||||||
try {
|
|
||||||
std::cout << map.at(_OPENMP);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
std::cout << _OPENMP;
|
|
||||||
}
|
|
||||||
#pragma omp parallel
|
|
||||||
{
|
|
||||||
#pragma omp master
|
|
||||||
{
|
|
||||||
const int nn = omp_get_num_threads(); // OpenMP
|
|
||||||
std::cout << " ---> " << nn << " Threads ";
|
|
||||||
}
|
|
||||||
#pragma omp barrier
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#ifdef _OPENACC
|
|
||||||
#pragma message(" ########## OPENACC ###############")
|
|
||||||
std::cout << "OpenACC ";
|
|
||||||
#endif
|
|
||||||
std::cout << std::endl;
|
|
||||||
std::cout << "Date : " << __DATE__ << " " << __TIME__;
|
|
||||||
std::cout << "\n#######################################################################\n";
|
|
||||||
}
|
|
||||||
// HG
|
|
||||||
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
#include "check_env.h"
|
|
||||||
#include "mylib.h"
|
|
||||||
#include <cstdlib> // atoi()
|
|
||||||
#include <cstring> // strncmp()
|
|
||||||
#include <ctime>
|
|
||||||
#include <iostream>
|
|
||||||
#include <omp.h> // OpenMP
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main(int argc, char const *argv[])
|
|
||||||
{
|
|
||||||
omp_set_schedule(omp_sched_static, 2000000);
|
|
||||||
//omp_set_schedule(omp_sched_dynamic, 1000000);
|
|
||||||
//omp_set_schedule(omp_sched_guided, 1000000);
|
|
||||||
//omp_set_schedule(omp_sched_auto, 1); // chunk size does not matter for auto
|
|
||||||
|
|
||||||
|
|
||||||
// Speedup for different number of cores (incl. hyperthreading)
|
|
||||||
omp_set_num_threads(8);
|
|
||||||
|
|
||||||
// Print number of available processors
|
|
||||||
cout << "Number of available processors: " << omp_get_num_procs() << endl;
|
|
||||||
|
|
||||||
// Currently executing parallel code? -> no
|
|
||||||
cout << "Currently in parallel? " << omp_in_parallel() << endl;
|
|
||||||
|
|
||||||
|
|
||||||
int const NLOOPS = 10; // chose a value such that the benchmark runs at least 10 sec.
|
|
||||||
unsigned int N = 500000001;
|
|
||||||
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
// Read Parameter from command line (C++ style)
|
|
||||||
cout << "Checking command line parameters for: -n <number> " << endl;
|
|
||||||
for (int i = 1; i < argc; i++)
|
|
||||||
{
|
|
||||||
cout << " arg[" << i << "] = " << argv[i] << endl;
|
|
||||||
string ss(argv[i]);
|
|
||||||
if ("-n"==ss && i + 1 < argc) // found "-n" followed by another parameter
|
|
||||||
{
|
|
||||||
N = static_cast<unsigned int>(atoi(argv[i + 1]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cout << "Corect call: " << argv[0] << " -n <number>\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "\nN = " << N << endl;
|
|
||||||
|
|
||||||
check_env(argc, argv);
|
|
||||||
//########################################################################
|
|
||||||
int nthreads; // OpenMP
|
|
||||||
#pragma omp parallel default(none) shared(cout,nthreads)
|
|
||||||
{
|
|
||||||
stringstream inparallel;
|
|
||||||
inparallel << "Currently in parallel? " << omp_in_parallel() << endl;
|
|
||||||
|
|
||||||
|
|
||||||
int const th_id = omp_get_thread_num(); // OpenMP
|
|
||||||
int const nthrds = omp_get_num_threads(); // OpenMP
|
|
||||||
stringstream ss;
|
|
||||||
ss << "C++: Hello World from thread " << th_id << " / " << nthrds << endl;
|
|
||||||
#pragma omp critical
|
|
||||||
{
|
|
||||||
cout << ss.str(); // output to a shared ressource
|
|
||||||
cout << inparallel.str() << endl;
|
|
||||||
}
|
|
||||||
#pragma omp master
|
|
||||||
nthreads = nthrds; // transfer nn to to master thread
|
|
||||||
}
|
|
||||||
cout << " " << nthreads << " threads have been started." << endl;
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
// Memory allocation
|
|
||||||
cout << "Memory allocation\n";
|
|
||||||
|
|
||||||
vector<double> x(N), y(N);
|
|
||||||
|
|
||||||
cout.precision(2);
|
|
||||||
cout << 2.0 * N *sizeof(x[0]) / 1024 / 1024 / 1024 << " GByte Memory allocated\n";
|
|
||||||
cout.precision(6);
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
// Data initialization
|
|
||||||
// Special: x_i = i+1; y_i = 1/x_i ==> <x,y> == N
|
|
||||||
for (unsigned int i = 0; i < N; ++i)
|
|
||||||
{
|
|
||||||
x[i] = i + 1;
|
|
||||||
y[i] = 1.0 / x[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
cout << "\nStart Benchmarking\n";
|
|
||||||
|
|
||||||
// Do calculation
|
|
||||||
double tstart = omp_get_wtime(); // OpenMP
|
|
||||||
|
|
||||||
double sk(0.0);
|
|
||||||
for (int i = 0; i < NLOOPS; ++i)
|
|
||||||
{
|
|
||||||
//sk = scalar(x, y);
|
|
||||||
sk = scalar_parallel(x, y);
|
|
||||||
//sk = scalar_trans(x, y);
|
|
||||||
//sk = norm(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
double t1 = omp_get_wtime() - tstart; // OpenMP
|
|
||||||
|
|
||||||
t1 /= NLOOPS; // divide by number of function calls
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
// Check the correct result
|
|
||||||
cout << "\n <x,y> = " << sk << endl;
|
|
||||||
if (static_cast<unsigned int>(sk) != N)
|
|
||||||
{
|
|
||||||
cout << " !! W R O N G result !!\n";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
//##########################################################################
|
|
||||||
// Timings and Performance
|
|
||||||
cout << endl;
|
|
||||||
cout.precision(2);
|
|
||||||
cout << "Total benchmarking time: " << t1*NLOOPS << endl;
|
|
||||||
cout << "Timing in sec. : " << t1 << endl;
|
|
||||||
cout << "GFLOPS : " << 2.0 * N / t1 / 1024 / 1024 / 1024 << endl;
|
|
||||||
cout << "GiByte/s : " << 2.0 * N / t1 / 1024 / 1024 / 1024 * sizeof(x[0]) << endl;
|
|
||||||
|
|
||||||
//#########################################################################
|
|
||||||
|
|
||||||
cout << "\n Try the reduction with an STL-vektor \n";
|
|
||||||
|
|
||||||
auto vr = reduction_vec_append(5);
|
|
||||||
cout << "done\n";
|
|
||||||
cout << vr << endl;
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} // memory for x and y will be deallocated their destructors
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
#include "mylib.h"
|
|
||||||
#include <cassert> // assert()
|
|
||||||
#include <cmath>
|
|
||||||
#include <iostream>
|
|
||||||
#include <functional> // multiplies<>{}
|
|
||||||
#include <list>
|
|
||||||
#include <numeric> // iota()
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#include <omp.h>
|
|
||||||
#endif
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
double scalar_parallel(vector<double> const &x, vector<double> const &y)
|
|
||||||
{
|
|
||||||
assert(x.size() == y.size()); // switch off via compile flag: -DNDEBUG
|
|
||||||
size_t const N = x.size();
|
|
||||||
double sum = 0.0;
|
|
||||||
#pragma omp parallel default(none) shared(x,y,N, cout) reduction(+:sum)
|
|
||||||
{
|
|
||||||
const size_t nthreads = omp_get_num_threads();
|
|
||||||
const size_t threadnum = omp_get_thread_num();
|
|
||||||
const size_t chunksize = N/nthreads;
|
|
||||||
|
|
||||||
|
|
||||||
size_t start = threadnum*chunksize;
|
|
||||||
size_t end = start + chunksize;
|
|
||||||
if (threadnum == nthreads - 1)
|
|
||||||
end = N;
|
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = start; i < end; ++i)
|
|
||||||
{
|
|
||||||
sum += x[i] * y[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vector<int> reduction_vec_append(int n)
|
|
||||||
{
|
|
||||||
vector<int> vec(n);
|
|
||||||
#pragma omp parallel default(none) shared(cout) reduction(VecAppend:vec)
|
|
||||||
{
|
|
||||||
#pragma omp barrier
|
|
||||||
#pragma omp critical
|
|
||||||
cout << omp_get_thread_num() << " : " << vec.size() << endl;
|
|
||||||
#pragma omp barrier
|
|
||||||
iota( vec.begin(),vec.end(), omp_get_thread_num() );
|
|
||||||
#pragma omp barrier
|
|
||||||
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
double scalar(vector<double> const &x, vector<double> const &y)
|
|
||||||
{
|
|
||||||
assert(x.size() == y.size()); // switch off via compile flag: -DNDEBUG
|
|
||||||
size_t const N = x.size();
|
|
||||||
double sum = 0.0;
|
|
||||||
#pragma omp parallel for default(none) shared(x,y,N) reduction(+:sum) schedule(runtime) // added schedule(runtime)
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
|
||||||
{
|
|
||||||
sum += x[i] * y[i];
|
|
||||||
//sum += exp(x[i])*log(y[i]);
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double norm(vector<double> const &x)
|
|
||||||
{
|
|
||||||
size_t const N = x.size();
|
|
||||||
double sum = 0.0;
|
|
||||||
#pragma omp parallel for default(none) shared(x,N) reduction(+:sum) schedule(runtime) // added schedule(runtime)
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
|
||||||
{
|
|
||||||
sum += x[i]*x[i];
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vector<int> reduction_vec(int n)
|
|
||||||
{
|
|
||||||
vector<int> vec(n);
|
|
||||||
#pragma omp parallel default(none) shared(cout) reduction(VecAdd:vec)
|
|
||||||
{
|
|
||||||
#pragma omp barrier
|
|
||||||
#pragma omp critical
|
|
||||||
cout << omp_get_thread_num() << " : " << vec.size() << endl;
|
|
||||||
#pragma omp barrier
|
|
||||||
iota( vec.begin(),vec.end(), omp_get_thread_num() );
|
|
||||||
#pragma omp barrier
|
|
||||||
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double scalar_trans(vector<double> const &x, vector<double> const &y)
|
|
||||||
{
|
|
||||||
assert(x.size() == y.size()); // switch off via compile flag: -DNDEBUG
|
|
||||||
vector<double> z(x.size());
|
|
||||||
//list<double> z(x.size()); // parallel for-loop on iterators not possible (missing 'operator-')
|
|
||||||
// c++-20 CLANG_, ONEAPI_:condition of OpenMP for loop must be a relational comparison
|
|
||||||
|
|
||||||
transform(cbegin(x),cend(x),cbegin(y),begin(z),std::multiplies<>{});
|
|
||||||
|
|
||||||
double sum = 0.0;
|
|
||||||
#pragma omp parallel for default(none) shared(z) reduction(+:sum) schedule(runtime) // added schedule(runtime)
|
|
||||||
for (auto pi = cbegin(z); pi!=cend(z); ++pi)
|
|
||||||
{
|
|
||||||
sum += *pi;
|
|
||||||
}
|
|
||||||
//for (auto val: z)
|
|
||||||
//{
|
|
||||||
//sum += val;
|
|
||||||
//}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <cassert>
|
|
||||||
#include <iomanip> // setw()
|
|
||||||
#include <iostream>
|
|
||||||
#include <omp.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/** Inner product
|
|
||||||
@param[in] x vector
|
|
||||||
@param[in] y vector
|
|
||||||
@return resulting Euclidian inner product <x,y>
|
|
||||||
*/
|
|
||||||
double scalar_parallel(std::vector<double> const &x, std::vector<double> const &y);
|
|
||||||
double scalar(std::vector<double> const &x, std::vector<double> const &y);
|
|
||||||
double scalar_trans(std::vector<double> const &x, std::vector<double> const &y);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Declare additional reduction operation in OpenMP for STL-vector
|
|
||||||
#pragma omp declare reduction(VecAppend : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end())) \
|
|
||||||
initializer (omp_priv=omp_orig)
|
|
||||||
|
|
||||||
std::vector<int> reduction_vec_append(int n);
|
|
||||||
|
|
||||||
|
|
||||||
/** l2-norm
|
|
||||||
@param[in] x vector
|
|
||||||
@return resulting Euclidian norm
|
|
||||||
*/
|
|
||||||
double norm(std::vector<double> const &x);
|
|
||||||
|
|
||||||
/** Vector @p b adds its elements to vector @p a .
|
|
||||||
@param[in] a vector
|
|
||||||
@param[in] b vector
|
|
||||||
@return a+=b componentwise
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
std::vector<T> &operator+=(std::vector<T> &a, std::vector<T> const &b)
|
|
||||||
{
|
|
||||||
assert(a.size()==b.size());
|
|
||||||
for (size_t k = 0; k < a.size(); ++k) {
|
|
||||||
a[k] += b[k];
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare the reduction operation in OpenMP for an STL-vector
|
|
||||||
// omp_out += omp_in requires operator+=(vector<int> &, vector<int> const &) from above
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// https://scc.ustc.edu.cn/zlsc/tc4600/intel/2016.0.109/compiler_c/common/core/GUID-7312910C-D175-4544-99C5-29C12D980744.htm
|
|
||||||
// https://gist.github.com/eruffaldi/7180bdec4c8c9a11f019dd0ba9a2d68c
|
|
||||||
// https://stackoverflow.com/questions/29633531/user-defined-reduction-on-vector-of-varying-size
|
|
||||||
// see also p.74ff in https://www.fz-juelich.de/ias/jsc/EN/AboutUs/Staff/Hagemeier_A/docs-parallel-programming/OpenMP-Slides.pdf
|
|
||||||
#pragma omp declare reduction(VecAdd : std::vector<int> : omp_out += omp_in) \
|
|
||||||
initializer (omp_priv=omp_orig)
|
|
||||||
|
|
||||||
// Templates are n o t possible, i.e. the reduction has to be declared fore a specified type.
|
|
||||||
//template <class T>
|
|
||||||
//#pragma omp declare reduction(VecAdd : std::vector<T> : omp_out += omp_in) initializer (omp_priv(omp_orig))
|
|
||||||
// MS: template nach #pragma !?
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Test for vector reduction.
|
|
||||||
*
|
|
||||||
* The thread-private vectors of size @p n are initialized via @f$v_k^{tID}=tID+k@f$.
|
|
||||||
* Afterwards these vectors are accumulated, i.e.,
|
|
||||||
* @f$v_k= \sum_{tID=0}^{numThreads} v_k^{tID}@f$.
|
|
||||||
*
|
|
||||||
* @param[in] n size of global/private vector
|
|
||||||
* @return resulting global vector.
|
|
||||||
*/
|
|
||||||
std::vector<int> reduction_vec(int n);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Output of a vector.
|
|
||||||
@param[in,out] s output stream
|
|
||||||
@param[in] x vector
|
|
||||||
@return modified output stream
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
std::ostream &operator<<(std::ostream &s, std::vector<T> const &x)
|
|
||||||
{
|
|
||||||
for (auto const &v : x) s << std::setw(4) << v << " ";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <chrono> // timing
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
using Clock = std::chrono::system_clock; //!< The wall clock timer chosen
|
|
||||||
//using Clock = std::chrono::high_resolution_clock;
|
|
||||||
using TPoint= std::chrono::time_point<Clock>;
|
|
||||||
|
|
||||||
// [Galowicz, C++17 STL Cookbook, p. 29]
|
|
||||||
inline
|
|
||||||
std::stack<TPoint> MyStopWatch; //!< starting time of stopwatch
|
|
||||||
|
|
||||||
/** Starts stopwatch timer.
|
|
||||||
* Use as @code tic(); myfunction(...) ; double tsec = toc(); @endcode
|
|
||||||
*
|
|
||||||
* The timining is allowed to be nested and the recent time is stored on top of the stack.
|
|
||||||
*
|
|
||||||
* @return recent time
|
|
||||||
* @see toc
|
|
||||||
*/
|
|
||||||
inline auto tic()
|
|
||||||
{
|
|
||||||
MyStopWatch.push(Clock::now());
|
|
||||||
return MyStopWatch.top();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the elapsed time from stopwatch.
|
|
||||||
*
|
|
||||||
* The time from top of the stack is used
|
|
||||||
* if time point @p t_b is not passed as input parameter.
|
|
||||||
* Use as @code tic(); myfunction(...) ; double tsec = toc(); @endcode
|
|
||||||
* or as @code auto t_b = tic(); myfunction(...) ; double tsec = toc(t_b); @endcode
|
|
||||||
* The last option is to be used in the case of
|
|
||||||
* non-nested but overlapping time measurements.
|
|
||||||
*
|
|
||||||
* @param[in] t_b start time of some stop watch
|
|
||||||
* @return elapsed time in seconds.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
inline double toc(TPoint const &t_b = MyStopWatch.top())
|
|
||||||
{
|
|
||||||
// https://en.cppreference.com/w/cpp/chrono/treat_as_floating_point
|
|
||||||
using Unit = std::chrono::seconds;
|
|
||||||
using FpSeconds = std::chrono::duration<double, Unit::period>;
|
|
||||||
auto t_e = Clock::now();
|
|
||||||
MyStopWatch.pop();
|
|
||||||
return FpSeconds(t_e-t_b).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
/** Executes function @p f and measures/prints elapsed wall clock time in seconds
|
|
||||||
*
|
|
||||||
* Call as
|
|
||||||
* @code measure("Time for (b = b + 1)", [&]() {
|
|
||||||
thrust::transform(b.begin(), b.end(), b.begin(), increment());
|
|
||||||
}); @endcode
|
|
||||||
*
|
|
||||||
* @param[in] label additional string to be printed with the measurement.
|
|
||||||
* @param[in] f function to execute.
|
|
||||||
* @author Therese Bösmüller, 2025
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
auto measure = [](const std::string& label, auto&& f) {
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
|
||||||
f();
|
|
||||||
auto stop = std::chrono::high_resolution_clock::now();
|
|
||||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count();
|
|
||||||
std::cout << label << ": " << duration << " microseconds" << std::endl;
|
|
||||||
}; // ';' is needed for a visible documentation of this lambda-function
|
|
||||||
Binary file not shown.
|
|
@ -1,130 +0,0 @@
|
||||||
#include "mylib.h"
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <omp.h>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// read vector from file
|
|
||||||
vector<size_t> data_vector = {};
|
|
||||||
|
|
||||||
ifstream input_stream("data_1.txt");
|
|
||||||
|
|
||||||
size_t line;
|
|
||||||
while(input_stream >> line)
|
|
||||||
{
|
|
||||||
data_vector.push_back(line);
|
|
||||||
}
|
|
||||||
data_vector.shrink_to_fit();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// specify loops
|
|
||||||
size_t NLOOPS = 10000;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ############# Parallelization with openMP #############
|
|
||||||
// calculate arithmetic mean, geometric mean and harmonic mean
|
|
||||||
double am_omp, gm_omp, hm_omp;
|
|
||||||
|
|
||||||
double tstart = omp_get_wtime();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < NLOOPS; ++i)
|
|
||||||
means_omp(data_vector, am_omp, gm_omp, hm_omp);
|
|
||||||
|
|
||||||
double t_means_omp = (omp_get_wtime() - tstart)/NLOOPS;
|
|
||||||
|
|
||||||
// calculate minimum and maximum
|
|
||||||
size_t min, max;
|
|
||||||
|
|
||||||
tstart = omp_get_wtime();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < NLOOPS; ++i)
|
|
||||||
minmax_omp(data_vector, min, max);
|
|
||||||
|
|
||||||
double t_minmax_omp = (omp_get_wtime() - tstart)/NLOOPS;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ############# Parallelization with C++ algorithms #############
|
|
||||||
// calculate arithmetic mean, geometric mean and harmonic mean
|
|
||||||
double am_cpp, gm_cpp, hm_cpp;
|
|
||||||
|
|
||||||
tstart = omp_get_wtime();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < NLOOPS; ++i)
|
|
||||||
means_cpp(data_vector, am_cpp, gm_cpp, hm_cpp);
|
|
||||||
|
|
||||||
double t_means_cpp = (omp_get_wtime() - tstart)/NLOOPS;
|
|
||||||
|
|
||||||
// calculate minimum and maximum
|
|
||||||
size_t min_cpp, max_cpp;
|
|
||||||
|
|
||||||
tstart = omp_get_wtime();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < NLOOPS; ++i)
|
|
||||||
minmax_cpp(data_vector, min_cpp, max_cpp);
|
|
||||||
|
|
||||||
double t_minmax_cpp = (omp_get_wtime() - tstart)/NLOOPS;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// print results
|
|
||||||
cout << "####### OpenMP #######" << endl;
|
|
||||||
cout << "minimum: " << min << endl;
|
|
||||||
cout << "maximum: " << max << endl;
|
|
||||||
cout << "duration: " << t_minmax_omp << endl << endl;
|
|
||||||
|
|
||||||
cout << "arithmetic mean: " << am_omp << endl;
|
|
||||||
cout << "geometric mean: " << gm_omp << endl;
|
|
||||||
cout << "harmonic mean: " << hm_omp << endl;
|
|
||||||
cout << "duration: " << t_means_omp << endl << endl;
|
|
||||||
|
|
||||||
|
|
||||||
cout << "####### C++ #######" << endl;
|
|
||||||
cout << "minimum: " << min_cpp << endl;
|
|
||||||
cout << "maximum: " << max_cpp << endl;
|
|
||||||
cout << "duration: " << t_minmax_cpp << endl << endl;
|
|
||||||
|
|
||||||
cout << "arithmetic mean: " << am_cpp << endl;
|
|
||||||
cout << "geometric mean: " << gm_cpp << endl;
|
|
||||||
cout << "harmonic mean: " << hm_cpp << endl;
|
|
||||||
cout << "duration: " << t_means_cpp << endl << endl;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ####### OpenMP #######
|
|
||||||
// minimum: 1
|
|
||||||
// maximum: 1000
|
|
||||||
// duration: 3.52086e-06
|
|
||||||
|
|
||||||
// arithmetic mean: 498.184
|
|
||||||
// geometric mean: 364.412
|
|
||||||
// harmonic mean: 95.6857
|
|
||||||
// duration: 5.90171e-06
|
|
||||||
|
|
||||||
// ####### C++ #######
|
|
||||||
// minimum: 1
|
|
||||||
// maximum: 1000
|
|
||||||
// duration: 1.76816e-05
|
|
||||||
|
|
||||||
// arithmetic mean: 498.184
|
|
||||||
// geometric mean: 364.412
|
|
||||||
// harmonic mean: 95.6857
|
|
||||||
// duration: 2.35728e-05
|
|
||||||
|
|
||||||
// --> the openMP variant is faster in both cases
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
|
@ -1,103 +0,0 @@
|
||||||
#include "mylib.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <execution>
|
|
||||||
#include <iostream>
|
|
||||||
#include <numeric>
|
|
||||||
#include <omp.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
void means_omp(const std::vector<size_t> numbers, double &am, double &gm, double &hm)
|
|
||||||
{
|
|
||||||
size_t const n = numbers.size();
|
|
||||||
|
|
||||||
am = 0.;
|
|
||||||
gm = 0.;
|
|
||||||
hm = 0.;
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(numbers, n, cout) reduction(+:am, gm, hm)
|
|
||||||
for (size_t i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
am += numbers[i];
|
|
||||||
gm += log(numbers[i]);
|
|
||||||
hm += 1.0/numbers[i];
|
|
||||||
|
|
||||||
// #pragma omp critical
|
|
||||||
// {
|
|
||||||
// cout << "Thread number " << omp_get_thread_num() << " processes value " << numbers[i] << endl;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
am /= n;
|
|
||||||
gm = exp(gm/n);
|
|
||||||
hm = n/hm;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void minmax_omp(const std::vector<size_t> numbers, size_t &global_min, size_t &global_max)
|
|
||||||
{
|
|
||||||
size_t const n = numbers.size();
|
|
||||||
|
|
||||||
global_min = -1; // gives the maximum size_t value
|
|
||||||
global_max = 0;
|
|
||||||
|
|
||||||
#pragma omp parallel shared(numbers, n, global_min, global_max)
|
|
||||||
{
|
|
||||||
const size_t nthreads = omp_get_num_threads();
|
|
||||||
const size_t threadnum = omp_get_thread_num();
|
|
||||||
const size_t chunksize = n/nthreads;
|
|
||||||
|
|
||||||
|
|
||||||
size_t start = threadnum*chunksize;
|
|
||||||
size_t end = start + chunksize;
|
|
||||||
if (threadnum == nthreads - 1)
|
|
||||||
end = n;
|
|
||||||
|
|
||||||
|
|
||||||
size_t local_min = -1;
|
|
||||||
size_t local_max = 0;
|
|
||||||
for (size_t i = start; i < end ; ++i)
|
|
||||||
{
|
|
||||||
if (numbers[i] < local_min)
|
|
||||||
local_min = numbers[i];
|
|
||||||
|
|
||||||
if (numbers[i] > local_max)
|
|
||||||
local_max = numbers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma omp critical
|
|
||||||
{
|
|
||||||
if (local_min < global_min)
|
|
||||||
global_min = local_min;
|
|
||||||
|
|
||||||
if (local_max > global_max)
|
|
||||||
global_max = local_max;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void means_cpp(const std::vector<size_t> numbers, double &am, double &gm, double &hm)
|
|
||||||
{
|
|
||||||
size_t const n = numbers.size();
|
|
||||||
|
|
||||||
am = reduce(std::execution::par, numbers.begin(), numbers.end());
|
|
||||||
gm = transform_reduce(std::execution::par, numbers.begin(), numbers.end(), 0.0, plus{}, [] (size_t x) -> double { return log(x); } );
|
|
||||||
hm = transform_reduce(std::execution::par, numbers.begin(), numbers.end(), 0.0, plus{}, [] (size_t x) -> double { return 1.0/x; });
|
|
||||||
|
|
||||||
am /= n;
|
|
||||||
gm = exp(gm/n);
|
|
||||||
hm = n/hm;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void minmax_cpp(const std::vector<size_t> numbers, size_t &global_min, size_t &global_max)
|
|
||||||
{
|
|
||||||
auto min_it = min_element(std::execution::par, numbers.begin(), numbers.end());
|
|
||||||
auto max_it = max_element(std::execution::par, numbers.begin(), numbers.end());
|
|
||||||
|
|
||||||
global_min = *min_it;
|
|
||||||
global_max = *max_it;
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function calculates arithmetic mean, geometric mean and harmonic mean of an integer vector.
|
|
||||||
Uses openMP parallelization.
|
|
||||||
@param[in] numbers vector containing integers
|
|
||||||
@param[out] am arithmetic mean
|
|
||||||
@param[out] gm geometric mean
|
|
||||||
@param[out] hm harmonic mean
|
|
||||||
*/
|
|
||||||
void means_omp(const std::vector<size_t> numbers, double &am, double &gm, double &hm);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function calculates the minimum and maximum of a vector.
|
|
||||||
Uses openMP parallelization.
|
|
||||||
@param[in] numbers vector containing integers
|
|
||||||
@param[out] global_min minimum
|
|
||||||
@param[out] global_max maximum
|
|
||||||
*/
|
|
||||||
void minmax_omp(const std::vector<size_t> numbers, size_t &global_min, size_t &global_max);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function calculates arithmetic mean, geometric mean and harmonic mean of an integer vector.
|
|
||||||
Uses C++ parallelization.
|
|
||||||
@param[in] numbers vector containing integers
|
|
||||||
@param[out] am arithmetic mean
|
|
||||||
@param[out] gm geometric mean
|
|
||||||
@param[out] hm harmonic mean
|
|
||||||
*/
|
|
||||||
void means_cpp(const std::vector<size_t> numbers, double &am, double &gm, double &hm);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function calculates the minimum and maximum of a vector.
|
|
||||||
Uses C++ parallelization.
|
|
||||||
@param[in] numbers vector containing integers
|
|
||||||
@param[out] global_min minimum
|
|
||||||
@param[out] global_max maximum
|
|
||||||
*/
|
|
||||||
void minmax_cpp(const std::vector<size_t> numbers, size_t &global_min, size_t &global_max);
|
|
||||||
Binary file not shown.
|
|
@ -1,30 +0,0 @@
|
||||||
#
|
|
||||||
# use GNU-Compiler tools
|
|
||||||
COMPILER=GCC_
|
|
||||||
# alternatively from the shell
|
|
||||||
# export COMPILER=GCC_
|
|
||||||
# or, alternatively from the shell
|
|
||||||
# make COMPILER=GCC_
|
|
||||||
|
|
||||||
# use Intel compilers
|
|
||||||
#COMPILER=ICC_
|
|
||||||
|
|
||||||
# use PGI compilers
|
|
||||||
# COMPILER=PGI_
|
|
||||||
|
|
||||||
|
|
||||||
SOURCES = main.cpp goldbach.cpp
|
|
||||||
OBJECTS = $(SOURCES:.cpp=.o)
|
|
||||||
|
|
||||||
PROGRAM = main.${COMPILER}
|
|
||||||
|
|
||||||
# uncomment the next to lines for debugging and detailed performance analysis
|
|
||||||
CXXFLAGS += -g
|
|
||||||
LINKFLAGS += -g
|
|
||||||
# do not use -pg with PGI compilers
|
|
||||||
|
|
||||||
ifndef COMPILER
|
|
||||||
COMPILER=GCC_
|
|
||||||
endif
|
|
||||||
|
|
||||||
include ../${COMPILER}default.mk
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
#include "goldbach.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <omp.h>
|
|
||||||
|
|
||||||
size_t single_goldbach(size_t k)
|
|
||||||
{
|
|
||||||
const std::vector<size_t> relevant_primes = get_primes(k);
|
|
||||||
size_t m = relevant_primes.size();
|
|
||||||
|
|
||||||
size_t counter = 0;
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(relevant_primes, m, k) reduction(+:counter)
|
|
||||||
for(size_t i = 0; i < m; ++i)
|
|
||||||
{
|
|
||||||
for(size_t j = i; j < m; ++j)
|
|
||||||
{
|
|
||||||
if(relevant_primes[i] + relevant_primes[j] == k)
|
|
||||||
++counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<size_t> count_goldbach(size_t n)
|
|
||||||
{
|
|
||||||
const std::vector<size_t> relevant_primes = get_primes(n);
|
|
||||||
size_t m = relevant_primes.size();
|
|
||||||
|
|
||||||
std::vector<size_t> counter_vector(n + 1, 0);
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(relevant_primes, m, n) reduction(VecAdd:counter_vector)
|
|
||||||
for(size_t i = 0; i < m; ++i)
|
|
||||||
{
|
|
||||||
for(size_t j = i; j < m; ++j)
|
|
||||||
{
|
|
||||||
size_t sum = relevant_primes[i] + relevant_primes[j];
|
|
||||||
if(sum <= n)
|
|
||||||
++counter_vector[relevant_primes[i] + relevant_primes[j]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return counter_vector;
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "mayer_primes.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function returns the number of possible decompositions of an integer into a sum of two prime numbers.
|
|
||||||
@param[in] k first integer
|
|
||||||
@param[out] count number of decompositions
|
|
||||||
*/
|
|
||||||
size_t single_goldbach(size_t k);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function returns the number of possible decompositions into a sum of two prime numbers of all even integers in the interval [4,n].
|
|
||||||
@param[in] n upper integer bound
|
|
||||||
@param[out] count_vector vector containing the number of decompositions for a natural number the corresponding index
|
|
||||||
*/
|
|
||||||
std::vector<size_t> count_goldbach(size_t n);
|
|
||||||
|
|
||||||
|
|
||||||
/** Vector @p b adds its elements to vector @p a .
|
|
||||||
@param[in] a vector
|
|
||||||
@param[in] b vector
|
|
||||||
@return a+=b componentwise
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
std::vector<T> &operator+=(std::vector<T> &a, std::vector<T> const &b)
|
|
||||||
{
|
|
||||||
assert(a.size()==b.size());
|
|
||||||
for (size_t k = 0; k < a.size(); ++k) {
|
|
||||||
a[k] += b[k];
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare the reduction operation in OpenMP for an STL-vector
|
|
||||||
// omp_out += omp_in requires operator+=(vector<int> &, vector<int> const &) from above
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// https://scc.ustc.edu.cn/zlsc/tc4600/intel/2016.0.109/compiler_c/common/core/GUID-7312910C-D175-4544-99C5-29C12D980744.htm
|
|
||||||
// https://gist.github.com/eruffaldi/7180bdec4c8c9a11f019dd0ba9a2d68c
|
|
||||||
// https://stackoverflow.com/questions/29633531/user-defined-reduction-on-vector-of-varying-size
|
|
||||||
// see also p.74ff in https://www.fz-juelich.de/ias/jsc/EN/AboutUs/Staff/Hagemeier_A/docs-parallel-programming/OpenMP-Slides.pdf
|
|
||||||
#pragma omp declare reduction(VecAdd : std::vector<size_t> : omp_out += omp_in) initializer (omp_priv=omp_orig)
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#include "goldbach.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <omp.h>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
cout << "Check: 694 has "<< single_goldbach(694) << " decompositions." << endl << "----------------------------------------" << endl;
|
|
||||||
|
|
||||||
for(size_t n : {10000, 100000, 400000, 1000000, 2000000})
|
|
||||||
{
|
|
||||||
double t_start = omp_get_wtime();
|
|
||||||
|
|
||||||
auto goldbach_vector = count_goldbach(n);
|
|
||||||
|
|
||||||
auto max_it = max_element(goldbach_vector.begin(), goldbach_vector.end());
|
|
||||||
size_t max_number = distance(goldbach_vector.begin(), max_it);
|
|
||||||
|
|
||||||
double t_end = omp_get_wtime() - t_start;
|
|
||||||
|
|
||||||
cout << "The number " << max_number << " has " << *max_it << " decompositions. Duration: " << t_end << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
###### WITHOUT PARALLELIZATION ######
|
|
||||||
The number 9240 has 329 decompositions. Duration: 0.00307696
|
|
||||||
The number 99330 has 2168 decompositions. Duration: 0.189839
|
|
||||||
The number 390390 has 7094 decompositions. Duration: 1.3042
|
|
||||||
The number 990990 has 15594 decompositions. Duration: 5.45034
|
|
||||||
The number 1981980 has 27988 decompositions. Duration: 47.1807
|
|
||||||
|
|
||||||
|
|
||||||
###### WITH PARALLELIZATION ######
|
|
||||||
The number 9240 has 329 decompositions. Duration: 0.000734854
|
|
||||||
The number 99330 has 2168 decompositions. Duration: 0.0251322
|
|
||||||
The number 390390 has 7094 decompositions. Duration: 0.487375
|
|
||||||
The number 990990 has 15594 decompositions. Duration: 6.16972
|
|
||||||
The number 1981980 has 27988 decompositions. Duration: 31.5699
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#
|
|
||||||
# use GNU-Compiler tools
|
|
||||||
COMPILER=GCC_
|
|
||||||
# alternatively from the shell
|
|
||||||
# export COMPILER=GCC_
|
|
||||||
# or, alternatively from the shell
|
|
||||||
# make COMPILER=GCC_
|
|
||||||
|
|
||||||
# use Intel compilers
|
|
||||||
#COMPILER=ICC_
|
|
||||||
|
|
||||||
# use PGI compilers
|
|
||||||
# COMPILER=PGI_
|
|
||||||
|
|
||||||
|
|
||||||
SOURCES = main.cpp benchmarks.cpp benchmark_tests.cpp
|
|
||||||
OBJECTS = $(SOURCES:.cpp=.o)
|
|
||||||
|
|
||||||
PROGRAM = main.${COMPILER}
|
|
||||||
|
|
||||||
# uncomment the next to lines for debugging and detailed performance analysis
|
|
||||||
CXXFLAGS += -g
|
|
||||||
LINKFLAGS += -g
|
|
||||||
# do not use -pg with PGI compilers
|
|
||||||
|
|
||||||
ifndef COMPILER
|
|
||||||
COMPILER=GCC_
|
|
||||||
endif
|
|
||||||
|
|
||||||
include ../${COMPILER}default.mk
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
vector<double> test_A(const size_t &NLOOPS, const size_t &N);
|
|
||||||
|
|
||||||
vector<double> test_A_sum(const size_t &NLOOPS, const size_t &N);
|
|
||||||
|
|
||||||
vector<double> test_B(const size_t &NLOOPS, const size_t &N, const size_t &M);
|
|
||||||
|
|
||||||
vector<double> test_C(const size_t &NLOOPS, const size_t &L, const size_t &M, const size_t &N);
|
|
||||||
|
|
||||||
vector<double> test_D(const size_t &NLOOPS, const size_t &N, const size_t &p);
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
#include "benchmarks.h"
|
|
||||||
#include <cassert> // assert()
|
|
||||||
#include <cmath>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <omp.h>
|
|
||||||
|
|
||||||
// (A) Inner product of two vectors (from skalar_stl)
|
|
||||||
double scalar_parallel(vector<double> const &x, vector<double> const &y)
|
|
||||||
{
|
|
||||||
assert(x.size() == y.size());
|
|
||||||
size_t const N = x.size();
|
|
||||||
double sum = 0.0;
|
|
||||||
//#pragma omp parallel for default(none) shared(x, y, N) reduction(+:sum) schedule(runtime)
|
|
||||||
#pragma omp parallel for shared(x, y, N) reduction(+:sum)
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
|
||||||
{
|
|
||||||
sum += x[i] * y[i];
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (A) Vector entry sum
|
|
||||||
double sum(vector<double> const &x)
|
|
||||||
{
|
|
||||||
double sum = 0.0;
|
|
||||||
#pragma omp parallel for shared(x) reduction(+:sum)
|
|
||||||
for (size_t i = 0; i < x.size(); ++i)
|
|
||||||
{
|
|
||||||
sum += x[i];
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// (B) Matrix-vector product (from intro_vector_densematrix)
|
|
||||||
vector<double> MatVec_parallel(vector<double> const &A, vector<double> const &x)
|
|
||||||
{
|
|
||||||
size_t const nelem = A.size();
|
|
||||||
size_t const N = x.size();
|
|
||||||
assert(nelem % N == 0); // make sure multiplication is possible
|
|
||||||
size_t const M = nelem/N;
|
|
||||||
|
|
||||||
vector<double> b(M);
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(A, x, N, M, b)
|
|
||||||
for (size_t i = 0; i < M; ++i)
|
|
||||||
{
|
|
||||||
double tmp = 0.0;
|
|
||||||
for (size_t j = 0; j < N; ++j)
|
|
||||||
tmp += A[N*i + j] * x[j];
|
|
||||||
b[i] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// (C) Matrix-matrix product
|
|
||||||
vector<double> MatMat_parallel(vector<double> const &A, vector<double> const &B, size_t const &L)
|
|
||||||
{
|
|
||||||
size_t const nelem_A = A.size();
|
|
||||||
size_t const nelem_B = B.size();
|
|
||||||
|
|
||||||
assert(nelem_A % L == 0 && nelem_B % L == 0);
|
|
||||||
|
|
||||||
size_t const M = nelem_A/L;
|
|
||||||
size_t const N = nelem_B/L;
|
|
||||||
|
|
||||||
|
|
||||||
vector<double> C(M*N);
|
|
||||||
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(A, B, M, N, L, C)
|
|
||||||
for (size_t i = 0; i < M; ++i)
|
|
||||||
{
|
|
||||||
for (size_t k = 0; k < L; ++k)
|
|
||||||
{
|
|
||||||
for (size_t j = 0; j < N; ++j)
|
|
||||||
{
|
|
||||||
C[N*i + j] += A[L*i + k]*B[N*k + j];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return C;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// (D) Evaluation of a polynomial function
|
|
||||||
vector<double> poly_parallel(vector<double> const &a, vector<double> const &x)
|
|
||||||
{
|
|
||||||
size_t const N = x.size();
|
|
||||||
size_t const p = a.size() - 1;
|
|
||||||
vector<double> y(N, 0);
|
|
||||||
|
|
||||||
#pragma omp parallel for shared(a, x, N, p, y)
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
|
||||||
{
|
|
||||||
double x_temp = x[i];
|
|
||||||
double y_temp = 0;
|
|
||||||
for (size_t k = 0; k < p + 1; ++k)
|
|
||||||
{
|
|
||||||
y_temp += x_temp*y_temp + a[p - k];
|
|
||||||
}
|
|
||||||
y[i] = y_temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue