taming-cpp

Experiments with C++ and comparisons with C
git clone https://git.tronto.net/taming-cpp
Download | Log | Files | Refs | README

commit 2f19e94b0ce78d6ccc9eedbf04b8a3460fd05565
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Mon, 29 Apr 2024 21:59:51 +0200

Sort benchmarks

Diffstat:
A.gitignore | 1+
AREADME.md | 19+++++++++++++++++++
Asort-benchmark/integers/Makefile | 20++++++++++++++++++++
Asort-benchmark/integers/notes.txt | 11+++++++++++
Asort-benchmark/integers/sort.c | 29+++++++++++++++++++++++++++++
Asort-benchmark/integers/sort.cpp | 25+++++++++++++++++++++++++
Asort-benchmark/integers/sort_parallel.cpp | 28++++++++++++++++++++++++++++
Asort-benchmark/pairs/Makefile | 20++++++++++++++++++++
Asort-benchmark/pairs/notes.txt | 11+++++++++++
Asort-benchmark/pairs/sort.c | 38++++++++++++++++++++++++++++++++++++++
Asort-benchmark/pairs/sort.cpp | 32++++++++++++++++++++++++++++++++
Asort-benchmark/pairs/sort_parallel.cpp | 35+++++++++++++++++++++++++++++++++++
12 files changed, 269 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +sort-benchmark/*/sort diff --git a/README.md b/README.md @@ -0,0 +1,19 @@ +# Taming C++ + +Experiments with C++ and comparisons with C. + +## sort-benchmark + +Inspired by [Bert's post](https://berthub.eu/articles/posts/c++-1). + +Sorting an array of integers is a simple task, so C and C++ should perform +similarly, right? Wrong! + +``` +C time for 100000000 numbers: 9.886314s +C++ time for 100000000 numbers: 4.92299s +C++ time for 100000000 numbers (parallel): 0.495435s +``` + +A similar benchmark is provided for sorting an arrays of pairs in a +non-standard way. diff --git a/sort-benchmark/integers/Makefile b/sort-benchmark/integers/Makefile @@ -0,0 +1,20 @@ +CC = gcc +CPP = g++ +OPT = -O3 +VAR = -DARRAYSIZE=100000000 + +all: sort_c sort_cpp sort_parallel_cpp + +sort_c: + ${CC} ${OPT} ${VAR} -std=c11 -o sort sort.c + ./sort + +sort_cpp: + ${CPP} ${OPT} ${VAR} -std=c++20 -o sort sort.cpp + ./sort + +sort_parallel_cpp: + ${CPP} ${OPT} ${VAR} -std=c++20 -o sort sort_parallel.cpp -ltbb + ./sort + +.PHONY: sort_c sort_cpp sort_parallel_cpp diff --git a/sort-benchmark/integers/notes.txt b/sort-benchmark/integers/notes.txt @@ -0,0 +1,11 @@ +- Getting the parallel version to work was a pain. Two major gotchas: + (1) -ltbb had to be added *at the end* of the command line + (2) clang requires a libstdc++ option to make this work + of course everything was terrible to decipher with C++ compile errors + being the mess they are. +- For measuring time I could also use + clock_t begin = clock(); + ... + clock_t end = clock(); + double time = (dobule)(end - begin) / CLOCKS_PER_SEC; + but it does not work with the parallel version (it meausres CPU clocks). diff --git a/sort-benchmark/integers/sort.c b/sort-benchmark/integers/sort.c @@ -0,0 +1,29 @@ +#define _POSIX_C_SOURCE 200809L /* Required to use clock_gettime */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +int a[ARRAYSIZE]; + +int compar(const void *x, const void *y) { return *(int *)x - *(int *)y; } + +int main() { + srand(time(NULL)); + for (int i = 0; i < ARRAYSIZE; i++) a[i] = rand() % 1000000000; + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + qsort(a, ARRAYSIZE, sizeof(int), compar); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + printf("(%d) C time for %d numbers: %lfs\n", + a[ARRAYSIZE/2], ARRAYSIZE, time); + + return 0; +} diff --git a/sort-benchmark/integers/sort.cpp b/sort-benchmark/integers/sort.cpp @@ -0,0 +1,25 @@ +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <iostream> + +int a[ARRAYSIZE]; + +int main(void) { + srand(time(NULL)); + for (auto &x : a) x = rand() % 1000000000; + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + std::sort(a, a+ARRAYSIZE, + [](const int &x, const int &y) { return x < y; }); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + std::cout << "(" << a[ARRAYSIZE/2] << ") C++ time for " << ARRAYSIZE + << " numbers: " << time << "s\n"; +} diff --git a/sort-benchmark/integers/sort_parallel.cpp b/sort-benchmark/integers/sort_parallel.cpp @@ -0,0 +1,28 @@ +/* Requires Thread Building Blocks (libtbb-dev on Debian) */ + +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <execution> +#include <iostream> + +int a[ARRAYSIZE]; + +int main(void) { + srand(time(NULL)); + for (auto &x : a) x = rand() % 1000000000; + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + std::sort(std::execution::par, a, a+ARRAYSIZE, + [](const int &x, const int &y) { return x < y; }); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + std::cout << "(" << a[ARRAYSIZE/2] << ") C++ time for " << ARRAYSIZE + << " numbers (parallel): " << time << "s\n"; +} diff --git a/sort-benchmark/pairs/Makefile b/sort-benchmark/pairs/Makefile @@ -0,0 +1,20 @@ +CC = gcc +CPP = g++ +OPT = -O3 +VAR = -DARRAYSIZE=100000000 + +all: sort_c sort_cpp sort_parallel_cpp + +sort_c: + ${CC} ${OPT} ${VAR} -std=c11 -o sort sort.c + ./sort + +sort_cpp: + ${CPP} ${OPT} ${VAR} -std=c++20 -o sort sort.cpp + ./sort + +sort_parallel_cpp: + ${CPP} ${OPT} ${VAR} -std=c++20 -o sort sort_parallel.cpp -ltbb + ./sort + +.PHONY: sort_c sort_cpp sort_parallel_cpp diff --git a/sort-benchmark/pairs/notes.txt b/sort-benchmark/pairs/notes.txt @@ -0,0 +1,11 @@ +- Getting the parallel version to work was a pain. Two major gotchas: + (1) -ltbb had to be added *at the end* of the command line + (2) clang requires a libstdc++ option to make this work + of course everything was terrible to decipher with C++ compile errors + being the mess they are. +- For measuring time I could also use + clock_t begin = clock(); + ... + clock_t end = clock(); + double time = (dobule)(end - begin) / CLOCKS_PER_SEC; + but it does not work with the parallel version (it meausres CPU clocks). diff --git a/sort-benchmark/pairs/sort.c b/sort-benchmark/pairs/sort.c @@ -0,0 +1,38 @@ +#define _POSIX_C_SOURCE 200809L /* Required to use clock_gettime */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +typedef struct { int a, b; } pair_t; +pair_t a[ARRAYSIZE]; + +int compar(const void *x, const void *y) { + pair_t *p = (pair_t *)x; + pair_t *q = (pair_t *)y; + int d = p->a - q->a; + return d > 0 ? 1 : (d < 0 ? -1 : (q->b - p->b)); +} + +int main() { + srand(time(NULL)); + for (int i = 0; i < ARRAYSIZE; i++) { + a[i].a = rand() % 1000000; + a[i].b = rand() % 1000000; + } + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + qsort(a, ARRAYSIZE, sizeof(pair_t), compar); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + printf("(%d) C time for %d pairs: %lfs\n", + a[ARRAYSIZE/2].a, ARRAYSIZE, time); + + return 0; +} diff --git a/sort-benchmark/pairs/sort.cpp b/sort-benchmark/pairs/sort.cpp @@ -0,0 +1,32 @@ +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <iostream> + +typedef struct { int a, b; } pair_t; +pair_t a[ARRAYSIZE]; + +int main(void) { + srand(time(NULL)); + for (auto &x : a) { + x.a = rand() % 1000000; + x.b = rand() % 1000000; + } + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + std::sort(a, a+ARRAYSIZE, + [](const pair_t &x, const pair_t &y) { + int d = x.a - y.a; + return d < 0 || (d == 0 && x.b > y.b); + }); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + std::cout << "(" << a[ARRAYSIZE/2].a << ") C++ time for " << ARRAYSIZE + << " pairs: " << time << "s\n"; +} diff --git a/sort-benchmark/pairs/sort_parallel.cpp b/sort-benchmark/pairs/sort_parallel.cpp @@ -0,0 +1,35 @@ +/* Requires Thread Building Blocks (libtbb-dev on Debian) */ + +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <execution> +#include <iostream> + +typedef struct { int a, b; } pair_t; +pair_t a[ARRAYSIZE]; + +int main(void) { + srand(time(NULL)); + for (auto &x : a) { + x.a = rand() % 1000000; + x.b = rand() % 1000000; + } + + struct timespec begin; + clock_gettime(CLOCK_MONOTONIC, &begin); + + std::sort(std::execution::par, a, a+ARRAYSIZE, + [](const pair_t &x, const pair_t &y) { + int d = x.a - y.a; + return d < 0 || (d == 0 && x.b > y.b); + }); + + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + double time = end.tv_sec - begin.tv_sec + + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + std::cout << "(" << a[ARRAYSIZE/2].a << ") C++ time for " << ARRAYSIZE + << " pairs (parallel): " << time << "s\n"; +}