mirror of
https://github.com/cp2k/cp2k.git
synced 2026-07-29 06:35:28 -04:00
Updated libsmm using OpenMP rather than multiprocess make for more
realistic affinity control (Alfio Lazzaro, Cray) svn-origin-rev: 14083
This commit is contained in:
parent
8a529013ef
commit
4c3b374e4f
16 changed files with 283 additions and 295 deletions
|
|
@ -19,7 +19,7 @@ Below you can find the detailed instructions for some examples.
|
|||
====================================================================================================================
|
||||
a) How to generate the library running several jobs in a cluster, where each
|
||||
computer allows for both execution and compilation.
|
||||
For this example we will use a CRAY system with GNU compiler and PBS.
|
||||
For this example we will use a CRAY system with GNU compiler and SLURM.
|
||||
Run "./generate -h" to see the meaning of the options.
|
||||
|
||||
1) Run: ./generate -c config/cray.gnu -j 100 -t 16 -w slurm tiny1
|
||||
|
|
@ -52,7 +52,7 @@ a) How to generate the library running several jobs in a cluster, where each
|
|||
|
||||
====================================================================================================================
|
||||
b) How to generate the library for the Intel Xeon Phi in batch mode
|
||||
For this example we will use a cluster with PBS, where each node has a MIC card.
|
||||
For this example we will use a cluster with SLURM, where each node has a MIC card.
|
||||
Run "./generate -h" to see the meaning of the options.
|
||||
We use the config file mic.intel (inside the directory config).
|
||||
Check if all options are OK for your case, in particular:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# and allow some flexibility in reordering floating point expressions (-ffast-math).
|
||||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
#
|
||||
target_compile="ftn -O2 -hfp3 -Oipa0 -hnodwarf -Onopattern "
|
||||
target_compile="ftn -O2 -hfp3 -hnodwarf -Onopattern -hvector1 "
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
@ -24,9 +24,14 @@ target_compile="ftn -O2 -hfp3 -Oipa0 -hnodwarf -Onopattern "
|
|||
# the library. The library itself is not compiled this way.
|
||||
# This compiler needs to be able to deal with some Fortran2003 constructs.
|
||||
#
|
||||
host_compile="gfortran -O2"
|
||||
host_compile="gfortran-4.6 -O2"
|
||||
|
||||
#
|
||||
# Show affinity mask
|
||||
#
|
||||
export CRAY_OMP_CHECK_AFFINITY=TRUE
|
||||
|
||||
#
|
||||
# Set the aprun command and its options for batch submission
|
||||
#
|
||||
aprun_cmd="aprun -B -cc none"
|
||||
aprun_cmd="aprun -n 1 -N 1 -d ${ntasks} -r 1"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# and allow some flexibility in reordering floating point expressions (-ffast-math).
|
||||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
#
|
||||
target_compile="ftn -O2 -funroll-loops -ffast-math -ftree-vectorize -fno-inline-functions -march=native"
|
||||
target_compile="ftn -O2 -funroll-loops -ffast-math -ftree-vectorize -finline-functions -fopenmp -march=native"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
@ -29,4 +29,4 @@ host_compile="gfortran -O2"
|
|||
#
|
||||
# Set the aprun command and its options for batch submission
|
||||
#
|
||||
aprun_cmd="aprun -B -cc none"
|
||||
aprun_cmd="aprun -n 1 -N 1 -d ${ntasks} -r 1"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# and allow some flexibility in reordering floating point expressions (-ffast-math).
|
||||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
#
|
||||
target_compile="ftn -O2 -funroll-loops -vec-report2 -warn -xHost -fno-inline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
target_compile="ftn -O2 -funroll-loops -warn -finline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
@ -25,7 +25,12 @@ target_compile="ftn -O2 -funroll-loops -vec-report2 -warn -xHost -fno-inline-fun
|
|||
#
|
||||
host_compile="ifort -O2"
|
||||
|
||||
#
|
||||
# Set KMP affinity
|
||||
#
|
||||
export KMP_AFFINITY=verbose,granularity=fine,scatter
|
||||
|
||||
#
|
||||
# Set the aprun command and its options for batch submission
|
||||
#
|
||||
aprun_cmd="aprun -B -cc none"
|
||||
aprun_cmd="aprun -n 1 -N 1 -d ${ntasks} -r 1 -cc none"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# and allow some flexibility in reordering floating point expressions (-ffast-math).
|
||||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
#
|
||||
target_compile="ifort -O2 -funroll-loops -vec-report2 -warn -xHost -fno-inline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
target_compile="ifort -O2 -funroll-loops -warn -xHost -finline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
@ -25,7 +25,12 @@ blas_linking="-static-intel -mkl=sequential"
|
|||
#
|
||||
host_compile="ifort -O2"
|
||||
|
||||
#
|
||||
# Set KMP affinity
|
||||
#
|
||||
export KMP_AFFINITY=verbose,granularity=fine,scatter
|
||||
|
||||
#
|
||||
# Set the aprun command and its options for batch submission
|
||||
#
|
||||
aprun_cmd="aprun -B -cc none"
|
||||
aprun_cmd="aprun -n 1 -N 1 -d ${ntasks} -r 1 -cc none"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# and allow some flexibility in reordering floating point expressions (-ffast-math).
|
||||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
#
|
||||
target_compile="gfortran -O2 -funroll-loops -ffast-math -ftree-vectorize -march=native -fno-inline-functions"
|
||||
target_compile="gfortran -O2 -funroll-loops -ffast-math -ftree-vectorize -march=native -finline-functions -fopenmp"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
# Note: -fp-model fast=1 is default for the Intel compiler
|
||||
#
|
||||
target_compile="ifort -O2 -funroll-loops -vec-report2 -warn -xHost -fno-inline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
target_compile="ifort -O2 -funroll-loops -vec-report2 -warn -xHost -finline-functions -nogen-interfaces -openmp -nolib-inline"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# Higher level optimisation (in particular loop nest optimization) should not be used.
|
||||
# Note: -fp-model fast=1 is default for the Intel compiler
|
||||
#
|
||||
target_compile="ifort -O2 -funroll-loops -vec-report2 -warn -mmic -fno-inline-functions -nogen-interfaces -openmp"
|
||||
target_compile="ifort -O2 -funroll-loops -vec-report2 -warn -mmic -finline-functions -nogen-interfaces -openmp"
|
||||
|
||||
#
|
||||
# target dgemm link options... these are the options needed to link blas (e.g. -lblas)
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
batch_cmd() {
|
||||
echo "${aprun_cmd} $@" | \
|
||||
qsub -N ${test_name} -j oe -V -d ${PWD} -lmppwidth=1 -lmppnppn=1 -lwalltime=${wtime};
|
||||
qsub -N ${test_name} -j oe -V -d ${PWD} -lnodes=1 -lwalltime=${wtime};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Author: Alfio Lazzaro, alazzaro@cray.com (2013)
|
||||
|
||||
batch_cmd() {
|
||||
sbatch -J ${test_name} -o "${test_name}-%j.out" -D ${PWD} --ntasks=1 --ntasks-per-node=1 -t ${wtime} <<EOF
|
||||
sbatch -J ${test_name} -o "${test_name}-%j.out" -D ${PWD} --ntasks=1 --ntasks-per-node=1 --cpus-per-task=${ntasks} -t ${wtime} <<EOF
|
||||
#!/bin/bash -e
|
||||
${aprun_cmd} $@
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ source generate.bash
|
|||
def_config_dir="config"
|
||||
def_config_file="${def_config_dir}/cray.gnu"
|
||||
def_SIMD="avx"
|
||||
def_ntasks="16"
|
||||
def_ntasks="1"
|
||||
def_base_out_dir="output"
|
||||
def_target="all"
|
||||
def_njobs="1"
|
||||
|
|
@ -43,8 +43,14 @@ show_help() {
|
|||
echo " Default value is ${def_ntasks}."
|
||||
echo " -w <wlm type> : workload manager for batch submission. The value must correspond to one of the files ${def_config_dir}/*.wlm."
|
||||
echo " Default value is \"${def_wlm}\"."
|
||||
echo " -m : time limit for batch execution."
|
||||
echo " -m <time> : time limit for batch execution."
|
||||
echo " Default value is \"${def_wtime}\"."
|
||||
echo " -a <target> : Target for make compilation. Values are: "
|
||||
echo " all: generate, compile and run the kernels."
|
||||
echo " source: only generate the source file kernels."
|
||||
echo " compile: generate and compile the kernels."
|
||||
echo " bench: same as all."
|
||||
echo " Default value is \"${def_target}\"."
|
||||
echo
|
||||
echo "COMMAND is one of the followings:"
|
||||
echo " tiny1 : it runs the tiny phase. Batch execution if requested."
|
||||
|
|
@ -87,7 +93,7 @@ check_number()
|
|||
|
||||
}
|
||||
|
||||
while getopts "c:hj:s:t:w:m:" OPTION; do
|
||||
while getopts "c:hj:s:t:w:m:a:" OPTION; do
|
||||
case $OPTION in
|
||||
c)
|
||||
config_file=$OPTARG
|
||||
|
|
@ -112,6 +118,17 @@ while getopts "c:hj:s:t:w:m:" OPTION; do
|
|||
m)
|
||||
wtime=$OPTARG
|
||||
;;
|
||||
a)
|
||||
case $OPTARG in
|
||||
all|source|compile|bench)
|
||||
target=$OPTARG
|
||||
;;
|
||||
*)
|
||||
echo "Warning: target \"$OPTARG\" unknown. Run ./generate -h for help."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
?)
|
||||
exit
|
||||
;;
|
||||
|
|
@ -123,15 +140,15 @@ shift $(( OPTIND - 1))
|
|||
# Use default OPTIONS values if they were not declared
|
||||
#
|
||||
if [ -z "${config_file}" ]; then
|
||||
config_file=$def_config_file
|
||||
config_file=${def_config_file}
|
||||
fi
|
||||
|
||||
if [ -z "${SIMD}" ]; then
|
||||
SIMD=$def_SIMD
|
||||
SIMD=${def_SIMD}
|
||||
fi
|
||||
|
||||
if [ -z "${ntasks}" ]; then
|
||||
ntasks=$def_ntasks
|
||||
ntasks=${def_ntasks}
|
||||
fi
|
||||
|
||||
if [ -z "${jobs}" ]; then
|
||||
|
|
@ -146,8 +163,11 @@ if [ -z "${wtime}" ]; then
|
|||
wtime=${def_wtime}
|
||||
fi
|
||||
|
||||
if [ -z "${target}" ]; then
|
||||
target=${def_target}
|
||||
fi
|
||||
|
||||
base_out_dir=$def_base_out_dir
|
||||
target=$def_target
|
||||
|
||||
#
|
||||
# Check COMMAND value
|
||||
|
|
@ -167,6 +187,7 @@ case $cmd in
|
|||
rm -fR run_tiny_*/
|
||||
rm -fR run_small_*/
|
||||
rm -fR run_lib_*/
|
||||
rm -fR run_check_*/
|
||||
rm -f *.mod Makefile.* *.x *.o
|
||||
rm -f *~
|
||||
if [ "$cmd" == "cleanall" ]; then
|
||||
|
|
@ -243,6 +264,7 @@ echo "WLM : ${wlm}"
|
|||
echo "SIMD register type : ${SIMD}"
|
||||
echo "Limit time batch : ${wtime}"
|
||||
echo "COMMAND : \"${cmd}\""
|
||||
echo "Make target : \"${target}\""
|
||||
echo
|
||||
|
||||
#
|
||||
|
|
@ -250,7 +272,6 @@ echo
|
|||
#
|
||||
config_file_name=`basename ${config_file}`
|
||||
out_dir="${base_out_dir}_${config_file_name}"
|
||||
OMP_NUM_THREADS=1
|
||||
|
||||
if [ ${jobs} -gt 0 ]; then
|
||||
source ${def_config_dir}/${wlm}.wlm
|
||||
|
|
@ -266,6 +287,12 @@ if [ ${jobs} -gt 0 ]; then
|
|||
else
|
||||
# Require 1 job
|
||||
jobs=1
|
||||
|
||||
case $cmd in
|
||||
tiny2|small2|check2)
|
||||
run_cmd=true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
type_label="_"
|
||||
|
|
@ -333,9 +360,13 @@ case $cmd in
|
|||
run_dir+="_small"
|
||||
make_file+="small"
|
||||
;;
|
||||
lib|check1|check2)
|
||||
lib)
|
||||
run_dir+="_lib"
|
||||
make_file+="lib"
|
||||
;;
|
||||
check1|check2)
|
||||
run_dir+="_check"
|
||||
|
||||
;;
|
||||
esac
|
||||
run_dir+="${type_label}"
|
||||
|
|
@ -343,7 +374,7 @@ make_file+="${type_label}_${config_file_name}"
|
|||
|
||||
tiny_file="tiny_gen_optimal${type_label}_${config_file_name}.out"
|
||||
small_file="small_gen_optimal${type_label}_${config_file_name}.out"
|
||||
test_file="test_smm${type_label}_${config_file_name}"
|
||||
test_file="test_smm${type_label}"
|
||||
|
||||
library="smm${type_label}_${config_file_name}"
|
||||
archive="../lib/lib${library}.a"
|
||||
|
|
|
|||
|
|
@ -36,12 +36,39 @@ write_makefile_header() {
|
|||
#
|
||||
# list of executables
|
||||
#
|
||||
printf "EXEFILES=\$(patsubst %%,\$(OUTDIR)/${prefix_file}_find_%%.x,\$(INDICES)) \n"
|
||||
printf "OBJFILES=\$(patsubst %%,\$(OUTDIR)/${prefix_file}_find_%%.o,\$(INDICES)) \n"
|
||||
|
||||
#
|
||||
# list of output files
|
||||
#
|
||||
printf "OUTFILES=\$(patsubst %%,\$(OUTDIR)/${prefix_file}_find_%%.out,\$(INDICES)) \n\n"
|
||||
printf "OUTFILES=\$(OBJFILES:.o=.out) \n\n"
|
||||
|
||||
#
|
||||
# name of the executable
|
||||
#
|
||||
printf "EXE=${prefix_file}_find_\$(firstword \$(INDICES))__\$(lastword \$(INDICES)).x \n\n"
|
||||
|
||||
#
|
||||
# main target
|
||||
#
|
||||
printf ".PHONY: bench \$(EXE:.x=.f90) \n"
|
||||
printf "all: bench \n\n"
|
||||
|
||||
#
|
||||
# include makefile for source master code generation
|
||||
#
|
||||
printf "DATATYPE=${strdat}\n"
|
||||
printf "include ../make.gen\n\n"
|
||||
|
||||
#
|
||||
# write general targets
|
||||
#
|
||||
printf "bench: \$(OUTDIR)/\$(EXE) \n"
|
||||
printf "\t rm -f \$(OUTFILES) \n"
|
||||
printf "\t export OMP_NUM_THREADS=${ntasks} ; ./\$< \n\n"
|
||||
|
||||
printf "\$(OUTDIR)/\$(EXE): \$(OBJFILES) \$(EXE:.x=.f90) \n"
|
||||
printf "\t ${target_compile} \$^ -o \$@ ${blas_linking} \n\n"
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -98,7 +125,7 @@ collect_results() {
|
|||
suffix=$1 ; shift
|
||||
|
||||
#
|
||||
# analyse results finding optimal tiny mults
|
||||
# analyse results finding optimal tiny or small mults
|
||||
#
|
||||
(
|
||||
for m in $@ ; do
|
||||
|
|
@ -134,26 +161,16 @@ do_generate_tiny() {
|
|||
write_makefile_header tiny "${dims_tiny}"
|
||||
|
||||
#
|
||||
# Write targets
|
||||
# Write specific targets
|
||||
#
|
||||
printf "all: bench \n\n"
|
||||
printf "compile: \$(OBJFILES) \n"
|
||||
printf "\$(OUTDIR)/%%.o: %%.f90 \n"
|
||||
printf "\t ${target_compile} -c \$< -o \$@ \n\n"
|
||||
|
||||
printf "source: \$(SRCFILES) \n\n"
|
||||
printf "source: \$(SRCFILES) \n"
|
||||
printf "%%.f90: \n"
|
||||
printf '\t .././tiny_gen.x `echo $* | awk -F_ '\''{ print $$3" "$$4" "$$5 }'\''`'
|
||||
printf " ${transpose_flavor} ${data_type} > \$@\n\n"
|
||||
|
||||
printf "compile: \$(EXEFILES) \n\n"
|
||||
printf "\$(OUTDIR)/%%.x: %%.f90 \n"
|
||||
printf "\t ${target_compile} \$< -o \$@ \n\n"
|
||||
|
||||
printf "bench: \$(OUTFILES) \n\n"
|
||||
printf "\$(OUTDIR)/%%.out: \$(OUTDIR)/%%.x \n"
|
||||
printf "\t ${mic_cmd} ./\$<"
|
||||
if [[ ( -n "${mic_cmd}" ) && ( -n "${OMP_NUM_THREADS}" ) ]]; then
|
||||
printf " -e \"OMP_NUM_THREADS=${OMP_NUM_THREADS}\""
|
||||
fi
|
||||
printf " > \$@ \n\n"
|
||||
printf " ${transpose_flavor} ${data_type} > \$@ \n\n"
|
||||
) > ${make_file}
|
||||
|
||||
run_make ${dims_tiny}
|
||||
|
|
@ -186,13 +203,6 @@ do_generate_small() {
|
|||
${host_compile} -c multrec_gen.f90
|
||||
${host_compile} mults.o multrec_gen.o small_gen.f90 -o small_gen.x
|
||||
|
||||
#
|
||||
# Make directory for MIC execution
|
||||
#
|
||||
if [[ ( -n "${MICFS}" ) && ( -n "${ssh_mic_cmd}" ) ]]; then
|
||||
mkdir -p ${MICFS}
|
||||
fi
|
||||
|
||||
#
|
||||
# for easy parallelism go via a Makefile
|
||||
#
|
||||
|
|
@ -200,38 +210,17 @@ do_generate_small() {
|
|||
(
|
||||
write_makefile_header small "${dims_small}"
|
||||
|
||||
if [[ ( -n "${MICFS}" ) && ( -n "${ssh_mic_cmd}" ) ]]; then
|
||||
printf "MICFS=${MICFS}\n\n"
|
||||
fi
|
||||
|
||||
#
|
||||
# Write targets
|
||||
# Write specific targets
|
||||
#
|
||||
printf "all: bench \n\n"
|
||||
printf "compile: \$(OBJFILES) \n"
|
||||
printf "\$(OUTDIR)/%%.o: \$(OUTDIR)/%%.f90 \n"
|
||||
printf "\t ${target_compile} -c \$< -o \$@ \n\n"
|
||||
|
||||
printf "source: \$(SRCFILES) \n\n"
|
||||
printf "%%.f90: \n"
|
||||
printf "source: \$(addprefix \$(OUTDIR)/,\$(SRCFILES)) \n"
|
||||
printf "\$(OUTDIR)/%%.f90: ../${tiny_file} \n"
|
||||
printf '\t .././small_gen.x `echo $* | awk -F_ '\''{ print $$3" "$$4" "$$5 }'\''`'
|
||||
printf " ${transpose_flavor} ${data_type} ${SIMD_size} ../${tiny_file} > \$@\n\n"
|
||||
|
||||
printf "compile: \$(EXEFILES) \n\n"
|
||||
printf "\$(OUTDIR)/%%.x: %%.f90 \n"
|
||||
printf "\t ${target_compile} \$< -o \$@ ${blas_linking} \n\n"
|
||||
|
||||
printf "bench: \$(OUTFILES) \n\n"
|
||||
printf "\$(OUTDIR)/%%.out: \$(OUTDIR)/%%.x \n"
|
||||
if [[ ( -n "${MICFS}" ) && ( -n "${ssh_mic_cmd}" ) ]]; then
|
||||
printf "\t cp \$< \$(MICFS) \n"
|
||||
printf "\t ${ssh_mic_cmd} \"ulimit -s 256000; export OMP_NUM_THREADS=1; "
|
||||
if [ -n "${MIC_LD_LIBRARY_PATH}" ]; then
|
||||
printf "export LD_LIBRARY_PATH=${MIC_LD_LIBRARY_PATH}; "
|
||||
fi
|
||||
printf "\$(MICFS)/./\$(<F)\" > \$@ \n"
|
||||
printf "\t rm \$(MICFS)/\$(<F)"
|
||||
else
|
||||
printf "\t ./\$< > \$@"
|
||||
fi
|
||||
printf "\n\n"
|
||||
) > ${make_file}
|
||||
|
||||
run_make ${dims_small}
|
||||
|
|
@ -408,30 +397,30 @@ do_generate_lib() {
|
|||
#
|
||||
# list of source files
|
||||
#
|
||||
printf "SRCFILES=\$(patsubst %%,smm${type_label}_%%.f90,\$(INDICES)) \n"
|
||||
printf "SRCFILES=\$(patsubst %%,\$(OUTDIR)/smm${type_label}_%%.f90,\$(INDICES)) \n"
|
||||
|
||||
#
|
||||
# list of obj files
|
||||
#
|
||||
printf "OBJFILES=\$(patsubst %%,\$(OUTDIR)/smm${type_label}_%%.o,\$(INDICES)) \n\n"
|
||||
|
||||
printf ".PHONY: \$(OUTDIR)/\$(DRIVER) \n\n"
|
||||
printf ".PHONY: \$(OUTDIR)/\$(DRIVER) archive \n\n"
|
||||
|
||||
printf "all: archive \n\n"
|
||||
|
||||
#
|
||||
# generation source rule
|
||||
#
|
||||
printf "source: \$(SRCFILES) \n\n"
|
||||
printf "%%.f90: \n"
|
||||
printf "source: \$(SRCFILES) \n"
|
||||
printf "\$(OUTDIR)/%%.f90: ../${small_file} ../${tiny_file} \n"
|
||||
printf '\t .././lib_gen.x `echo $* | awk -F_ '\''{ print $$3" "$$4" "$$5 }'\''`'
|
||||
printf " ${transpose_flavor} ${data_type} ${SIMD_size} ../${small_file} ../${tiny_file} > \$@\n\n"
|
||||
|
||||
#
|
||||
# compile rule
|
||||
#
|
||||
printf "compile: \$(OBJFILES) \n\n"
|
||||
printf "\$(OUTDIR)/%%.o: %%.f90 \n"
|
||||
printf "compile: \$(OBJFILES) \n"
|
||||
printf "\$(OUTDIR)/%%.o: \$(OUTDIR)/%%.f90 \n"
|
||||
printf "\t ${target_compile} -c \$< -o \$@ \n\n"
|
||||
|
||||
printf "\$(OUTDIR)/\$(DRIVER): \n"
|
||||
|
|
@ -456,7 +445,7 @@ do_generate_lib() {
|
|||
# execute makefile compiling all variants and executing them
|
||||
#
|
||||
test_name="${run_dir}_job${jobs}"
|
||||
${run_cmd} make -B -j ${ntasks} -f ../${make_file} ${target}
|
||||
${run_cmd} make -j ${ntasks} -f ../${make_file} ${target}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -487,6 +476,11 @@ do_check() {
|
|||
element_end=0
|
||||
ijob=0
|
||||
|
||||
#
|
||||
# make the output dir
|
||||
#
|
||||
mkdir -p ${out_dir}
|
||||
|
||||
#
|
||||
# Make directory for MIC execution
|
||||
#
|
||||
|
|
@ -509,7 +503,7 @@ do_check() {
|
|||
echo "Preparing test program for job #$ijob..."
|
||||
filename=${test_file}_job$ijob
|
||||
|
||||
cat << EOF > ${filename}.f90
|
||||
cat << EOF > ${out_dir}/${filename}.f90
|
||||
MODULE WTF_job$ijob
|
||||
INTERFACE MYRAND
|
||||
MODULE PROCEDURE SMYRAND, DMYRAND, CMYRAND, ZMYRAND
|
||||
|
|
@ -573,6 +567,7 @@ SUBROUTINE testit(M,N,K)
|
|||
|
||||
IF (MAXVAL(ABS(C2-C1))>100*EPSILON(REAL(1.0,KIND=KIND(A(1,1))))) THEN
|
||||
write(6,*) "Matrix size",M,N,K
|
||||
write(6,*) "Max diff=",MAXVAL(ABS(C2-C1))
|
||||
write(6,*) "A=",A
|
||||
write(6,*) "B=",B
|
||||
write(6,*) "C1=",C1
|
||||
|
|
@ -605,33 +600,35 @@ END SUBROUTINE
|
|||
PROGRAM tester
|
||||
IMPLICIT NONE
|
||||
|
||||
!\$omp parallel
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
echo " CALL testit(${m},${n},${k})" >> ${filename}.f90
|
||||
echo " CALL testit(${m},${n},${k})" >> ${out_dir}/${filename}.f90
|
||||
|
||||
# last entry for a job
|
||||
if [ $element -eq $element_end ]; then
|
||||
|
||||
# last job
|
||||
if [ $ijob -eq $jobs ]; then
|
||||
cat << EOF >> ${filename}.f90
|
||||
cat << EOF >> ${out_dir}/${filename}.f90
|
||||
! checking 'peak' performance (and a size likely outside of the library)
|
||||
CALL testit(1000,1000,1000)
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat << EOF >> ${filename}.f90
|
||||
cat << EOF >> ${out_dir}/${filename}.f90
|
||||
!\$omp end parallel
|
||||
END PROGRAM
|
||||
EOF
|
||||
|
||||
echo "Launching job #$ijob"
|
||||
test_name="${run_dir}_check_job${ijob}"
|
||||
test_name="${run_dir}_job${ijob}"
|
||||
|
||||
exe=${filename}.x
|
||||
|
||||
rm -f ${filename}.sh
|
||||
rm -f ${out_dir}/${filename}.sh
|
||||
#
|
||||
# Prepare the script for compile the benchmarking
|
||||
# and testing program for the smm library
|
||||
|
|
@ -639,21 +636,13 @@ EOF
|
|||
(
|
||||
printf "#!/bin/bash -e \n\n"
|
||||
printf "set -o pipefail\n\n"
|
||||
printf "${target_compile} ${filename}.f90 -o ${exe} -L../lib -l${library} ${blas_linking}\n"
|
||||
if [[ ( -n "${MICFS}" ) && ( -n "${ssh_mic_cmd}" ) ]]; then
|
||||
printf "cp ${exe} ${MICFS}\n"
|
||||
printf "${ssh_mic_cmd} \"ulimit -s 256000; export OMP_NUM_THREADS=1; "
|
||||
if [ -n "${MIC_LD_LIBRARY_PATH}" ]; then
|
||||
printf "export LD_LIBRARY_PATH=${MIC_LD_LIBRARY_PATH}; "
|
||||
fi
|
||||
printf "${MICFS}/./${exe}\" | tee ${filename}.out\n"
|
||||
else
|
||||
printf "./${exe} | tee ${filename}.out"
|
||||
fi
|
||||
) > ${filename}.sh
|
||||
chmod +x ${filename}.sh
|
||||
printf "cd ${out_dir}\n"
|
||||
printf "${target_compile} ${filename}.f90 -o ${exe} -L../../lib -l${library} ${blas_linking}\n"
|
||||
printf "export OMP_NUM_THREADS=1 ; ./${exe} | tee ${filename}.out"
|
||||
) > ${out_dir}/${filename}.sh
|
||||
chmod +x ${out_dir}/${filename}.sh
|
||||
|
||||
${run_cmd} ./${filename}.sh
|
||||
${run_cmd} ./${out_dir}/${filename}.sh
|
||||
fi
|
||||
|
||||
element=$(( element + 1 ))
|
||||
|
|
@ -674,28 +663,30 @@ EOF
|
|||
#
|
||||
# Merge the output files in the case of $run_cmd" = "true"
|
||||
#
|
||||
rm -f ${test_file}.out
|
||||
rm -f ${test_file}_${config_file_name}.out
|
||||
|
||||
for (( ijob=1 ; ijob<=jobs; ijob++ )); do
|
||||
if [ ! -s ${run_dir}/${test_file}"_job$ijob".out ]; then
|
||||
echo "ERROR: Empty check file \"${run_dir}/${test_file}_job$ijob.out\""
|
||||
if [ ! -s ${run_dir}/${out_dir}/${test_file}"_job$ijob".out ]; then
|
||||
echo "ERROR: Empty check file \"${run_dir}/${out_dir}/${test_file}_job$ijob.out\""
|
||||
exit
|
||||
fi
|
||||
cat ${run_dir}/${test_file}"_job$ijob".out >> ${test_file}.out
|
||||
cat ${run_dir}/${out_dir}/${test_file}"_job$ijob".out >> ${test_file}_${config_file_name}.out
|
||||
done
|
||||
|
||||
#
|
||||
# We're done... protect the user from bad compilers
|
||||
#
|
||||
set +e
|
||||
grep "BLAS and smm yield different results" ${test_file}.out >& /dev/null
|
||||
grep "BLAS and smm yield different results" ${test_file}_${config_file_name}.out >& /dev/null
|
||||
if [ "$?" == "0" ]; then
|
||||
echo "Library is miscompiled... removing lib/lib${library}.a"
|
||||
echo
|
||||
rm -f ${archive}
|
||||
else
|
||||
pathhere=`pwd -P`
|
||||
echo "Done... check performance looking at ${test_file}.out"
|
||||
echo "Done... check performance looking at ${test_file}_${config_file_name}.out"
|
||||
echo "Final library can be linked as -L${pathhere}/lib -l${library}"
|
||||
echo
|
||||
fi
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,24 +76,28 @@ CONTAINS
|
|||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
INTEGER, OPTIONAL :: Cbuffer_row, Cbuffer_col
|
||||
|
||||
IF (PRESENT(stack_size_label).AND.stack_size_label/="") THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " SUBROUTINE smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,"_stack"//TRIM(label)//"("//TRIM(trparam(stack_size_label))//")"
|
||||
CALL write_stack_params(data_type,stack_size_label)
|
||||
write(6,'(A)') " INTEGER :: sp"
|
||||
IF (PRESENT(Cbuffer_row).AND.PRESENT(Cbuffer_col)) THEN
|
||||
write(6,'(A,I0,A,I0,A)') " "//trdat(data_type)//":: Cbuffer(",Cbuffer_row,",",Cbuffer_col,")"
|
||||
IF (PRESENT(stack_size_label)) THEN
|
||||
IF (stack_size_label/="") THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " SUBROUTINE smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,"_stack"//TRIM(label)//"("//TRIM(trparam(stack_size_label))//")"
|
||||
CALL write_stack_params(data_type,stack_size_label)
|
||||
write(6,'(A)') " INTEGER :: sp"
|
||||
IF (PRESENT(Cbuffer_row).AND.PRESENT(Cbuffer_col)) THEN
|
||||
write(6,'(A,I0,A,I0,A)') " "//trdat(data_type)//":: Cbuffer(",Cbuffer_row,",",Cbuffer_col,")"
|
||||
ENDIF
|
||||
write(6,'(A)') " DO sp = 1, "//TRIM(stack_size_label)
|
||||
IF (PRESENT(Cbuffer_row).AND.PRESENT(Cbuffer_col)) THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " CALL smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,&
|
||||
TRIM(label)//"_buffer(A(params(p_a_first,sp)),B(params(p_b_first,sp)),C(params(p_c_first,sp)),Cbuffer)"
|
||||
ELSE
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " CALL smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,&
|
||||
TRIM(label)//"(A(params(p_a_first,sp)),B(params(p_b_first,sp)),C(params(p_c_first,sp)))"
|
||||
ENDIF
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
ENDIF
|
||||
write(6,'(A)') " DO sp = 1, "//TRIM(stack_size_label)
|
||||
IF (PRESENT(Cbuffer_row).AND.PRESENT(Cbuffer_col)) THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " CALL smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,TRIM(label)//"_buffer(A(params(p_a_first,sp)),B(params(p_b_first,sp)),C(params(p_c_first,sp)),Cbuffer)"
|
||||
ELSE
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " CALL smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,TRIM(label)//"(A(params(p_a_first,sp)),B(params(p_b_first,sp)),C(params(p_c_first,sp)))"
|
||||
ENDIF
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
ENDIF
|
||||
END SUBROUTINE write_subroutine_stack
|
||||
|
||||
|
|
@ -103,12 +107,17 @@ CONTAINS
|
|||
INTEGER :: multElements,modElements
|
||||
CHARACTER(LEN=*) :: label
|
||||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
LOGICAL :: do_stack
|
||||
|
||||
multElements=(M/nSIMD)*nSIMD
|
||||
modElements=MOD(M,nSIMD)
|
||||
|
||||
IF (modElements>0) THEN
|
||||
if (PRESENT(stack_size_label).AND.stack_size_label/="") THEN
|
||||
do_stack=.FALSE.
|
||||
IF (PRESENT(stack_size_label)) THEN
|
||||
IF (stack_size_label/="") do_stack=.TRUE.
|
||||
ENDIF
|
||||
IF (do_stack) THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " PURE SUBROUTINE smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,TRIM(label)//"_buffer(A,B,C,Cbuffer)"
|
||||
write(6,'(A,I0,A,I0,A)') " "//trdat(data_type,"INOUT")//" :: Cbuffer(",nSIMD,",",MIN(stride,N),")"
|
||||
|
|
@ -322,8 +331,10 @@ CONTAINS
|
|||
! generation of the vector version
|
||||
IF (nSIMD>0) THEN
|
||||
CALL MULTVECTOR(label,M,N,K,transpose_flavor,data_type,nSIMD,stride,stack_size_label)
|
||||
IF (PRESENT(write_buffer_interface).AND.write_buffer_interface) THEN
|
||||
CALL MULTVECTOR(label,M,N,K,transpose_flavor,data_type,nSIMD,stride)
|
||||
IF (PRESENT(write_buffer_interface)) THEN
|
||||
IF (write_buffer_interface) THEN
|
||||
CALL MULTVECTOR(label,M,N,K,transpose_flavor,data_type,nSIMD,stride)
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
ENDIF
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@ CONTAINS
|
|||
CHARACTER(LEN=*), OPTIONAL :: in_intent_label
|
||||
CHARACTER(LEN=50) :: intent_label
|
||||
CHARACTER(LEN=50) :: trdat
|
||||
|
||||
IF (PRESENT(in_intent_label).AND.(in_intent_label.ne."")) THEN
|
||||
intent_label=", INTENT("//TRIM(in_intent_label)//")"
|
||||
ELSE
|
||||
intent_label=""
|
||||
|
||||
intent_label=""
|
||||
IF (PRESENT(in_intent_label)) THEN
|
||||
IF (in_intent_label/="") THEN
|
||||
intent_label=", INTENT("//TRIM(in_intent_label)//")"
|
||||
ENDIF
|
||||
ENDIF
|
||||
SELECT CASE(data_type)
|
||||
CASE(1)
|
||||
|
|
@ -25,6 +26,7 @@ CONTAINS
|
|||
trdat="COMPLEX(KIND=KIND(0.0))"//TRIM(intent_label)
|
||||
END SELECT
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION trgemm(data_type)
|
||||
INTEGER :: data_type
|
||||
CHARACTER(LEN=5) :: trgemm
|
||||
|
|
@ -39,6 +41,7 @@ CONTAINS
|
|||
trgemm="CGEMM"
|
||||
END SELECT
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION trstr(transpose_flavor,data_type)
|
||||
INTEGER :: transpose_flavor, data_type
|
||||
CHARACTER(LEN=3) :: trstr
|
||||
|
|
@ -64,6 +67,7 @@ CONTAINS
|
|||
trstr=dstr//"tt"
|
||||
END SELECT
|
||||
END FUNCTION trstr
|
||||
|
||||
FUNCTION trparam(stack_size_label)
|
||||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
CHARACTER(LEN=128) :: trparam
|
||||
|
|
@ -73,6 +77,7 @@ CONTAINS
|
|||
trparam = "A,B,C"
|
||||
ENDIF
|
||||
END FUNCTION trparam
|
||||
|
||||
SUBROUTINE write_stack_params(data_type,stack_size_label)
|
||||
INTEGER :: data_type
|
||||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
|
|
@ -83,6 +88,7 @@ CONTAINS
|
|||
write(6,'(A)') " INTEGER, INTENT(IN) :: p_a_first, p_b_first, p_c_first"
|
||||
ENDIF
|
||||
END SUBROUTINE write_stack_params
|
||||
|
||||
SUBROUTINE write_matrix_defs(M,N,K,transpose_flavor,data_type,write_intent,stack_size_label,padding)
|
||||
INTEGER, OPTIONAL :: M,N,K,transpose_flavor
|
||||
INTEGER :: data_type
|
||||
|
|
@ -90,6 +96,7 @@ CONTAINS
|
|||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
LOGICAL, OPTIONAL :: padding
|
||||
CHARACTER(LEN=50) :: intent_label
|
||||
LOGICAL :: do_padding
|
||||
|
||||
IF (PRESENT(M).AND.PRESENT(N).AND.PRESENT(K).AND.PRESENT(transpose_flavor)) THEN
|
||||
IF (PRESENT(stack_size_label)) THEN
|
||||
|
|
@ -105,7 +112,11 @@ CONTAINS
|
|||
" "//trdat(data_type,"INOUT")//" :: C(",M,",",N,")"
|
||||
intent_label="IN"
|
||||
ELSE
|
||||
IF (PRESENT(padding).AND.padding) THEN
|
||||
do_padding=.FALSE.
|
||||
IF (PRESENT(padding)) THEN
|
||||
IF (padding) do_padding=.TRUE.
|
||||
ENDIF
|
||||
IF (do_padding) THEN
|
||||
write(6,'(A)') &
|
||||
" "//trdat(data_type)//" :: C(M*N+8)"
|
||||
ELSE
|
||||
|
|
@ -130,43 +141,16 @@ CONTAINS
|
|||
END SELECT
|
||||
ENDIF
|
||||
ELSE
|
||||
write(6,'(A)') " "//trdat(data_type,"INOUT")//" :: C(*)"
|
||||
write(6,'(A)') " "//trdat(data_type,"IN")//" :: B(*), A(*)"
|
||||
IF (write_intent) THEN
|
||||
write(6,'(A)') " "//trdat(data_type,"INOUT")//" :: C(*)"
|
||||
write(6,'(A)') " "//trdat(data_type,"IN")//" :: B(*), A(*)"
|
||||
ELSE
|
||||
write(6,'(A)') " "//trdat(data_type)//" :: C(*)"
|
||||
write(6,'(A)') " "//trdat(data_type)//" :: B(*), A(*)"
|
||||
ENDIF
|
||||
ENDIF
|
||||
END SUBROUTINE write_matrix_defs
|
||||
|
||||
SUBROUTINE write_test_fun(M,N,K,transpose_flavor,data_type,stack_size_label)
|
||||
INTEGER :: M,N,K,transpose_flavor,data_type
|
||||
CHARACTER(LEN=*), OPTIONAL :: stack_size_label
|
||||
|
||||
write(6,'(A)') "FUNCTION TEST(X,"//TRIM(trparam(stack_size_label))//",Niter) RESULT(res)"
|
||||
IF (PRESENT(stack_size_label)) THEN
|
||||
CALL write_stack_params(data_type,stack_size_label)
|
||||
ELSE
|
||||
CALL write_matrix_defs(M,N,K,transpose_flavor,data_type,.FALSE.)
|
||||
ENDIF
|
||||
write(6,'(A)') " INTEGER :: Niter"
|
||||
write(6,'(A)') " REAL :: t2,t1,res"
|
||||
write(6,'(A)') " INTERFACE"
|
||||
write(6,'(A)') " SUBROUTINE X("//TRIM(trparam(stack_size_label))//")"
|
||||
IF (PRESENT(stack_size_label)) THEN
|
||||
CALL write_stack_params(data_type,stack_size_label)
|
||||
ELSE
|
||||
CALL write_matrix_defs(M,N,K,transpose_flavor,data_type,.FALSE.)
|
||||
ENDIF
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
write(6,'(A)') " END INTERFACE"
|
||||
write(6,'(A)') " INTEGER :: i"
|
||||
|
||||
write(6,'(A)') " CALL CPU_TIME(t1)"
|
||||
write(6,'(A)') " DO i=1,Niter"
|
||||
write(6,'(A)') " CALL X("//TRIM(trparam(stack_size_label))//")"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " CALL CPU_TIME(t2)"
|
||||
write(6,'(A)') " res=REAL(t2-t1,KIND=KIND(res))"
|
||||
write(6,'(A)') "END FUNCTION"
|
||||
END SUBROUTINE
|
||||
|
||||
SUBROUTINE smm_inner(mi,mf,ni,nf,ki,kf,iloop,mu,nu,ku,transpose_flavor,data_type)
|
||||
INTEGER :: mi,mf,ni,nf,ki,kf,iloop,mu,nu,ku,transpose_flavor,data_type
|
||||
INTEGER :: im,in,ik,ido
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ PROGRAM small_gen
|
|||
USE multrec_gen
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER :: M,N,K,nline,iline,max_dim, best_square(4),i,isquare, opts(4), transpose_flavor, data_type, SIMD_size
|
||||
INTEGER, DIMENSION(:,:), ALLOCATABLE :: tiny_opts
|
||||
REAL, DIMENSION(:), ALLOCATABLE :: tiny_perf,square_perf
|
||||
CHARACTER(LEN=1024) :: arg,filename,line,label
|
||||
INTEGER :: ibest_square=3
|
||||
CHARACTER(LEN=1024) :: arg,filename,label
|
||||
INTEGER :: M,N,K,transpose_flavor,data_type,SIMD_size
|
||||
INTEGER :: ibest_square=3, best_square=4
|
||||
INTEGER :: isquare
|
||||
|
||||
CALL GET_COMMAND_ARGUMENT(1,arg)
|
||||
READ(arg,*) M
|
||||
|
|
@ -48,73 +47,49 @@ PROGRAM small_gen
|
|||
CALL mult_versions(M,N,K,3,label,transpose_flavor,data_type,SIMD_size,filename)
|
||||
|
||||
! generation of the multrec versions (4)
|
||||
DO isquare=1,SIZE(best_square)
|
||||
write(label,'(A,I0)') "_",ibest_square+isquare
|
||||
CALL mult_versions(M,N,K,ibest_square+isquare,label,transpose_flavor,data_type,SIMD_size,filename)
|
||||
DO isquare=ibest_square+1,ibest_square+best_square
|
||||
write(label,'(A,I0)') "_",isquare
|
||||
CALL mult_versions(M,N,K,isquare,label,transpose_flavor,data_type,SIMD_size,filename)
|
||||
ENDDO
|
||||
|
||||
! generation of the vector version,
|
||||
! only in the case of SIMD_size=32(i.e. AVX) and SIMD_size=64(i.e. MIC)
|
||||
IF ((SIMD_size==32 .OR. SIMD_size==64) .AND. transpose_flavor==1 .AND. data_type<=2) THEN
|
||||
ibest_square=ibest_square+1
|
||||
write(label,'(A,I0)') "_",ibest_square+SIZE(best_square)
|
||||
CALL mult_versions(M,N,K,ibest_square+SIZE(best_square),label,&
|
||||
write(label,'(A,I0)') "_",ibest_square+best_square
|
||||
CALL mult_versions(M,N,K,ibest_square+best_square,label,&
|
||||
transpose_flavor,data_type,SIMD_size,filename,stack_size_label="")
|
||||
ENDIF
|
||||
|
||||
! test function
|
||||
CALL write_test_fun(M,N,K,transpose_flavor,data_type)
|
||||
|
||||
! test program
|
||||
write(6,'(A)') " PROGRAM small_find"
|
||||
write(6,'(A)') " IMPLICIT NONE"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0)') " INTEGER, PARAMETER :: M=",&
|
||||
M,",N=",N,",K=",K,",Nmin=5,versions=",ibest_square+SIZE(best_square)
|
||||
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') "SUBROUTINE small_find_",M,"_",N,"_",K,"(unit)"
|
||||
write(6,'(A)') " IMPLICIT NONE"
|
||||
write(6,'(A)') " INTEGER :: unit ! Output unit"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0)') " INTEGER, PARAMETER :: M=",M,",N=",N,",K=",K
|
||||
write(6,'(A)') " CHARACTER(len=64) :: filename"
|
||||
CALL write_matrix_defs(M,N,K,transpose_flavor,data_type,.FALSE.,padding=.TRUE.)
|
||||
|
||||
write(6,'(A)') " REAL :: timing(versions), best_time, test"
|
||||
write(6,'(A)') " REAL(KIND=KIND(0.D0)) :: flops,gflop"
|
||||
write(6,'(A)') " INTEGER :: imin,Niter,iloop,best_loop"
|
||||
write(6,'(A)') " INTERFACE"
|
||||
write(6,'(A)') " SUBROUTINE X("//TRIM(trparam())//")"
|
||||
write(6,'(A)') " INTERFACE"
|
||||
write(6,'(A)') " SUBROUTINE X("//TRIM(trparam())//")"
|
||||
CALL write_matrix_defs(data_type=data_type,write_intent=.TRUE.)
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
write(6,'(A)') " END INTERFACE"
|
||||
DO i=1,ibest_square+SIZE(best_square)
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
write(6,'(A)') " END INTERFACE"
|
||||
DO isquare=1,ibest_square+best_square
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0)') "PROCEDURE(X) :: smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,"_",i
|
||||
M,"_",N,"_",K,"_",isquare
|
||||
ENDDO
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " flops=2*REAL(M,KIND=KIND(0.D0))*N*K"
|
||||
write(6,'(A)') " gflop=1000.0D0*1000.0D0*1000.0D0"
|
||||
write(6,'(A)') " ! assume we would like to do 1 Gflop for testing a subroutine"
|
||||
write(6,'(A)') " Niter=MAX(1,CEILING(MIN(100000000.0D0,1*gflop/flops)))"
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " best_time=HUGE(best_time)"
|
||||
write(6,'(A)') " timing=best_time"
|
||||
write(6,'(A)') " C=0 ; A=0 ; B=0 "
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " DO imin=1,Nmin"
|
||||
DO i=1,ibest_square+SIZE(best_square)
|
||||
write(6,*) " timing(",i,")= &"
|
||||
write(6,*) " MIN(timing(",i,"), &"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') " TEST(smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,"_",i,",A,B,C,Niter))"
|
||||
write(6,*) 'write(6,''(1I4,F12.6,F12.3)'') ',i,',&'
|
||||
write(6,*) "timing(",i,"),&"
|
||||
write(6,*) "flops*Niter/gflop/timing(",i,")"
|
||||
write(6,'(A,I0,A,I0)') " INTEGER, PARAMETER :: Nmin=5,Nk=1,Nloop=",ibest_square+best_square
|
||||
write(6,'(A)') " TYPE t_kernels"
|
||||
write(6,'(A)') " PROCEDURE(X), POINTER, NOPASS :: ptr"
|
||||
write(6,'(A)') " END TYPE t_kernels"
|
||||
write(6,'(A)') " TYPE(t_kernels) :: kernels(Nk,Nloop)"
|
||||
write(6,'(A)') " INTEGER :: mnk(3,Nk) ! mu, nu, ku"
|
||||
DO isquare=1,ibest_square+best_square
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0)') " kernels(Nk,",isquare,")%ptr => smm_"//trstr(transpose_flavor,data_type)//"_",&
|
||||
M,"_",N,"_",K,"_",isquare
|
||||
ENDDO
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " DO iloop=1,versions"
|
||||
write(6,'(A)') " IF (timing(iloop)< best_time) THEN"
|
||||
write(6,'(A)') " best_time=timing(iloop)"
|
||||
write(6,'(A)') " best_loop=iloop"
|
||||
write(6,'(A)') " ENDIF"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A84)') ' write(6,''(1I4,F12.6,F12.3)'') '//&
|
||||
'best_loop, best_time, (flops*Niter/best_time)/gflop'
|
||||
write(6,'(A)') "END PROGRAM small_find"
|
||||
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " filename='small_find_",M,"_",N,"_",K,".out'"
|
||||
write(6,'(A)') " C = 0 ; A = 0 ; B = 0"
|
||||
write(6,'(A)') " mnk=0"
|
||||
write(6,'(A)') " CALL run_kernels(filename,unit,M,N,K,A,B,C,Nmin,Nk,Nloop,kernels,mnk)"
|
||||
write(6,'(A,I0,A,I0,A,I0)') "END SUBROUTINE small_find_",M,"_",N,"_",K
|
||||
|
||||
END PROGRAM small_gen
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ PROGRAM tiny_gen
|
|||
USE mults
|
||||
IMPLICIT NONE
|
||||
|
||||
INTEGER :: M,N,K
|
||||
INTEGER :: M,N,K,transpose_flavor,data_type
|
||||
INTEGER, PARAMETER :: Nloop=6
|
||||
CHARACTER(LEN=80) :: arg
|
||||
INTEGER :: mi,mf,ni,nf,ki,kf,iloop,ku,nu,mu,transpose_flavor, data_type
|
||||
INTEGER :: Nk,mi,mf,ni,nf,ki,kf,iloop,ku,nu,mu
|
||||
|
||||
CALL GET_COMMAND_ARGUMENT(1,arg)
|
||||
READ(arg,*) M
|
||||
|
|
@ -16,56 +17,31 @@ PROGRAM tiny_gen
|
|||
READ(arg,*) transpose_flavor
|
||||
CALL GET_COMMAND_ARGUMENT(5,arg)
|
||||
READ(arg,*) data_type
|
||||
|
||||
|
||||
CALL loop_variants(1)
|
||||
|
||||
CALL write_test_fun(M,N,K,transpose_flavor,data_type)
|
||||
|
||||
write(6,'(A)') " PROGRAM tiny_find"
|
||||
write(6,'(A)') " IMPLICIT NONE"
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " INTEGER, PARAMETER :: M=",M,",N=",N,",K=",K,",Nmin=2"
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') "SUBROUTINE tiny_find_",M,"_",N,"_",K,"(unit)"
|
||||
write(6,'(A)') " IMPLICIT NONE"
|
||||
write(6,'(A)') " INTEGER :: unit ! Output unit"
|
||||
write(6,'(A,I0,A,I0,A,I0)') " INTEGER, PARAMETER :: M=",M,",N=",N,",K=",K
|
||||
write(6,'(A)') " CHARACTER(len=64) :: filename"
|
||||
CALL write_matrix_defs(M,N,K,transpose_flavor,data_type,.FALSE.)
|
||||
write(6,'(A)') " REAL :: timing(6,M,N,K), best_time, test"
|
||||
write(6,'(A)') " REAL(KIND=KIND(0.D0)) :: flops,gflop"
|
||||
write(6,'(A)') " INTEGER :: imin,Niter,iloop,i,j,l, best_loop,best_mu, best_nu, best_ku"
|
||||
write(6,'(A)') " INTERFACE"
|
||||
write(6,'(A)') " SUBROUTINE X(A,B,C)"
|
||||
CALL write_matrix_defs(M,N,K,transpose_flavor,data_type,.FALSE.)
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
write(6,'(A)') " END INTERFACE"
|
||||
write(6,'(A)') " INTERFACE"
|
||||
write(6,'(A)') " SUBROUTINE X(A,B,C)"
|
||||
CALL write_matrix_defs(data_type=data_type,write_intent=.FALSE.)
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
write(6,'(A)') " END INTERFACE"
|
||||
CALL loop_variants(2)
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " flops=2*REAL(M,KIND=KIND(0.D0))*N*K"
|
||||
write(6,'(A)') " gflop=1000.0D0*1000.0D0*1000.0D0"
|
||||
write(6,'(A)') " ! assume we would like to do 1 Gflop for testing a subroutine"
|
||||
write(6,'(A)') " Niter=MAX(1,CEILING(MIN(100000000.0D0,1*gflop/flops)))"
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " best_time=HUGE(best_time)"
|
||||
write(6,'(A)') " timing=best_time"
|
||||
write(6,'(A)') " C=0 ; A=0 ; B=0 "
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " DO imin=1,Nmin"
|
||||
write(6,'(A,I0,A,I0)') " INTEGER, PARAMETER :: Nmin=2, Nk=",Nk,", Nloop=",Nloop
|
||||
write(6,'(A)') " TYPE t_kernels"
|
||||
write(6,'(A)') " PROCEDURE(X), POINTER, NOPASS :: ptr"
|
||||
write(6,'(A)') " END TYPE t_kernels"
|
||||
write(6,'(A)') " TYPE(t_kernels) :: kernels(Nk,Nloop)"
|
||||
write(6,'(A)') " INTEGER :: mnk(3,Nk) ! mu, nu, ku"
|
||||
CALL loop_variants(3)
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') ""
|
||||
write(6,'(A)') " DO iloop=1,6"
|
||||
write(6,'(A)') " DO i=1,M"
|
||||
write(6,'(A)') " DO j=1,N"
|
||||
write(6,'(A)') " DO l=1,K"
|
||||
write(6,'(A)') " IF (timing(iloop,i,j,l)< best_time) THEN"
|
||||
write(6,'(A)') " best_time=timing(iloop,i,j,l)"
|
||||
write(6,'(A)') " best_loop=iloop"
|
||||
write(6,'(A)') " best_mu=i"
|
||||
write(6,'(A)') " best_nu=j"
|
||||
write(6,'(A)') " best_ku=l"
|
||||
write(6,'(A)') " ENDIF"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A)') " ENDDO"
|
||||
write(6,'(A112)') ' write(6,''(4I4,F12.6,F12.3)'') '//&
|
||||
'best_loop,best_mu, best_nu, best_ku, best_time, (flops*Niter/best_time)/gflop'
|
||||
write(6,'(A)') "END PROGRAM tiny_find"
|
||||
write(6,'(A,I0,A,I0,A,I0,A)') " filename='tiny_find_",M,"_",N,"_",K,".out'"
|
||||
write(6,'(A)') " C = 0 ; A = 0 ; B = 0"
|
||||
write(6,'(A)') " CALL run_kernels(filename,unit,M,N,K,A,B,C,Nmin,Nk,Nloop,kernels,mnk)"
|
||||
write(6,'(A,I0,A,I0,A,I0)') "END SUBROUTINE tiny_find_",M,"_",N,"_",K
|
||||
|
||||
CONTAINS
|
||||
|
||||
|
|
@ -74,8 +50,11 @@ CONTAINS
|
|||
INTEGER :: itype
|
||||
|
||||
mi=1 ; mf=M ; ni=1 ; nf=N ; ki=1 ; kf=K
|
||||
|
||||
DO iloop=1,6
|
||||
|
||||
DO iloop=1,Nloop
|
||||
|
||||
IF (itype.ne.1) Nk=0
|
||||
|
||||
DO mu=1,M
|
||||
DO nu=1,N
|
||||
DO ku=1,K
|
||||
|
|
@ -83,9 +62,10 @@ CONTAINS
|
|||
IF (MOD(M,mu).NE.0) CYCLE
|
||||
IF (MOD(N,nu).NE.0) CYCLE
|
||||
IF (MOD(K,ku).NE.0) CYCLE
|
||||
! do not unroll with more than 32 mults in the inner loop (some more unrolling can be faster, but we reduce size and speedup lib generation)
|
||||
! do not unroll with more than 32 mults in the inner loop
|
||||
! (some more unrolling can be faster, but we reduce size and speedup lib generation)
|
||||
IF (mu*nu*ku>32) CYCLE
|
||||
|
||||
|
||||
SELECT CASE(itype)
|
||||
CASE(1)
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A)') &
|
||||
|
|
@ -96,25 +76,26 @@ CONTAINS
|
|||
CALL smm_inner(mi,mf,ni,nf,ki,kf,iloop,mu,nu,ku,transpose_flavor,data_type)
|
||||
write(6,'(A)') " END SUBROUTINE"
|
||||
CASE(2)
|
||||
Nk=Nk+1
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0)') &
|
||||
" PROCEDURE(X) :: smm_"//trstr(transpose_flavor,data_type)//"_",M,"_",N,"_",K,"_",iloop, &
|
||||
" PROCEDURE(X) :: smm_"//trstr(transpose_flavor,data_type)//"_",M,"_",N,"_",K,"_",iloop, &
|
||||
"_",mu,"_",nu,"_",ku
|
||||
CASE(3)
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') " timing(",iloop,",",mu,",",nu,",",ku,")= &"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') " MIN(timing(",iloop,",",mu,",",nu,",",ku,"), &"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A)') &
|
||||
" TEST(smm_"//trstr(transpose_flavor,data_type)//"_",M,"_",N,"_",K,"_", &
|
||||
iloop,"_",mu,"_",nu,"_",ku,",A,B,C,Niter))"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') 'write(6,''(4I4,F12.6,F12.3)'') ',iloop,",",mu,",",nu,",",ku,",& "
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') "timing(",iloop,",",mu,",",nu,",",ku,"),&"
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A)') "flops*Niter/gflop/timing(",iloop,",",mu,",",nu,",",ku,")"
|
||||
|
||||
Nk=Nk+1
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0,A,I0)') " kernels(",Nk,",",iloop, &
|
||||
")%ptr => smm_"//trstr(transpose_flavor,data_type)//"_",M,"_",N,"_",K,"_", &
|
||||
iloop,"_",mu,"_",nu,"_",ku
|
||||
IF (iloop.eq.1) THEN
|
||||
write(6,'(A,I0,A,I0,A,I0,A,I0,A,I0,A,I0)') " mnk(1,",Nk,")=",mu, &
|
||||
" ; mnk(2,",Nk,")=",nu, &
|
||||
" ; mnk(3,",Nk,")=",ku
|
||||
END IF
|
||||
END SELECT
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
ENDDO
|
||||
|
||||
|
||||
END SUBROUTINE loop_variants
|
||||
|
||||
END PROGRAM tiny_gen
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue