From 104141f228a13ee134d1810475bb4aebd5c9a7a4 Mon Sep 17 00:00:00 2001 From: Victor Moneratto Date: Tue, 1 Nov 2016 18:09:31 -0200 Subject: [PATCH] i32 and size_t memory variants, parallel data and control variants Also a rusty benchmark, oh, and no output until a --quiet flag is made --- .gitignore | 109 +++++++++++++++++++++++++++++++++++++++ benchmark.sh | 51 +++++++++++++++++++ sieve.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ sieve_openmp.c | 44 ---------------- 4 files changed, 295 insertions(+), 44 deletions(-) create mode 100644 .gitignore create mode 100755 benchmark.sh create mode 100644 sieve.c delete mode 100644 sieve_openmp.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..742b622 --- /dev/null +++ b/.gitignore @@ -0,0 +1,109 @@ + +# Created by https://www.gitignore.io/api/linux,windows,visualstudiocode,cmake,c + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + + +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json + + +### CMake ### +CMakeCache.txt +CMakeFiles +CMakeScripts +Makefile +cmake_install.cmake +install_manifest.txt +CTestTestfile.cmake + + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/benchmark.sh b/benchmark.sh new file mode 100755 index 0000000..dfc7e3e --- /dev/null +++ b/benchmark.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +run() { + local N=4294967294 + local I=1 + # while [ $N -le $MAX ]; do + TIME=$(date +%s%3N) + (./sieve $N) #> /dev/null + if [ $? -gt 0 ]; then exit; fi + echo $I. $(($(date +%s%3N) - $TIME))ms looking until $N + I=$((I+1)) + N=$(($N*10)) + # done +} + +compare() { + export OMP_NUM_THREADS=1 + echo ********Running with OMP_NUM_THREADS = $OMP_NUM_THREADS******** + run + + echo "" + + unset OMP_NUM_THREADS + echo ********Running with default OMP_NUM_THREADS******** + run +} + +MAX="$(echo "10^$1" | bc)" +IN=$1 +COMPILER="gcc sieve.c -lm -fopenmp -Wall -Wextra -Werror -std=c99 -o sieve" + +echo "############### SLOW32 ###############" +$COMPILER +compare +echo "######################################" + +echo "############### SLOWEX ###############" +$COMPILER -DSIEVE_EXTENDED +compare +echo "######################################" + +echo "############### FAST32 ###############" +$COMPILER -DSIEVE_FAST +compare +echo "######################################" + +echo "############### FASTEX ###############" +$COMPILER -DSIEVE_FAST -DSIEVE_EXTENDED +compare +echo "######################################" + diff --git a/sieve.c b/sieve.c new file mode 100644 index 0000000..474954a --- /dev/null +++ b/sieve.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include + +// +// NOTE: Type definitions +// +typedef uint8_t b8; +#define true 1 +#define false 0 + +typedef uint32_t u32; +#define PrintU32 PRIu32 +#define MAX_U32 UINT32_MAX + +#ifdef SIEVE_EXTENDED +#define sieve_num size_t +#define PrintSieveNum "zu" // No ideal portable version on inttypes :( +#define MAX_SIEVE SIZE_MAX +#else +#define sieve_num u32 +#define PrintSieveNum PrintU32 +#define MAX_SIEVE MAX_U32 +#endif + +uintmax_t StringToUMax(char* Str, uintmax_t MaxVal) { + uintmax_t Val = strtoumax(Str, NULL, 10); + if (Val > MaxVal) { + Val = MaxVal; + errno = ERANGE; + } + // + // NOTE: In case Val > UINTMAX_MAX, errno is already set to ERANGE, + // there's no need for additional checks + // + + return Val; +} +#define StringToSieveNum(Str) (sieve_num) StringToUMax(Str, MAX_SIEVE) + +// +// NOTE: Scope based free (assuming gcc here) +// +void _Autofree(void* Ptr) { + void** _Ptr = Ptr; + if (*_Ptr) + free(*_Ptr); +} +#define AUTOFREE(Ptr) __attribute__((cleanup(_Autofree))) Ptr = NULL + +void ShowUsage(char* Cmd) { + fprintf(stderr, "USAGE: %s \n", Cmd); +} + +int main(int NumberOfArgs, char** Args) { + // + // NOTE: Parsing arguments + // + if (NumberOfArgs != 2) { + ShowUsage(Args[0]); + return EXIT_FAILURE; + } + + sieve_num Max = StringToSieveNum(Args[1]); + // if (errno == EINVAL) *((b8*)0) = 0; + if (errno == ERANGE || Max == MAX_SIEVE) + { + // + // NOTE: Passed value is over our limit (MAX_SIEVE-1) + // We will cap it and warn the user + // + Max = MAX_SIEVE - 1; + fprintf(stderr, + "%s is higher than we can handle, " + "looking to a max of %" PrintSieveNum " instead\n", + Args[1], Max); + } + // Biased float conversion seems safe until 64bits integer + sieve_num MaxSqrt = (sieve_num)(sqrtf((float)Max) + 1e-5f); + + // + // NOTE: Sieve table allocation + // + sieve_num ElementsToAllocate = Max + 1; + b8* AUTOFREE(IsComposite); + IsComposite = (b8*)calloc((size_t)ElementsToAllocate, sizeof(b8)); + if (IsComposite == 0 || errno == ENOMEM) { + fprintf(stderr, + "Problem allocating memory, try looking for lower maximum " + "values\n"); + return EXIT_FAILURE; + } + + // + // NOTE: Sieve algorithm + // + #ifndef SIEVE_FAST + #pragma omp parallel for shared(MaxSqrt) shared(IsComposite) schedule(static) + #endif + for (sieve_num Number = 2; Number <= MaxSqrt; Number++) { + if (!IsComposite[Number]) { + #ifdef SIEVE_FAST + #pragma omp parallel for firstprivate(Number) schedule(static) + #endif + for (sieve_num Composite = Number * Number; Composite <= Max; + Composite += Number) { + IsComposite[Composite] = true; + } + } + } +#if 0 + // + // NOTE: Output + // + u32 PrimeInLine = 0; + const u32 PrimesPerLine = 12; + for (sieve_num Number = 2; Number <= Max; Number++) { + if (!IsComposite[Number]) { + PrimeInLine = (PrimeInLine + 1) % PrimesPerLine; + char* Separator = (PrimeInLine == 0) ? "\n" : ", "; + printf("%" PrintSieveNum "%s", Number, Separator); + } + } + + // Append empty line if missing + if(PrimeInLine > 0) { + printf("\n"); + } +#endif + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/sieve_openmp.c b/sieve_openmp.c deleted file mode 100644 index 1f8f55c..0000000 --- a/sieve_openmp.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include - -void print_primes(char *nums_array, long max_prime) -{ - int i; - for(i = 2; i <= max_prime; i++) - { - if(nums_array[i] == 0) - { - printf("%d\n", i); - } - } -} - -int main(int argc, char** argv) -{ - if (argc < 2) - { - printf("missing arg"); - return 1; - } - long max_prime = atoi(argv[1]); - char *nums_array = (char *) calloc(max_prime + 1, sizeof(char)); - - long i; - for(i = 2; i <= max_prime; i++) - { - if (nums_array[i] == 0) - { - long j; - #pragma omp parallel for schedule(static) - for(j = i*i; j <= max_prime; j += i) - { -// printf("%d\n", omp_get_thread_num()); - nums_array[j] = 1; - } - } - } - -// print_primes(nums_array, max_prime); - return 0; -}