From c4913263ceba0a9ca80dc046891bba4eee57484f Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 17:25:40 -0700 Subject: [PATCH 01/16] Update to Python3; update README to improve instructions, incl. for Ubuntu 20.04 --- Makefile | 1 + README.md | 76 +++++++++++++++++++++++++++++----------- bench_collect_results.py | 14 ++++---- bench_plot_results.py | 18 +++++++--- 4 files changed, 77 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index c733300..32938c8 100755 --- a/Makefile +++ b/Makefile @@ -163,6 +163,7 @@ collect_results: @sudo lshw -short -class memory -class processor > $(results_dir)/hardware-inventory.txt @echo -n "Number of CPU cores: " >>$(results_dir)/hardware-inventory.txt @grep "processor" /proc/cpuinfo | wc -l >>$(results_dir)/hardware-inventory.txt + # NB: you may need to install `numactl` first with `sudo apt install numactl`. @(which numactl >/dev/null 2>&1) && echo "NUMA informations:" >>$(results_dir)/hardware-inventory.txt @(which numactl >/dev/null 2>&1) && numactl -H >>$(results_dir)/hardware-inventory.txt diff --git a/README.md b/README.md index 6636599..c3cee53 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,50 @@ # malloc-benchmarks -Simple benchmarking scripts to run on any machine to compare different C/C++ malloc implementations. -The scripts are not meant to face any possible problem, quite the opposite. +Simple benchmarking and plotting scripts to run on any machine to compare different C/C++ malloc implementations. +The scripts are not meant to face any possible problem; quite the opposite. They will: - download and build [GNU libc](https://www.gnu.org/software/libc/), [Google perftools](https://github.com/gperftools/gperftools), [Jemalloc](http://jemalloc.net/) - - use GNU libc malloc multi-thread benchmarking utility to generate JSON results for different combinations - of malloc implementation and number of threads - - use [Python matplotlib](https://matplotlib.org/) to produce a summary figure + - use the GNU libc malloc multi-threaded benchmarking utility to generate JSON results for different combinations + of malloc implementations and numbers of threads + - use [Python matplotlib](https://matplotlib.org/) to produce a plot of the results + + +## Dependencies + +If `make` below fails, you may need to install (via `sudo apt install`) one or more of the following. If you like, just begin by running the installation commands below. Last tested in Ubuntu 20.04. + +```bash +sudo apt update && sudo apt install \ + numactl g++ clang llvm-dev unzip dos2unix linuxinfo bc libgmp-dev wget \ + cmake python python3 ruby ninja-build libtool autoconf +# For Python +pip3 install matplotlib +``` ## How to collect benchmark results and view them +```bash +git clone https://github.com/f18m/malloc-benchmarks.git +cd malloc-benchmarks +make +# OR, time the process too to help you set expectations for how long it will take +time make +``` + +Once you have run `make`, the plot will display. To re-plot the results without rerunning the tests, run: +```bash +make plot_results ``` - git clone https://github.com/f18m/malloc-benchmarks.git - cd malloc-benchmarks - make + +Note that each time you run `make`, all of the benchmark results will be stored in a folder for your computer within the `results` dir, overwriting all previous results. So, if you wish to save previous benchmarking runs, be sure to rename your computer's folder in the `results` dir prior to running `make` again. + +You can customize the runs be setting environment variables as you call `make`. See the top of the `Makefile` for details. See the default values for `benchmark_nthreads` and `implem_list` in the `Makefile`. + +Examples: +```bash +# Run only 1 and 2 threads, testing only malloc implementations jemalloc and tcmalloc: +NTHREADS="1 2" IMPLEMENTATIONS="jemalloc tcmalloc" make ``` @@ -22,28 +52,32 @@ They will: On the machine where you want to collect benchmark results: -``` - git clone https://github.com/f18m/malloc-benchmarks.git - cd malloc-benchmarks - make download build collect_results - scp -r results IP_OF_OTHER_MACHINE: +```bash +git clone https://github.com/f18m/malloc-benchmarks.git +cd malloc-benchmarks +make download build collect_results +scp -r results IP_OF_OTHER_MACHINE: ``` On the other machine where you want to plot results: -``` - git clone https://github.com/f18m/malloc-benchmarks.git - cd malloc-benchmarks - mv ../results . - make plot_results +```bash +git clone https://github.com/f18m/malloc-benchmarks.git +cd malloc-benchmarks +mv ../results . +make plot_results ``` ## Example benchmarks -The following are some pictures obtained on different HW systems using however the same benchmarking utility written by -GNU libc developers. They give an idea on how much performances can be different on different CPU/memory HW and varying the number of threads. -Of course the closer the curves are to zero, the better they are (the lower the better!). +The following are some plots of results obtained on different hardware systems using the same benchmarking utility written by the +GNU libc developers. They give an idea of how much performance can differ on different CPU/memory hardware and a varying the number of threads. +Of course, the closer the curves are to zero, the better they are (the lower the better!). + +### To verify the version numbers for your benchmarks, look in the following places: +1. + diff --git a/bench_collect_results.py b/bench_collect_results.py index d6fd9f3..2950cee 100755 --- a/bench_collect_results.py +++ b/bench_collect_results.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 """Generate benchmarking results in JSON form, using GNU libc benchmarking utility; different allocators are injected into that utility by using LD_PRELOAD trick. """ @@ -43,7 +43,7 @@ def find(name, paths): for path in paths: - #print "Searching into: ", path + #print("Searching into: ", path) for root, dirs, files in os.walk(path, followlinks=False): if name in files: return os.path.join(root, name) @@ -107,7 +107,7 @@ def run_benchmark(outfile,thread_values,impl_name): os.environ["LD_PRELOAD"] = impl_preload_libs[impl_name] if len(os.environ["LD_PRELOAD"])>0: # the tcmalloc/jemalloc shared libs require in turn C++ libs: - #print "preload_required_libs_fullpaths is:", preload_required_libs_fullpaths + #print("preload_required_libs_fullpaths is:", preload_required_libs_fullpaths) for lib in preload_required_libs_fullpaths: os.environ["LD_PRELOAD"] = os.environ["LD_PRELOAD"] + ':' + lib @@ -156,13 +156,13 @@ def main(args): sys.exit(3) outfile = os.path.join(outfile_path_prefix, implementations[idx] + '-' + outfile_postfix) - print "----------------------------------------------------------------------------------------------" - print "Testing implementation '{}'. Saving results into '{}'".format(implementations[idx],outfile) + print("----------------------------------------------------------------------------------------------") + print("Testing implementation '{}'. Saving results into '{}'".format(implementations[idx],outfile)) - print "Will run tests for {} different number of threads".format(len(thread_values)) + print("Will run tests for {} different number of threads".format(len(thread_values))) success = success + run_benchmark(outfile,thread_values,implementations[idx]) - print "----------------------------------------------------------------------------------------------" + print("----------------------------------------------------------------------------------------------") return success if __name__ == '__main__': diff --git a/bench_plot_results.py b/bench_plot_results.py index 22e3ef9..d1b71a8 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 """Generates a figure that shows all benchmarking results """ import sys @@ -8,7 +8,7 @@ import matplotlib.pyplot as plotlib -BenchmarkPoint = collections.namedtuple('BenchmarkPoint', ['threads', 'time_per_iteration'], verbose=False) +BenchmarkPoint = collections.namedtuple('BenchmarkPoint', ['threads', 'time_per_iteration']) filled_markers = ('o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', 'P', 'X') colours = ('r', 'g', 'b', 'black', 'yellow', 'purple') @@ -32,8 +32,12 @@ def plot_graphs(outfilename, benchmark_dict): plotlib.setp(lines, 'color', colours[nmarker]) # remember max X/Y - max_x.append(max(X)) - max_y.append(max(Y)) + # In case you only ran some of the tests, don't attempt to get `max()` on an empty list--ie: + # for a benchmark you didn't run. Only operate if the lists aren't empty. + if X: + max_x.append(max(X)) + if Y: + max_y.append(max(Y)) nmarker=nmarker+1 @@ -42,6 +46,12 @@ def plot_graphs(outfilename, benchmark_dict): plotlib.ylim(0, max(max_y)*1.3) print("Writing plot into '%s'" % outfilename) + print("- - -\n" + + "Close the plot to terminate the program. Run `make plot_results` to plot the results\n" + + "again. Be sure to manually make a copy of the \"results\" folder (if you wish to\n" + + "save your results) before running `make` again, or else these results will be\n" + + "overwritten.\n" + + "- - -") plotlib.legend(loc='upper left') plotlib.savefig(outfilename) plotlib.show() From 8c3f76c2947262371d883382a4e6767e81d29e4f Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 18:06:28 -0700 Subject: [PATCH 02/16] Update README to show how to find versions --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c3cee53..fceb7f6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # malloc-benchmarks Simple benchmarking and plotting scripts to run on any machine to compare different C/C++ malloc implementations. -The scripts are not meant to face any possible problem; quite the opposite. +These scripts are not meant to face any possible problem; quite the opposite. They will: - - download and build [GNU libc](https://www.gnu.org/software/libc/), [Google perftools](https://github.com/gperftools/gperftools), [Jemalloc](http://jemalloc.net/) - - use the GNU libc malloc multi-threaded benchmarking utility to generate JSON results for different combinations +1. Download and build [GNU libc](https://www.gnu.org/software/libc/), [Google perftools](https://github.com/gperftools/gperftools), [Jemalloc](http://jemalloc.net/) +1. Use the GNU libc malloc multi-threaded benchmarking utility to generate JSON results for different combinations of malloc implementations and numbers of threads - - use [Python matplotlib](https://matplotlib.org/) to produce a plot of the results +1. Use [Python matplotlib](https://matplotlib.org/) to produce a plot of the results ## Dependencies @@ -75,8 +75,11 @@ The following are some plots of results obtained on different hardware systems u GNU libc developers. They give an idea of how much performance can differ on different CPU/memory hardware and a varying the number of threads. Of course, the closer the curves are to zero, the better they are (the lower the better!). -### To verify the version numbers for your benchmarks, look in the following places: -1. +**To verify the version numbers for your benchmarks, look in the following places after running `make`:** +1. **system_default:** run `apt show libc6` to see your system glibc version. Ex: `Version: 2.31-0ubuntu9.2` +1. **glibc:** See this file: `malloc-benchmarks/glibc/version.h` +1. **tcmalloc:** See the `TC_VERSION_STRING` value inside `malloc-benchmarks/tcmalloc-install/include/gperftools/tcmalloc.h` +1. **jemalloc:** See the `JEMALLOC_VERSION` value inside `malloc-benchmarks/jemalloc-install/include/jemalloc/jemalloc.h`
From 3842b238f8633ce64e3e06e96338a92916d44de0 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 18:07:51 -0700 Subject: [PATCH 03/16] Update readme w/reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fceb7f6..220dad0 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ GNU libc developers. They give an idea of how much performance can differ on dif Of course, the closer the curves are to zero, the better they are (the lower the better!). **To verify the version numbers for your benchmarks, look in the following places after running `make`:** -1. **system_default:** run `apt show libc6` to see your system glibc version. Ex: `Version: 2.31-0ubuntu9.2` +1. **system_default:** run `apt show libc6` to see your system glibc version ([source: "Determining the Installed glibc Version"](https://www.linode.com/docs/guides/patching-glibc-for-the-ghost-vulnerability/)). Ex: `Version: 2.31-0ubuntu9.2` 1. **glibc:** See this file: `malloc-benchmarks/glibc/version.h` 1. **tcmalloc:** See the `TC_VERSION_STRING` value inside `malloc-benchmarks/tcmalloc-install/include/gperftools/tcmalloc.h` 1. **jemalloc:** See the `JEMALLOC_VERSION` value inside `malloc-benchmarks/jemalloc-install/include/jemalloc/jemalloc.h` From 4c910ddbad3a73f09ffb8db3ff6e73206144f22d Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 18:35:49 -0700 Subject: [PATCH 04/16] Update notes in Makefile, and benchmark-src/README.md --- Makefile | 26 ++++++++++++++++---------- benchmark-src/README.md | 21 +++++++++++++++++++-- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 32938c8..9e54057 100755 --- a/Makefile +++ b/Makefile @@ -1,17 +1,22 @@ # # This makefile will build a small benchmarking utility for 'malloc' implementations and will -# run it with different implementations saving results into JSON files. +# run it with different implementations, first saving results into JSON files, and then plotting +# them graphically. # -# Specifically this makefile downloads, configure and compiles 3 different software packages: -# - GNU libc -# - Google perftools (tcmalloc) -# - jemalloc +# Specifically, this makefile downloads, configures and compiles these different software packages: +# 1. GNU libc +# 2. Google perftools (tcmalloc) +# 3. jemalloc # -# Tested with versions: -# - GNU libc 2.26 -# - Google perftools (tcmalloc) 2.6.3 -# - jemalloc 5.0.1 +# First tested with these versions: +# 1. GNU libc 2.26 +# 2. Google perftools (tcmalloc) 2.6.3 +# 3. jemalloc 5.0.1 # +# Most-recently tested on Ubuntu 20.04 with these versions: +# 1. GNU libc 2.31 +# 2. Google perftools (tcmalloc) 2.9.1 +# 3. jemalloc 5.2.1-742 # # @@ -76,6 +81,7 @@ glibc_url := git://sourceware.org/git/glibc.git tcmalloc_url := https://github.com/gperftools/gperftools.git jemalloc_url := https://github.com/jemalloc/jemalloc.git +# Alternate download version and source if not using the git repo above glibc_version := 2.26 glibc_alt_wget_url := https://ftpmirror.gnu.org/libc/glibc-$(glibc_version).tar.xz @@ -174,5 +180,5 @@ plot_results: upload_results: git add -f $(results_dir)/*$(benchmark_result_json) $(results_dir)/$(benchmark_result_png) $(results_dir)/hardware-inventory.txt git commit -m "Adding results from folder $(results_dir) to the GIT repository" - @echo "Run 'git push' to push online your results (required GIT repo write access)" + @echo "Run 'git push' to push online your results (requires GIT repo write access)" diff --git a/benchmark-src/README.md b/benchmark-src/README.md index 61a538b..7033b55 100644 --- a/benchmark-src/README.md +++ b/benchmark-src/README.md @@ -1,4 +1,21 @@ # Benchmark utility sources -The sources collected here are a small subset of GNU libc benchmarking utility for 'malloc' implementations. -Please see glibc/benchtests/bech-malloc-thread.c for the most up-to-date source code. +The sources collected here are a small subset of the GNU libc benchmarking utility for `malloc` implementations. + +Please see `glibc/benchtests/bech-malloc-thread.c` for the most up-to-date source code. + +You can obtain it here: https://www.gnu.org/software/libc/sources.html: +```bash +git clone https://sourceware.org/git/glibc.git +cd glibc +git checkout master +``` + +Mirror: https://github.com/bminor/glibc/tree/master/benchtests + +See also: +1. https://kazoo.ga/a-simple-tool-to-test-malloc-performance/ + + +## Each of the above source files came from the following glibc paths: +1. todo From 412db7013ca21a2e54f4c5e791bbdaf3fdae2272 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 18:42:10 -0700 Subject: [PATCH 05/16] Update README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 220dad0..dc241dc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +See the included glibc benchmark source code and readme here: [benchmark-src](benchmark-src) + + # malloc-benchmarks Simple benchmarking and plotting scripts to run on any machine to compare different C/C++ malloc implementations. @@ -44,7 +47,7 @@ You can customize the runs be setting environment variables as you call `make`. Examples: ```bash # Run only 1 and 2 threads, testing only malloc implementations jemalloc and tcmalloc: -NTHREADS="1 2" IMPLEMENTATIONS="jemalloc tcmalloc" make +NTHREADS="1 2" IMPLEMENTATIONS="jemalloc tcmalloc" time make ``` From 93d67bde9588cc5ce4db4928aa8d13501d9114ea Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 20:05:28 -0700 Subject: [PATCH 06/16] Update all benchmark-src files to latest from glibc --- benchmark-src/README.md | 30 ++++- benchmark-src/_itoa.h | 6 +- benchmark-src/bench-malloc-simple.c | 185 ++++++++++++++++++++++++++++ benchmark-src/bench-malloc-thread.c | 11 +- benchmark-src/bench-timing.h | 55 +++------ benchmark-src/hp-timing-common.h | 16 ++- benchmark-src/hp-timing.h | 49 +++++--- benchmark-src/json-lib.c | 4 +- benchmark-src/json-lib.h | 4 +- 9 files changed, 280 insertions(+), 80 deletions(-) create mode 100644 benchmark-src/bench-malloc-simple.c diff --git a/benchmark-src/README.md b/benchmark-src/README.md index 7033b55..6f6351d 100644 --- a/benchmark-src/README.md +++ b/benchmark-src/README.md @@ -18,4 +18,32 @@ See also: ## Each of the above source files came from the following glibc paths: -1. todo + +```bash +glibc/benchtests/bench-malloc-simple.c # <=== this one +glibc/benchtests/bench-malloc-thread.c # <=== this one + +glibc/benchtests/bench-timing.h # <=== this one + +glibc$ find | grep hp-timing\.h +./sysdeps/powerpc/powerpc64/hp-timing.h +./sysdeps/powerpc/powerpc32/power4/hp-timing.h +./sysdeps/s390/hp-timing.h +./sysdeps/x86/hp-timing.h # <=== this one +./sysdeps/alpha/hp-timing.h +./sysdeps/sparc/sparc32/sparcv9/hp-timing.h +./sysdeps/sparc/sparc64/hp-timing.h +./sysdeps/ia64/hp-timing.h +./sysdeps/generic/hp-timing.h +./sysdeps/mach/hurd/hp-timing.h + +glibc/sysdeps/generic/hp-timing-common.h # <=== this one + +glibc$ find | grep _itoa\.h +./sysdeps/x86_64/x32/_itoa.h +./sysdeps/mips/mips64/n32/_itoa.h +./sysdeps/generic/_itoa.h # <=== this one + +glibc/benchtests/json-lib.h # <=== this one +glibc/benchtests/json-lib.c # <=== this one +``` diff --git a/benchmark-src/_itoa.h b/benchmark-src/_itoa.h index 986df34..695fd85 100644 --- a/benchmark-src/_itoa.h +++ b/benchmark-src/_itoa.h @@ -1,5 +1,5 @@ /* Internal function for converting integers to ASCII. - Copyright (C) 1994-2017 Free Software Foundation, Inc. + Copyright (C) 1994-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ #ifndef _ITOA_H #define _ITOA_H @@ -35,8 +35,6 @@ # define _ITOA_WORD_TYPE unsigned long int #endif -#define attribute_hidden /* empty macro */ -#define IS_IN(x) 0 /* Convert VALUE into ASCII in base BASE (2..36). Write backwards starting the character just before BUFLIM. diff --git a/benchmark-src/bench-malloc-simple.c b/benchmark-src/bench-malloc-simple.c new file mode 100644 index 0000000..dd5b305 --- /dev/null +++ b/benchmark-src/bench-malloc-simple.c @@ -0,0 +1,185 @@ +/* Benchmark malloc and free functions. + Copyright (C) 2019-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include "bench-timing.h" +#include "json-lib.h" + +/* Benchmark the malloc/free performance of a varying number of blocks of a + given size. This enables performance tracking of the t-cache and fastbins. + It tests 3 different scenarios: single-threaded using main arena, + multi-threaded using thread-arena, and main arena with SINGLE_THREAD_P + false. */ + +#define NUM_ITERS 200000 +#define NUM_ALLOCS 4 +#define MAX_ALLOCS 1600 + +typedef struct +{ + size_t iters; + size_t size; + int n; + timing_t elapsed; +} malloc_args; + +static void +do_benchmark (malloc_args *args, int **arr) +{ + timing_t start, stop; + size_t iters = args->iters; + size_t size = args->size; + int n = args->n; + + TIMING_NOW (start); + + for (int j = 0; j < iters; j++) + { + for (int i = 0; i < n; i++) + arr[i] = malloc (size); + + for (int i = 0; i < n; i++) + free (arr[i]); + } + + TIMING_NOW (stop); + + TIMING_DIFF (args->elapsed, start, stop); +} + +static malloc_args tests[3][NUM_ALLOCS]; +static int allocs[NUM_ALLOCS] = { 25, 100, 400, MAX_ALLOCS }; + +static void * +thread_test (void *p) +{ + int **arr = (int**)p; + + /* Run benchmark multi-threaded. */ + for (int i = 0; i < NUM_ALLOCS; i++) + do_benchmark (&tests[2][i], arr); + + return p; +} + +void +bench (unsigned long size) +{ + size_t iters = NUM_ITERS; + int **arr = (int**) malloc (MAX_ALLOCS * sizeof (void*)); + + for (int t = 0; t < 3; t++) + for (int i = 0; i < NUM_ALLOCS; i++) + { + tests[t][i].n = allocs[i]; + tests[t][i].size = size; + tests[t][i].iters = iters / allocs[i]; + + /* Do a quick warmup run. */ + if (t == 0) + do_benchmark (&tests[0][i], arr); + } + + /* Run benchmark single threaded in main_arena. */ + for (int i = 0; i < NUM_ALLOCS; i++) + do_benchmark (&tests[0][i], arr); + + /* Run benchmark in a thread_arena. */ + pthread_t t; + pthread_create (&t, NULL, thread_test, (void*)arr); + pthread_join (t, NULL); + + /* Repeat benchmark in main_arena with SINGLE_THREAD_P == false. */ + for (int i = 0; i < NUM_ALLOCS; i++) + do_benchmark (&tests[1][i], arr); + + free (arr); + + json_ctx_t json_ctx; + + json_init (&json_ctx, 0, stdout); + + json_document_begin (&json_ctx); + + json_attr_string (&json_ctx, "timing_type", TIMING_TYPE); + + json_attr_object_begin (&json_ctx, "functions"); + + json_attr_object_begin (&json_ctx, "malloc"); + + char s[100]; + double iters2 = iters; + + json_attr_object_begin (&json_ctx, ""); + json_attr_double (&json_ctx, "malloc_block_size", size); + + struct rusage usage; + getrusage (RUSAGE_SELF, &usage); + json_attr_double (&json_ctx, "max_rss", usage.ru_maxrss); + + for (int i = 0; i < NUM_ALLOCS; i++) + { + sprintf (s, "main_arena_st_allocs_%04d_time", allocs[i]); + json_attr_double (&json_ctx, s, tests[0][i].elapsed / iters2); + } + + for (int i = 0; i < NUM_ALLOCS; i++) + { + sprintf (s, "main_arena_mt_allocs_%04d_time", allocs[i]); + json_attr_double (&json_ctx, s, tests[1][i].elapsed / iters2); + } + + for (int i = 0; i < NUM_ALLOCS; i++) + { + sprintf (s, "thread_arena__allocs_%04d_time", allocs[i]); + json_attr_double (&json_ctx, s, tests[2][i].elapsed / iters2); + } + + json_attr_object_end (&json_ctx); + + json_attr_object_end (&json_ctx); + + json_attr_object_end (&json_ctx); + + json_document_end (&json_ctx); +} + +static void usage (const char *name) +{ + fprintf (stderr, "%s: \n", name); + exit (1); +} + +int +main (int argc, char **argv) +{ + long val = 16; + if (argc == 2) + val = strtol (argv[1], NULL, 0); + + if (argc > 2 || val <= 0) + usage (argv[0]); + + bench (val); + + return 0; +} diff --git a/benchmark-src/bench-malloc-thread.c b/benchmark-src/bench-malloc-thread.c index 32cd5e3..04b98c0 100644 --- a/benchmark-src/bench-malloc-thread.c +++ b/benchmark-src/bench-malloc-thread.c @@ -1,5 +1,5 @@ /* Benchmark malloc and free functions. - Copyright (C) 2013-2017 Free Software Foundation, Inc. + Copyright (C) 2013-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ #include #include @@ -31,7 +31,7 @@ #include "json-lib.h" /* Benchmark duration in seconds. */ -#define BENCHMARK_DURATION 60 +#define BENCHMARK_DURATION 10 #define RAND_SEED 88 #ifndef NUM_THREADS @@ -225,7 +225,6 @@ main (int argc, char **argv) { timing_t cur; size_t iters = 0, num_threads = 1; - unsigned long res; json_ctx_t json_ctx; double d_total_s, d_total_i; struct sigaction act; @@ -261,10 +260,6 @@ main (int argc, char **argv) json_attr_object_begin (&json_ctx, ""); - TIMING_INIT (res); - - (void) res; - memset (&act, 0, sizeof (act)); act.sa_handler = &alarm_handler; diff --git a/benchmark-src/bench-timing.h b/benchmark-src/bench-timing.h index 302a84c..28fad56 100644 --- a/benchmark-src/bench-timing.h +++ b/benchmark-src/bench-timing.h @@ -1,5 +1,5 @@ /* Define timing macros. - Copyright (C) 2013-2017 Free Software Foundation, Inc. + Copyright (C) 2013-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,51 +14,26 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ -#include "hp-timing.h" +#undef attribute_hidden +#define attribute_hidden +#ifdef USE_CLOCK_GETTIME +# include +#else +# include +#endif #include -#if HP_TIMING_AVAIL && !defined USE_CLOCK_GETTIME -# define GL(x) _##x -# define GLRO(x) _##x +#define GL(x) _##x +#define GLRO(x) _##x typedef hp_timing_t timing_t; -# define TIMING_TYPE "hp_timing" - -# define TIMING_INIT(res) ({ (res) = 1; }) - -# define TIMING_NOW(var) HP_TIMING_NOW (var) -# define TIMING_DIFF(diff, start, end) HP_TIMING_DIFF ((diff), (start), (end)) -# define TIMING_ACCUM(sum, diff) HP_TIMING_ACCUM_NT ((sum), (diff)) - -#else - -#include -typedef uint64_t timing_t; - -# define TIMING_TYPE "clock_gettime" - -/* Measure the resolution of the clock so we can scale the number of - benchmark iterations by this value. */ -# define TIMING_INIT(res) \ -({ \ - struct timespec start; \ - clock_getres (CLOCK_PROCESS_CPUTIME_ID, &start); \ - (res) = start.tv_nsec; \ -}) +#define TIMING_TYPE "hp_timing" -# define TIMING_NOW(var) \ -({ \ - struct timespec tv; \ - clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &tv); \ - (var) = (uint64_t) (tv.tv_nsec + (uint64_t) 1000000000 * tv.tv_sec); \ -}) - -# define TIMING_DIFF(diff, start, end) (diff) = (end) - (start) -# define TIMING_ACCUM(sum, diff) (sum) += (diff) - -#endif +#define TIMING_NOW(var) HP_TIMING_NOW (var) +#define TIMING_DIFF(diff, start, end) HP_TIMING_DIFF ((diff), (start), (end)) +#define TIMING_ACCUM(sum, diff) HP_TIMING_ACCUM_NT ((sum), (diff)) #define TIMING_PRINT_MEAN(d_total_s, d_iters) \ printf ("\t%g", (d_total_s) / (d_iters)) diff --git a/benchmark-src/hp-timing-common.h b/benchmark-src/hp-timing-common.h index 63bf6a8..d59a27d 100644 --- a/benchmark-src/hp-timing-common.h +++ b/benchmark-src/hp-timing-common.h @@ -1,5 +1,5 @@ /* High precision, low overhead timing functions. Generic version. - Copyright (C) 1998-2017 Free Software Foundation, Inc. + Copyright (C) 1998-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1998. @@ -15,13 +15,11 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ /* In case a platform supports timers in the hardware the following macros and types must be defined: - - HP_TIMING_AVAIL: test for availability. - - HP_TIMING_INLINE: this macro is non-zero if the functionality is not implemented using function calls but instead uses some inlined code which might simply consist of a few assembler instructions. We have to @@ -39,7 +37,7 @@ #include #include -#include "_itoa.h" +#include <_itoa.h> /* Compute the difference between START and END, storing into DIFF. */ #define HP_TIMING_DIFF(Diff, Start, End) ((Diff) = (End) - (Start)) @@ -47,16 +45,16 @@ /* Accumulate ADD into SUM. No attempt is made to be thread-safe. */ #define HP_TIMING_ACCUM_NT(Sum, Diff) ((Sum) += (Diff)) +#define HP_TIMING_PRINT_SIZE (3 * sizeof (hp_timing_t) + 1) + /* Write a decimal representation of the timing value into the given string. */ #define HP_TIMING_PRINT(Dest, Len, Val) \ do { \ - char __buf[20]; \ + char __buf[HP_TIMING_PRINT_SIZE]; \ char *__dest = (Dest); \ size_t __len = (Len); \ char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0); \ size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len); \ memcpy (__dest, __cp, __cp_len); \ - memcpy (__dest + __cp_len, " cycles", \ - MIN (__len - __cp_len, sizeof (" cycles"))); \ - __dest[__len - 1] = '\0'; \ + __dest[__cp_len - 1] = '\0'; \ } while (0) diff --git a/benchmark-src/hp-timing.h b/benchmark-src/hp-timing.h index dab525a..196fef1 100644 --- a/benchmark-src/hp-timing.h +++ b/benchmark-src/hp-timing.h @@ -1,5 +1,5 @@ -/* High precision, low overhead timing functions. x86-64 version. - Copyright (C) 2002-2017 Free Software Foundation, Inc. +/* High precision, low overhead timing functions. x86 version. + Copyright (C) 2018-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,27 +14,48 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ #ifndef _HP_TIMING_H #define _HP_TIMING_H 1 -/* We always assume having the timestamp register. */ -#define HP_TIMING_AVAIL (1) -#define HP_SMALL_TIMING_AVAIL (1) +#include +#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 /* We indeed have inlined functions. */ -#define HP_TIMING_INLINE (1) +# define HP_TIMING_INLINE (1) /* We use 64bit values for the times. */ typedef unsigned long long int hp_timing_t; -/* The "=A" constraint used in 32-bit mode does not work in 64-bit mode. */ -#define HP_TIMING_NOW(Var) \ - ({ unsigned int _hi, _lo; \ - asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \ - (Var) = ((unsigned long long int) _hi << 32) | _lo; }) - -#include "hp-timing-common.h" +/* That's quite simple. Use the `rdtsc' instruction. Note that the value + might not be 100% accurate since there might be some more instructions + running in this moment. This could be changed by using a barrier like + 'cpuid' right before the `rdtsc' instruciton. But we are not interested + in accurate clock cycles here so we don't do this. + + NB: Use __builtin_ia32_rdtsc directly since including + makes building glibc very slow. */ +# ifdef USE_RDTSCP +/* RDTSCP waits until all previous instructions have executed and all + previous loads are globally visible before reading the counter. + RDTSC doesn't wait until all previous instructions have been executed + before reading the counter. */ +# define HP_TIMING_NOW(Var) \ + (__extension__ ({ \ + unsigned int __aux; \ + (Var) = __builtin_ia32_rdtscp (&__aux); \ + })) +# else +# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) +# endif + +# include +#else +/* NB: Undefine _HP_TIMING_H so that will + be included. */ +# undef _HP_TIMING_H +# include +#endif #endif /* hp-timing.h */ diff --git a/benchmark-src/json-lib.c b/benchmark-src/json-lib.c index 9743506..47ae82b 100644 --- a/benchmark-src/json-lib.c +++ b/benchmark-src/json-lib.c @@ -1,5 +1,5 @@ /* Simple library for printing JSON data. - Copyright (C) 2014-2017 Free Software Foundation, Inc. + Copyright (C) 2014-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ #include diff --git a/benchmark-src/json-lib.h b/benchmark-src/json-lib.h index b3df4b5..fb44174 100644 --- a/benchmark-src/json-lib.h +++ b/benchmark-src/json-lib.h @@ -1,5 +1,5 @@ /* Simple library for printing JSON data. - Copyright (C) 2014-2017 Free Software Foundation, Inc. + Copyright (C) 2014-2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -14,7 +14,7 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see - . */ + . */ #ifndef __JSON_LIB_H__ #define __JSON_LIB_H__ From e32c2a041d05877c957b58ab8ac47e5638d295ac Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sat, 26 Jun 2021 23:53:50 -0700 Subject: [PATCH 07/16] wip: continue adding more files to benchmark-src dir --- benchmark-src/Makefile | 2 +- benchmark-src/README.md | 9 + benchmark-src/isa.h | 24 + benchmark-src/libc-symbols.h | 1089 ++++++++++++++++++++++++++++++++++ 4 files changed, 1123 insertions(+), 1 deletion(-) create mode 100644 benchmark-src/isa.h create mode 100644 benchmark-src/libc-symbols.h diff --git a/benchmark-src/Makefile b/benchmark-src/Makefile index ca7e88e..8db744c 100644 --- a/benchmark-src/Makefile +++ b/benchmark-src/Makefile @@ -1,7 +1,7 @@ TARGET = bench-malloc-thread LIBS = -lpthread CC = gcc -CFLAGS = -g -Wall -O2 -std=gnu99 +CFLAGS = -g -Wall -O2 -std=gnu99 -I. -include libc-symbols.h .PHONY: default all clean diff --git a/benchmark-src/README.md b/benchmark-src/README.md index 6f6351d..83be582 100644 --- a/benchmark-src/README.md +++ b/benchmark-src/README.md @@ -46,4 +46,13 @@ glibc$ find | grep _itoa\.h glibc/benchtests/json-lib.h # <=== this one glibc/benchtests/json-lib.c # <=== this one + +glibc$ find | grep isa\.h +./sysdeps/x86_64/isa.h # <=== this one +./sysdeps/i386/i586/isa.h +./sysdeps/i386/i686/isa.h +./sysdeps/i386/isa.h +./sysdeps/x86/tst-ifunc-isa.h + +glibc/include/libc-symbols.h # <=== this one ``` diff --git a/benchmark-src/isa.h b/benchmark-src/isa.h new file mode 100644 index 0000000..38028e4 --- /dev/null +++ b/benchmark-src/isa.h @@ -0,0 +1,24 @@ +/* x86 ISA info. x86-64 version. + Copyright (C) 2018-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ISA_H +#define _ISA_H + +#define MINIMUM_ISA 8664 + +#endif diff --git a/benchmark-src/libc-symbols.h b/benchmark-src/libc-symbols.h new file mode 100644 index 0000000..127ea65 --- /dev/null +++ b/benchmark-src/libc-symbols.h @@ -0,0 +1,1089 @@ +/* Support macros for making weak and strong aliases for symbols, + and for using symbol sets and linker warnings with GNU ld. + Copyright (C) 1995-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC_SYMBOLS_H +#define _LIBC_SYMBOLS_H 1 + +/* This file is included implicitly in the compilation of every source file, + using -include. It includes config.h. */ + +/* Enable declarations of GNU extensions, since we are compiling them. */ +#define _GNU_SOURCE 1 + +#ifdef MODULE_NAME + +/* Use `#if IS_IN (module)` to detect what component is being compiled. */ +#define PASTE_NAME1(a,b) a##b +#define PASTE_NAME(a,b) PASTE_NAME1 (a,b) +#define IN_MODULE PASTE_NAME (MODULE_, MODULE_NAME) +#define IS_IN(lib) (IN_MODULE == MODULE_##lib) + +/* True if the current module is a versioned library. Versioned + library names culled from shlib-versions files are assigned a + MODULE_* value greater than MODULE_LIBS_BEGIN. */ +#define IS_IN_LIB (IN_MODULE > MODULE_LIBS_BEGIN) + +/* The testsuite, and some other ancillary code, should be compiled against + as close an approximation to the installed headers as possible. + Defining this symbol disables most internal-use-only declarations + provided by this header, and all those provided by other internal + wrapper headers. */ +#if IS_IN (testsuite) || defined IS_IN_build || defined __cplusplus +# define _ISOMAC 1 +#endif + +#else +/* The generation process for a few files created very early in the + build (notably libc-modules.h itself) involves preprocessing this + header without defining MODULE_NAME. Under these conditions, + internal declarations (especially from config.h) must be visible, + but IS_IN should always evaluate as false. */ +# define IS_IN(lib) 0 +# define IS_IN_LIB 0 +# define IN_MODULE (-1) +#endif + +#ifndef _ISOMAC + +/* This is defined for the compilation of all C library code. features.h + tests this to avoid inclusion of stubs.h while compiling the library, + before stubs.h has been generated. Some library code that is shared + with other packages also tests this symbol to see if it is being + compiled as part of the C library. We must define this before including + config.h, because it makes some definitions conditional on whether libc + itself is being compiled, or just some generator program. */ +#define _LIBC 1 + +/* Some files must be compiled with optimization on. */ +#if !defined __ASSEMBLER__ && !defined __OPTIMIZE__ +# error "glibc cannot be compiled without optimization" +#endif + +/* -ffast-math cannot be applied to the C library, as it alters the ABI. + Some test components that use -ffast-math are currently not part of + IS_IN (testsuite) for technical reasons, so we have a secondary override. */ +#if defined __FAST_MATH__ && !defined TEST_FAST_MATH +# error "glibc must not be compiled with -ffast-math" +#endif + +#include + +/* Obtain the definition of symbol_version_reference. */ +#include + +/* When PIC is defined and SHARED isn't defined, we are building PIE + by default. */ +#if defined PIC && !defined SHARED +# define BUILD_PIE_DEFAULT 1 +#else +# define BUILD_PIE_DEFAULT 0 +#endif + +/* Define this for the benefit of portable GNU code that wants to check it. + Code that checks with #if will not #include again, since we've + already done it (and this file is implicitly included in every compile, + via -include). Code that checks with #ifdef will #include , + but that file should always be idempotent (i.e., it's just #define/#undef + and nothing else anywhere should be changing the macro state it touches), + so it's harmless. */ +#define HAVE_CONFIG_H 0 + +/* Define these macros for the benefit of portable GNU code that wants to check + them. Of course, STDC_HEADERS is never false when building libc! */ +#define STDC_HEADERS 1 +#define HAVE_MBSTATE_T 1 +#define HAVE_MBSRTOWCS 1 +#define HAVE_LIBINTL_H 1 +#define HAVE_WCTYPE_H 1 +#define HAVE_ISWCTYPE 1 +#define ENABLE_NLS 1 + +/* The symbols in all the user (non-_) macros are C symbols. */ + +#ifndef __SYMBOL_PREFIX +# define __SYMBOL_PREFIX +#endif + +#ifndef C_SYMBOL_NAME +# define C_SYMBOL_NAME(name) name +#endif + +#ifndef ASM_LINE_SEP +# define ASM_LINE_SEP ; +#endif + +#ifndef __attribute_copy__ +/* Provide an empty definition when cdefs.h is not included. */ +# define __attribute_copy__(arg) +#endif + +#ifndef __ASSEMBLER__ +/* GCC understands weak symbols and aliases; use its interface where + possible, instead of embedded assembly language. */ + +/* Define ALIASNAME as a strong alias for NAME. */ +# define strong_alias(name, aliasname) _strong_alias(name, aliasname) +# define _strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))) \ + __attribute_copy__ (name); + +/* This comes between the return type and function name in + a function definition to make that definition weak. */ +# define weak_function __attribute__ ((weak)) +# define weak_const_function __attribute__ ((weak, __const__)) + +/* Define ALIASNAME as a weak alias for NAME. + If weak aliases are not available, this defines a strong alias. */ +# define weak_alias(name, aliasname) _weak_alias (name, aliasname) +# define _weak_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))) \ + __attribute_copy__ (name); + +/* Same as WEAK_ALIAS, but mark symbol as hidden. */ +# define weak_hidden_alias(name, aliasname) \ + _weak_hidden_alias (name, aliasname) +# define _weak_hidden_alias(name, aliasname) \ + extern __typeof (name) aliasname \ + __attribute__ ((weak, alias (#name), __visibility__ ("hidden"))) \ + __attribute_copy__ (name); + +/* Declare SYMBOL as weak undefined symbol (resolved to 0 if not defined). */ +# define weak_extern(symbol) _weak_extern (weak symbol) +# define _weak_extern(expr) _Pragma (#expr) + +/* In shared builds, the expression call_function_static_weak + (FUNCTION-SYMBOL, ARGUMENTS) invokes FUNCTION-SYMBOL (an + identifier) unconditionally, with the (potentially empty) argument + list ARGUMENTS. In static builds, if FUNCTION-SYMBOL has a + definition, the function is invoked as before; if FUNCTION-SYMBOL + is NULL, no call is performed. */ +# ifdef SHARED +# define call_function_static_weak(func, ...) func (__VA_ARGS__) +# else /* !SHARED */ +# define call_function_static_weak(func, ...) \ + ({ \ + extern __typeof__ (func) func weak_function; \ + (func != NULL ? func (__VA_ARGS__) : (void)0); \ + }) +# endif + +#else /* __ASSEMBLER__ */ + +# ifdef HAVE_ASM_SET_DIRECTIVE +# define strong_alias(original, alias) \ + .globl C_SYMBOL_NAME (alias) ASM_LINE_SEP \ + .set C_SYMBOL_NAME (alias),C_SYMBOL_NAME (original) +# define strong_data_alias(original, alias) strong_alias(original, alias) +# else +# define strong_alias(original, alias) \ + .globl C_SYMBOL_NAME (alias) ASM_LINE_SEP \ + C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) +# define strong_data_alias(original, alias) strong_alias(original, alias) +# endif + +# define weak_alias(original, alias) \ + .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \ + C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) + +# define weak_extern(symbol) \ + .weak C_SYMBOL_NAME (symbol) + +#endif /* __ASSEMBLER__ */ + +/* Determine the return address. */ +#define RETURN_ADDRESS(nr) \ + __builtin_extract_return_addr (__builtin_return_address (nr)) + +/* When a reference to SYMBOL is encountered, the linker will emit a + warning message MSG. */ +/* We want the .gnu.warning.SYMBOL section to be unallocated. */ +#define __make_section_unallocated(section_string) \ + asm (".section " section_string "\n\t.previous"); + +/* Tacking on "\n\t#" to the section name makes gcc put it's bogus + section attributes on what looks like a comment to the assembler. */ +#ifdef HAVE_SECTION_QUOTES +# define __sec_comment "\"\n\t#\"" +#else +# define __sec_comment "\n\t#" +#endif +#define link_warning(symbol, msg) \ + __make_section_unallocated (".gnu.warning." #symbol) \ + static const char __evoke_link_warning_##symbol[] \ + __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \ + = msg; + +/* A canned warning for sysdeps/stub functions. */ +#define stub_warning(name) \ + __make_section_unallocated (".gnu.glibc-stub." #name) \ + link_warning (name, #name " is not implemented and will always fail") + +/* Warning for linking functions calling dlopen into static binaries. */ +#ifdef SHARED +#define static_link_warning(name) +#else +#define static_link_warning(name) static_link_warning1(name) +#define static_link_warning1(name) \ + link_warning(name, "Using '" #name "' in statically linked applications \ +requires at runtime the shared libraries from the glibc version used \ +for linking") +#endif + +/* Resource Freeing Hooks: + + Normally a process exits and the OS cleans up any allocated + memory. However, when tooling like mtrace or valgrind is monitoring + the process we need to free all resources that are part of the + process in order to provide the consistency required to track + memory leaks. + + A single public API exists and is __libc_freeres(), and this is used + by applications like valgrind to freee resouces. + + There are 3 cases: + + (a) __libc_freeres + + In this case all you need to do is define the freeing routine: + + foo.c: + libfoo_freeres_fn (foo_freeres) + { + complex_free (mem); + } + + This ensures the function is called at the right point to free + resources. + + (b) __libc_freeres_ptr + + The framework for (a) iterates over the list of pointers-to-free + in (b) and frees them. + + foo.c: + libc_freeres_ptr (static char *foo_buffer); + + Freeing these resources alaways happens last and is equivalent + to registering a function that does 'free (foo_buffer)'. + + (c) Explicit lists of free routines to call or objects to free. + + It is the intended goal to remove (a) and (b) which have some + non-determinism based on link order, and instead use explicit + lists of functions and frees to resolve cleanup ordering issues + and make it easy to debug and maintain. + + As of today the following subsystems use (c): + + Per-thread cleanup: + * malloc/thread-freeres.c + + libdl cleanup: + * dlfcn/dlfreeres.c + + libpthread cleanup: + * nptl/nptlfreeres.c + + So if you need any shutdown routines to run you should add them + directly to the appropriate subsystem's shutdown list. */ + +/* Resource pointers to free in libc.so. */ +#define libc_freeres_ptr(decl) \ + __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \ + decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment))) + +/* Resource freeing functions from libc.so go in this section. */ +#define __libc_freeres_fn_section \ + __attribute__ ((__used__, section ("__libc_freeres_fn"))) + +/* Resource freeing functions for libc.so. */ +#define libc_freeres_fn(name) \ + static void name (void) __attribute_used__ __libc_freeres_fn_section; \ + text_set_element (__libc_subfreeres, name); \ + static void name (void) + +/* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes + alias to ORIGINAL, when the assembler supports such declarations + (such as in ELF). + This is only necessary when defining something in assembly, or playing + funny alias games where the size should be other than what the compiler + thinks it is. */ +#define declare_symbol_alias(symbol, original, type, size) \ + declare_symbol_alias_1 (symbol, original, type, size) +#ifdef __ASSEMBLER__ +# define declare_symbol_alias_1(symbol, original, type, size) \ + strong_alias (original, symbol); \ + .type C_SYMBOL_NAME (symbol), %##type; \ + .size C_SYMBOL_NAME (symbol), size +#else /* Not __ASSEMBLER__. */ +# define declare_symbol_alias_1(symbol, original, type, size) \ + asm (".globl " __SYMBOL_PREFIX #symbol \ + "\n\t" declare_symbol_alias_1_alias (symbol, original) \ + "\n\t.type " __SYMBOL_PREFIX #symbol ", " \ + "%" #type \ + "\n\t.size " __SYMBOL_PREFIX #symbol ", " #size); +# ifdef HAVE_ASM_SET_DIRECTIVE +# define declare_symbol_alias_1_alias(symbol, original) \ + ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX #original +# else +# define declare_symbol_alias_1_alias(symbol, original) \ + __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX #original +# endif /* HAVE_ASM_SET_DIRECTIVE */ +#endif /* __ASSEMBLER__ */ + + +/* + +*/ + +#ifdef HAVE_GNU_RETAIN +# define attribute_used_retain __attribute__ ((__used__, __retain__)) +#else +# define attribute_used_retain __attribute__ ((__used__)) +#endif + +/* Symbol set support macros. */ + +/* Make SYMBOL, which is in the text segment, an element of SET. */ +#define text_set_element(set, symbol) _elf_set_element(set, symbol) +/* Make SYMBOL, which is in the data segment, an element of SET. */ +#define data_set_element(set, symbol) _elf_set_element(set, symbol) +/* Make SYMBOL, which is in the bss segment, an element of SET. */ +#define bss_set_element(set, symbol) _elf_set_element(set, symbol) + +/* These are all done the same way in ELF. + There is a new section created for each set. */ +#ifdef SHARED +/* When building a shared library, make the set section writable, + because it will need to be relocated at run time anyway. */ +# define _elf_set_element(set, symbol) \ + static const void *__elf_set_##set##_element_##symbol##__ \ + attribute_used_retain __attribute__ ((section (#set))) = &(symbol) +#else +# define _elf_set_element(set, symbol) \ + static const void *const __elf_set_##set##_element_##symbol##__ \ + attribute_used_retain __attribute__ ((section (#set))) = &(symbol) +#endif + +/* Define SET as a symbol set. This may be required (it is in a.out) to + be able to use the set's contents. */ +#define symbol_set_define(set) symbol_set_declare(set) + +/* Declare SET for use in this module, if defined in another module. + In a shared library, this is always local to that shared object. + For static linking, the set might be wholly absent and so we use + weak references. */ +#define symbol_set_declare(set) \ + extern char const __start_##set[] __symbol_set_attribute; \ + extern char const __stop_##set[] __symbol_set_attribute; +#ifdef SHARED +# define __symbol_set_attribute attribute_hidden +#else +# define __symbol_set_attribute __attribute__ ((weak)) +#endif + +/* Return a pointer (void *const *) to the first element of SET. */ +#define symbol_set_first_element(set) ((void *const *) (&__start_##set)) + +/* Return true iff PTR (a void *const *) has been incremented + past the last element in SET. */ +#define symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set) + +#ifdef SHARED +# define symbol_version(real, name, version) \ + symbol_version_reference(real, name, version) +# define default_symbol_version(real, name, version) \ + _default_symbol_version(real, name, version) +/* See . */ +# ifdef __ASSEMBLER__ +# define _default_symbol_version(real, name, version) \ + _set_symbol_version (real, name@@version) +# else +# define _default_symbol_version(real, name, version) \ + _set_symbol_version (real, #name "@@" #version) +# endif + +/* Evalutes to a string literal for VERSION in LIB. */ +# define symbol_version_string(lib, version) \ + _symbol_version_stringify_1 (VERSION_##lib##_##version) +# define _symbol_version_stringify_1(arg) _symbol_version_stringify_2 (arg) +# define _symbol_version_stringify_2(arg) #arg + +#else /* !SHARED */ +# define symbol_version(real, name, version) +# define default_symbol_version(real, name, version) \ + strong_alias(real, name) +#endif + +#if defined SHARED || defined LIBC_NONSHARED \ + || (BUILD_PIE_DEFAULT && IS_IN (libc)) +# define attribute_hidden __attribute__ ((visibility ("hidden"))) +#else +# define attribute_hidden +#endif + +#define attribute_tls_model_ie __attribute__ ((tls_model ("initial-exec"))) + +#define attribute_relro __attribute__ ((section (".data.rel.ro"))) + + +/* Used to disable stack protection in sensitive places, like ifunc + resolvers and early static TLS init. */ +#ifdef HAVE_CC_NO_STACK_PROTECTOR +# define inhibit_stack_protector \ + __attribute__ ((__optimize__ ("-fno-stack-protector"))) +#else +# define inhibit_stack_protector +#endif + +/* The following macros are used for PLT bypassing within libc.so + (and if needed other libraries similarly). + First of all, you need to have the function prototyped somewhere, + say in foo/foo.h: + + int foo (int __bar); + + If calls to foo within libc.so should always go to foo defined in libc.so, + then in include/foo.h you add: + + libc_hidden_proto (foo) + + line and after the foo function definition: + + int foo (int __bar) + { + return __bar; + } + libc_hidden_def (foo) + + or + + int foo (int __bar) + { + return __bar; + } + libc_hidden_weak (foo) + + Similarly for global data. If references to foo within libc.so should + always go to foo defined in libc.so, then in include/foo.h you add: + + libc_hidden_proto (foo) + + line and after foo's definition: + + int foo = INITIAL_FOO_VALUE; + libc_hidden_data_def (foo) + + or + + int foo = INITIAL_FOO_VALUE; + libc_hidden_data_weak (foo) + + If foo is normally just an alias (strong or weak) to some other function, + you should use the normal strong_alias first, then add libc_hidden_def + or libc_hidden_weak: + + int baz (int __bar) + { + return __bar; + } + strong_alias (baz, foo) + libc_hidden_weak (foo) + + If the function should be internal to multiple objects, say ld.so and + libc.so, the best way is to use: + + #if IS_IN (libc) || IS_IN (rtld) + hidden_proto (foo) + #endif + + in include/foo.h and the normal macros at all function definitions + depending on what DSO they belong to. + + If versioned_symbol macro is used to define foo, + libc_hidden_ver macro should be used, as in: + + int __real_foo (int __bar) + { + return __bar; + } + versioned_symbol (libc, __real_foo, foo, GLIBC_2_1); + libc_hidden_ver (__real_foo, foo) */ + +#if defined SHARED && !defined NO_HIDDEN +# ifndef __ASSEMBLER__ +# define __hidden_proto_hiddenattr(attrs...) \ + __attribute__ ((visibility ("hidden"), ##attrs)) +# define hidden_proto(name, attrs...) \ + __hidden_proto (name, , __GI_##name, ##attrs) +# define hidden_tls_proto(name, attrs...) \ + __hidden_proto (name, __thread, __GI_##name, ##attrs) +# define __hidden_proto(name, thread, internal, attrs...) \ + extern thread __typeof (name) name __asm__ (__hidden_asmname (#internal)) \ + __hidden_proto_hiddenattr (attrs); +# define __hidden_asmname(name) \ + __hidden_asmname1 (__USER_LABEL_PREFIX__, name) +# define __hidden_asmname1(prefix, name) __hidden_asmname2(prefix, name) +# define __hidden_asmname2(prefix, name) #prefix name +# define __hidden_ver1(local, internal, name) \ + __hidden_ver2 (, local, internal, name) +# define __hidden_ver2(thread, local, internal, name) \ + extern thread __typeof (name) __EI_##name \ + __asm__(__hidden_asmname (#internal)); \ + extern thread __typeof (name) __EI_##name \ + __attribute__((alias (__hidden_asmname (#local)))) \ + __attribute_copy__ (name) +# define hidden_ver(local, name) __hidden_ver1(local, __GI_##name, name); +# define hidden_data_ver(local, name) hidden_ver(local, name) +# define hidden_def(name) __hidden_ver1(__GI_##name, name, name); +# define hidden_data_def(name) hidden_def(name) +# define hidden_tls_def(name) \ + __hidden_ver2 (__thread, __GI_##name, name, name); +# define hidden_weak(name) \ + __hidden_ver1(__GI_##name, name, name) __attribute__((weak)); +# define hidden_data_weak(name) hidden_weak(name) +# define hidden_nolink(name, lib, version) \ + __hidden_nolink1 (__GI_##name, __EI_##name, name, VERSION_##lib##_##version) +# define __hidden_nolink1(local, internal, name, version) \ + __hidden_nolink2 (local, internal, name, version) +# define __hidden_nolink2(local, internal, name, version) \ + extern __typeof (name) internal __attribute__ ((alias (#local))) \ + __attribute_copy__ (name); \ + __hidden_nolink3 (local, internal, #name "@" #version) +# define __hidden_nolink3(local, internal, vername) \ + __asm__ (".symver " #internal ", " vername); +# else +/* For assembly, we need to do the opposite of what we do in C: + in assembly gcc __REDIRECT stuff is not in place, so functions + are defined by its normal name and we need to create the + __GI_* alias to it, in C __REDIRECT causes the function definition + to use __GI_* name and we need to add alias to the real name. + There is no reason to use hidden_weak over hidden_def in assembly, + but we provide it for consistency with the C usage. + hidden_proto doesn't make sense for assembly but the equivalent + is to call via the HIDDEN_JUMPTARGET macro instead of JUMPTARGET. */ +# define hidden_def(name) strong_alias (name, __GI_##name) +# define hidden_weak(name) hidden_def (name) +# define hidden_ver(local, name) strong_alias (local, __GI_##name) +# define hidden_data_def(name) strong_data_alias (name, __GI_##name) +# define hidden_tls_def(name) hidden_data_def (name) +# define hidden_data_weak(name) hidden_data_def (name) +# define hidden_data_ver(local, name) strong_data_alias (local, __GI_##name) +# define HIDDEN_JUMPTARGET(name) __GI_##name +# endif +#else +# ifndef __ASSEMBLER__ +# if !defined SHARED && IS_IN (libc) && !defined LIBC_NONSHARED \ + && (!defined PIC || !defined NO_HIDDEN_EXTERN_FUNC_IN_PIE) \ + && !defined NO_HIDDEN +# define __hidden_proto_hiddenattr(attrs...) \ + __attribute__ ((visibility ("hidden"), ##attrs)) +# define hidden_proto(name, attrs...) \ + __hidden_proto (name, , name, ##attrs) +# define hidden_tls_proto(name, attrs...) \ + __hidden_proto (name, __thread, name, ##attrs) +# define __hidden_proto(name, thread, internal, attrs...) \ + extern thread __typeof (name) name __hidden_proto_hiddenattr (attrs); +# else +# define hidden_proto(name, attrs...) +# define hidden_tls_proto(name, attrs...) +# endif +# else +# define HIDDEN_JUMPTARGET(name) JUMPTARGET(name) +# endif /* Not __ASSEMBLER__ */ +# define hidden_weak(name) +# define hidden_def(name) +# define hidden_ver(local, name) +# define hidden_data_weak(name) +# define hidden_data_def(name) +# define hidden_tls_def(name) +# define hidden_data_ver(local, name) +# define hidden_nolink(name, lib, version) +#endif + +#if IS_IN (libc) +# define libc_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libc_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) +# define libc_hidden_def(name) hidden_def (name) +# define libc_hidden_weak(name) hidden_weak (name) +# define libc_hidden_nolink_sunrpc(name, version) hidden_nolink (name, libc, version) +# define libc_hidden_ver(local, name) hidden_ver (local, name) +# define libc_hidden_data_def(name) hidden_data_def (name) +# define libc_hidden_tls_def(name) hidden_tls_def (name) +# define libc_hidden_data_weak(name) hidden_data_weak (name) +# define libc_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libc_hidden_proto(name, attrs...) +# define libc_hidden_tls_proto(name, attrs...) +# define libc_hidden_def(name) +# define libc_hidden_weak(name) +# define libc_hidden_ver(local, name) +# define libc_hidden_data_def(name) +# define libc_hidden_tls_def(name) +# define libc_hidden_data_weak(name) +# define libc_hidden_data_ver(local, name) +#endif + +#if IS_IN (rtld) +# define rtld_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define rtld_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) +# define rtld_hidden_def(name) hidden_def (name) +# define rtld_hidden_weak(name) hidden_weak (name) +# define rtld_hidden_ver(local, name) hidden_ver (local, name) +# define rtld_hidden_data_def(name) hidden_data_def (name) +# define rtld_hidden_tls_def(name) hidden_tls_def (name) +# define rtld_hidden_data_weak(name) hidden_data_weak (name) +# define rtld_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define rtld_hidden_proto(name, attrs...) +# define rtld_hidden_tls_proto(name, attrs...) +# define rtld_hidden_def(name) +# define rtld_hidden_weak(name) +# define rtld_hidden_ver(local, name) +# define rtld_hidden_data_def(name) +# define rtld_hidden_tls_def(name) +# define rtld_hidden_data_weak(name) +# define rtld_hidden_data_ver(local, name) +#endif + +#if IS_IN (libm) +# define libm_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libm_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) +# define libm_hidden_def(name) hidden_def (name) +# define libm_hidden_weak(name) hidden_weak (name) +# define libm_hidden_ver(local, name) hidden_ver (local, name) +# define libm_hidden_data_def(name) hidden_data_def (name) +# define libm_hidden_tls_def(name) hidden_tls_def (name) +# define libm_hidden_data_weak(name) hidden_data_weak (name) +# define libm_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libm_hidden_proto(name, attrs...) +# define libm_hidden_tls_proto(name, attrs...) +# define libm_hidden_def(name) +# define libm_hidden_weak(name) +# define libm_hidden_ver(local, name) +# define libm_hidden_data_def(name) +# define libm_hidden_tls_def(name) +# define libm_hidden_data_weak(name) +# define libm_hidden_data_ver(local, name) +#endif + +#if IS_IN (libmvec) +# define libmvec_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libmvec_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) +# define libmvec_hidden_def(name) hidden_def (name) +# define libmvec_hidden_weak(name) hidden_weak (name) +# define libmvec_hidden_ver(local, name) hidden_ver (local, name) +# define libmvec_hidden_data_def(name) hidden_data_def (name) +# define libmvec_hidden_tls_def(name) hidden_tls_def (name) +# define libmvec_hidden_data_weak(name) hidden_data_weak (name) +# define libmvec_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libmvec_hidden_proto(name, attrs...) +# define libmvec_hidden_tls_proto(name, attrs...) +# define libmvec_hidden_def(name) +# define libmvec_hidden_weak(name) +# define libmvec_hidden_ver(local, name) +# define libmvec_hidden_data_def(name) +# define libmvec_hidden_tls_def(name) +# define libmvec_hidden_data_weak(name) +# define libmvec_hidden_data_ver(local, name) +#endif + +#if IS_IN (libresolv) +# define libresolv_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libresolv_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libresolv_hidden_def(name) hidden_def (name) +# define libresolv_hidden_weak(name) hidden_weak (name) +# define libresolv_hidden_ver(local, name) hidden_ver (local, name) +# define libresolv_hidden_data_def(name) hidden_data_def (name) +# define libresolv_hidden_tls_def(name) hidden_tls_def (name) +# define libresolv_hidden_data_weak(name) hidden_data_weak (name) +# define libresolv_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libresolv_hidden_proto(name, attrs...) +# define libresolv_hidden_tls_proto(name, attrs...) +# define libresolv_hidden_def(name) +# define libresolv_hidden_weak(name) +# define libresolv_hidden_ver(local, name) +# define libresolv_hidden_data_def(name) +# define libresolv_hidden_tls_def(name) +# define libresolv_hidden_data_weak(name) +# define libresolv_hidden_data_ver(local, name) +#endif + +#if IS_IN (libpthread) +# define libpthread_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libpthread_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libpthread_hidden_def(name) hidden_def (name) +# define libpthread_hidden_weak(name) hidden_weak (name) +# define libpthread_hidden_ver(local, name) hidden_ver (local, name) +# define libpthread_hidden_data_def(name) hidden_data_def (name) +# define libpthread_hidden_tls_def(name) hidden_tls_def (name) +# define libpthread_hidden_data_weak(name) hidden_data_weak (name) +# define libpthread_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libpthread_hidden_proto(name, attrs...) +# define libpthread_hidden_tls_proto(name, attrs...) +# define libpthread_hidden_def(name) +# define libpthread_hidden_weak(name) +# define libpthread_hidden_ver(local, name) +# define libpthread_hidden_data_def(name) +# define libpthread_hidden_tls_def(name) +# define libpthread_hidden_data_weak(name) +# define libpthread_hidden_data_ver(local, name) +#endif + +#if IS_IN (librt) +# define librt_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define librt_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define librt_hidden_def(name) hidden_def (name) +# define librt_hidden_weak(name) hidden_weak (name) +# define librt_hidden_ver(local, name) hidden_ver (local, name) +# define librt_hidden_data_def(name) hidden_data_def (name) +# define librt_hidden_tls_def(name) hidden_tls_def (name) +# define librt_hidden_data_weak(name) hidden_data_weak (name) +# define librt_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define librt_hidden_proto(name, attrs...) +# define librt_hidden_tls_proto(name, attrs...) +# define librt_hidden_def(name) +# define librt_hidden_weak(name) +# define librt_hidden_ver(local, name) +# define librt_hidden_data_def(name) +# define librt_hidden_tls_def(name) +# define librt_hidden_data_weak(name) +# define librt_hidden_data_ver(local, name) +#endif + +#if IS_IN (libdl) +# define libdl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libdl_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libdl_hidden_def(name) hidden_def (name) +# define libdl_hidden_weak(name) hidden_weak (name) +# define libdl_hidden_ver(local, name) hidden_ver (local, name) +# define libdl_hidden_data_def(name) hidden_data_def (name) +# define libdl_hidden_tls_def(name) hidden_tls_def (name) +# define libdl_hidden_data_weak(name) hidden_data_weak (name) +# define libdl_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libdl_hidden_proto(name, attrs...) +# define libdl_hidden_tls_proto(name, attrs...) +# define libdl_hidden_def(name) +# define libdl_hidden_weak(name) +# define libdl_hidden_ver(local, name) +# define libdl_hidden_data_def(name) +# define libdl_hidden_tls_def(name) +# define libdl_hidden_data_weak(name) +# define libdl_hidden_data_ver(local, name) +#endif + +#if IS_IN (libnss_files) +# define libnss_files_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libnss_files_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libnss_files_hidden_def(name) hidden_def (name) +# define libnss_files_hidden_weak(name) hidden_weak (name) +# define libnss_files_hidden_ver(local, name) hidden_ver (local, name) +# define libnss_files_hidden_data_def(name) hidden_data_def (name) +# define libnss_files_hidden_tls_def(name) hidden_tls_def (name) +# define libnss_files_hidden_data_weak(name) hidden_data_weak (name) +# define libnss_files_hidden_data_ver(local, name) hidden_data_ver(local, name) +#else +# define libnss_files_hidden_proto(name, attrs...) +# define libnss_files_hidden_tls_proto(name, attrs...) +# define libnss_files_hidden_def(name) +# define libnss_files_hidden_weak(name) +# define libnss_files_hidden_ver(local, name) +# define libnss_files_hidden_data_def(name) +# define libnss_files_hidden_tls_def(name) +# define libnss_files_hidden_data_weak(name) +# define libnss_files_hidden_data_ver(local, name) +#endif + +#if IS_IN (libnsl) +# define libnsl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libnsl_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libnsl_hidden_nolink_def(name, version) hidden_nolink (name, libnsl, version) +# define libnsl_hidden_weak(name) hidden_weak (name) +# define libnsl_hidden_ver(local, name) hidden_ver (local, name) +# define libnsl_hidden_data_def(name) hidden_data_def (name) +# define libnsl_hidden_tls_def(name) hidden_tls_def (name) +# define libnsl_hidden_data_weak(name) hidden_data_weak (name) +# define libnsl_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libnsl_hidden_proto(name, attrs...) +# define libnsl_hidden_tls_proto(name, attrs...) +# define libnsl_hidden_weak(name) +# define libnsl_hidden_ver(local, name) +# define libnsl_hidden_data_def(name) +# define libnsl_hidden_tls_def(name) +# define libnsl_hidden_data_weak(name) +# define libnsl_hidden_data_ver(local, name) +#endif + +#define libc_hidden_builtin_proto(name, attrs...) libc_hidden_proto (name, ##attrs) +#define libc_hidden_builtin_def(name) libc_hidden_def (name) +#define libc_hidden_builtin_weak(name) libc_hidden_weak (name) +#define libc_hidden_builtin_ver(local, name) libc_hidden_ver (local, name) + +#define libc_hidden_ldbl_proto(name, attrs...) libc_hidden_proto (name, ##attrs) +#ifdef __ASSEMBLER__ +# define HIDDEN_BUILTIN_JUMPTARGET(name) HIDDEN_JUMPTARGET(name) +#endif + +#if IS_IN (libutil) +# define libutil_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libutil_hidden_tls_proto(name, attrs...) \ + hidden_tls_proto (name, ##attrs) +# define libutil_hidden_def(name) hidden_def (name) +# define libutil_hidden_weak(name) hidden_weak (name) +# define libutil_hidden_ver(local, name) hidden_ver (local, name) +# define libutil_hidden_data_def(name) hidden_data_def (name) +# define libutil_hidden_tls_def(name) hidden_tls_def (name) +# define libutil_hidden_data_weak(name) hidden_data_weak (name) +# define libutil_hidden_data_ver(local, name) hidden_data_ver (local, name) +#else +# define libutil_hidden_proto(name, attrs...) +# define libutil_hidden_tls_proto(name, attrs...) +# define libutil_hidden_def(name) +# define libutil_hidden_weak(name) +# define libutil_hidden_ver(local, name) +# define libutil_hidden_data_def(name) +# define libutil_hidden_tls_def(name) +# define libutil_hidden_data_weak(name) +# define libutil_hidden_data_ver(local, name) +#endif + +#if IS_IN (libanl) +# define libanl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) +# define libanl_hidden_def(name) hidden_def (name) +#else +# define libanl_hidden_proto(name, attrs...) +# define libanl_hidden_def(name) +#endif + +/* Get some dirty hacks. */ +#include + +/* Move compatibility symbols out of the way by placing them all in a + special section. */ +#ifndef __ASSEMBLER__ +# define attribute_compat_text_section \ + __attribute__ ((section (".text.compat"))) +# define attribute_compat_data_section \ + __attribute__ ((section (".data.compat"))) +#else +# define compat_text_section .section ".text.compat", "ax"; +# define compat_data_section .section ".data.compat", "aw"; +#endif + +/* Helper / base macros for indirect function symbols. */ +#define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \ + classifier inhibit_stack_protector \ + __typeof (type_name) *name##_ifunc (arg) \ + { \ + init (); \ + __typeof (type_name) *res = expr; \ + return res; \ + } + +#ifdef HAVE_GCC_IFUNC +# define __ifunc(type_name, name, expr, arg, init) \ + extern __typeof (type_name) name __attribute__ \ + ((ifunc (#name "_ifunc"))); \ + __ifunc_resolver (type_name, name, expr, arg, init, static) + +# define __ifunc_hidden(type_name, name, expr, arg, init) \ + __ifunc (type_name, name, expr, arg, init) +#else +/* Gcc does not support __attribute__ ((ifunc (...))). Use the old behaviour + as fallback. But keep in mind that the debug information for the ifunc + resolver functions is not correct. It contains the ifunc'ed function as + DW_AT_linkage_name. E.g. lldb uses this field and an inferior function + call of the ifunc'ed function will fail due to "no matching function for + call to ..." because the ifunc'ed function and the resolver function have + different signatures. (Gcc support is disabled at least on a ppc64le + Ubuntu 14.04 system.) */ + +# define __ifunc(type_name, name, expr, arg, init) \ + extern __typeof (type_name) name; \ + __typeof (type_name) *name##_ifunc (arg) __asm__ (#name); \ + __ifunc_resolver (type_name, name, expr, arg, init,) \ + __asm__ (".type " #name ", %gnu_indirect_function"); + +# define __ifunc_hidden(type_name, name, expr, arg, init) \ + extern __typeof (type_name) __libc_##name; \ + __ifunc (type_name, __libc_##name, expr, arg, init) \ + strong_alias (__libc_##name, name); +#endif /* !HAVE_GCC_IFUNC */ + +/* The following macros are used for indirect function symbols in libc.so. + First of all, you need to have the function prototyped somewhere, + say in foo.h: + + int foo (int __bar); + + If you have an implementation for foo which e.g. uses a special hardware + feature which isn't available on all machines where this libc.so will be + used but decideable if available at runtime e.g. via hwcaps, you can provide + two or multiple implementations of foo: + + int __foo_default (int __bar) + { + return __bar; + } + + int __foo_special (int __bar) + { + return __bar; + } + + If your function foo has no libc_hidden_proto (foo) defined for PLT + bypassing, you can use: + + #define INIT_ARCH() unsigned long int hwcap = __GLRO(dl_hwcap); + + libc_ifunc (foo, (hwcap & HWCAP_SPECIAL) ? __foo_special : __foo_default); + + This will define a resolver function for foo which returns __foo_special or + __foo_default depending on your specified expression. Please note that you + have to define a macro function INIT_ARCH before using libc_ifunc macro as + it is called by the resolver function before evaluating the specified + expression. In this example it is used to prepare the hwcap variable. + The resolver function is assigned to an ifunc'ed symbol foo. Calls to foo + from inside or outside of libc.so will be indirected by a PLT call. + + If your function foo has a libc_hidden_proto (foo) defined for PLT bypassing + and calls to foo within libc.so should always go to one specific + implementation of foo e.g. __foo_default then you have to add: + + __hidden_ver1 (__foo_default, __GI_foo, __foo_default); + + or a tweaked definition of libc_hidden_def macro after the __foo_default + function definition. Calls to foo within libc.so will always go directly to + __foo_default. Calls to foo from outside libc.so will be indirected by a + PLT call to ifunc'ed symbol foo which you have to define in a separate + compile unit: + + #define foo __redirect_foo + #include + #undef foo + + extern __typeof (__redirect_foo) __foo_default attribute_hidden; + extern __typeof (__redirect_foo) __foo_special attribute_hidden; + + libc_ifunc_redirected (__redirect_foo, foo, + (hwcap & HWCAP_SPECIAL) + ? __foo_special + : __foo_default); + + This will define the ifunc'ed symbol foo like above. The redirection of foo + in header file is needed to omit an additional defintion of __GI_foo which + would end in a linker error while linking libc.so. You have to specify + __redirect_foo as first parameter which is used within libc_ifunc_redirected + macro in conjunction with typeof to define the ifunc'ed symbol foo. + + If your function foo has a libc_hidden_proto (foo) defined and calls to foo + within or from outside libc.so should go via ifunc'ed symbol, then you have + to use: + + libc_ifunc_hidden (foo, foo, + (hwcap & HWCAP_SPECIAL) + ? __foo_special + : __foo_default); + libc_hidden_def (foo) + + The first parameter foo of libc_ifunc_hidden macro is used in the same way + as for libc_ifunc_redirected macro. */ + +#define libc_ifunc(name, expr) __ifunc (name, name, expr, void, INIT_ARCH) + +#define libc_ifunc_redirected(redirected_name, name, expr) \ + __ifunc (redirected_name, name, expr, void, INIT_ARCH) + +#define libc_ifunc_hidden(redirected_name, name, expr) \ + __ifunc_hidden (redirected_name, name, expr, void, INIT_ARCH) + +/* The body of the function is supposed to use __get_cpu_features + which will, if necessary, initialize the data first. */ +#define libm_ifunc_init() +#define libm_ifunc(name, expr) \ + __ifunc (name, name, expr, void, libm_ifunc_init) + +/* Add the compiler optimization to inhibit loop transformation to library + calls. This is used to avoid recursive calls in memset and memmove + default implementations. */ +#ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL +# define inhibit_loop_to_libcall \ + __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns"))) +#else +# define inhibit_loop_to_libcall +#endif + +/* These macros facilitate sharing source files with gnulib. + + They are here instead of sys/cdefs.h because they should not be + used in public header files. + + Their definitions should be kept consistent with the definitions in + gnulib-common.m4, but it is not necessary to cater to old non-GCC + compilers, since they will only be used while building glibc itself. + (Note that _GNUC_PREREQ cannot be used in this file.) */ + +/* Define as a marker that can be attached to declarations that might not + be used. This helps to reduce warnings, such as from + GCC -Wunused-parameter. */ +#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) +# define _GL_UNUSED __attribute__ ((__unused__)) +#else +# define _GL_UNUSED +#endif + +/* gcc supports the "unused" attribute on possibly unused labels, and + g++ has since version 4.5. Note to support C++ as well as C, + _GL_UNUSED_LABEL should be used with a trailing ; */ +#if !defined __cplusplus || __GNUC__ > 4 \ + || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# define _GL_UNUSED_LABEL _GL_UNUSED +#else +# define _GL_UNUSED_LABEL +#endif + +/* The __pure__ attribute was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + +/* The __const__ attribute was added in gcc 2.95. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__)) +#else +# define _GL_ATTRIBUTE_CONST /* empty */ +#endif + +#endif /* !_ISOMAC */ +#endif /* libc-symbols.h */ From a45992969a09e69fd857a65d845dda35bdd4a162 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sun, 27 Jun 2021 10:14:03 -0700 Subject: [PATCH 08/16] Update to use the latest glibc's bench-malloc-thread program --- Makefile | 6 +- bench_collect_results.py | 2 +- benchmark-src/Makefile | 25 - benchmark-src/_itoa.h | 105 -- benchmark-src/bench-malloc-simple.c | 185 --- benchmark-src/bench-malloc-thread.c | 297 ----- benchmark-src/bench-timing.h | 39 - benchmark-src/hp-timing-common.h | 60 - benchmark-src/hp-timing.h | 61 - benchmark-src/isa.h | 24 - benchmark-src/json-lib.c | 240 ---- benchmark-src/json-lib.h | 53 - benchmark-src/libc-symbols.h | 1089 ----------------- .../README.md => glibc-benchmark-info.md | 0 14 files changed, 4 insertions(+), 2182 deletions(-) delete mode 100644 benchmark-src/Makefile delete mode 100644 benchmark-src/_itoa.h delete mode 100644 benchmark-src/bench-malloc-simple.c delete mode 100644 benchmark-src/bench-malloc-thread.c delete mode 100644 benchmark-src/bench-timing.h delete mode 100644 benchmark-src/hp-timing-common.h delete mode 100644 benchmark-src/hp-timing.h delete mode 100644 benchmark-src/isa.h delete mode 100644 benchmark-src/json-lib.c delete mode 100644 benchmark-src/json-lib.h delete mode 100644 benchmark-src/libc-symbols.h rename benchmark-src/README.md => glibc-benchmark-info.md (100%) diff --git a/Makefile b/Makefile index 9e54057..a7327a6 100755 --- a/Makefile +++ b/Makefile @@ -40,8 +40,8 @@ endif ifdef NUMPROC parallel_flags := -j$(NUMPROC) else -# default value -parallel_flags := -j4 +# default value: pull from the max number of hardware processes: `nproc` cmd output; ex: 8 +parallel_flags := -j$(nproc) endif ifdef POSTFIX @@ -131,6 +131,7 @@ $(glibc_install_dir)/lib/libc.so.6: cd $(glibc_build_dir) && \ ../glibc/configure --prefix=$(glibc_install_dir) && \ make $(parallel_flags) && \ + make bench-build $(parallel_flags) && \ make install [ -x $(glibc_build_dir)/benchtests/bench-malloc-thread ] && echo "GNU libc benchmarking utility is ready!" || echo "Cannot find GNU libc benchmarking utility! Cannot collect benchmark results" @@ -149,7 +150,6 @@ $(jemalloc_install_dir)/lib/libjemalloc.so: ( make install || true ) build: - $(MAKE) -C benchmark-src ifeq ($(findstring glibc,$(implem_list)),glibc) $(MAKE) $(glibc_install_dir)/lib/libc.so.6 endif diff --git a/bench_collect_results.py b/bench_collect_results.py index 2950cee..a49a38d 100755 --- a/bench_collect_results.py +++ b/bench_collect_results.py @@ -11,7 +11,7 @@ # Constants # -internal_benchmark_util = 'benchmark-src/bench-malloc-thread' +internal_benchmark_util = 'glibc-build/benchtests/bench-malloc-thread' glibc_install_dir = 'glibc-install' tcmalloc_install_dir = 'tcmalloc-install' diff --git a/benchmark-src/Makefile b/benchmark-src/Makefile deleted file mode 100644 index 8db744c..0000000 --- a/benchmark-src/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -TARGET = bench-malloc-thread -LIBS = -lpthread -CC = gcc -CFLAGS = -g -Wall -O2 -std=gnu99 -I. -include libc-symbols.h - -.PHONY: default all clean - -default: $(TARGET) - -all: default - -OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) -HEADERS = $(wildcard *.h) - -%.o: %.c $(HEADERS) - $(CC) $(CFLAGS) -c $< -o $@ - -.PRECIOUS: $(TARGET) $(OBJECTS) - -$(TARGET): $(OBJECTS) - $(CC) $(OBJECTS) -Wall $(LIBS) -o $@ - -clean: - -rm -f *.o - -rm -f $(TARGET) diff --git a/benchmark-src/_itoa.h b/benchmark-src/_itoa.h deleted file mode 100644 index 695fd85..0000000 --- a/benchmark-src/_itoa.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Internal function for converting integers to ASCII. - Copyright (C) 1994-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _ITOA_H -#define _ITOA_H - -#include - -/* When long long is different from long, by default, _itoa_word is - provided to convert long to ASCII and _itoa is provided to convert - long long. A sysdeps _itoa.h can define _ITOA_NEEDED to 0 and define - _ITOA_WORD_TYPE to unsigned long long int to override it so that - _itoa_word is changed to convert long long to ASCII and _itoa is - mapped to _itoa_word. */ - -#ifndef _ITOA_NEEDED -# define _ITOA_NEEDED (LONG_MAX != LLONG_MAX) -#endif -#ifndef _ITOA_WORD_TYPE -# define _ITOA_WORD_TYPE unsigned long int -#endif - - -/* Convert VALUE into ASCII in base BASE (2..36). - Write backwards starting the character just before BUFLIM. - Return the address of the first (left-to-right) character in the number. - Use upper case letters iff UPPER_CASE is nonzero. */ - -extern char *_itoa (unsigned long long int value, char *buflim, - unsigned int base, int upper_case) attribute_hidden; - -extern const char _itoa_upper_digits[]; -extern const char _itoa_lower_digits[]; -#if IS_IN (libc) || IS_IN (rtld) -hidden_proto (_itoa_upper_digits) -hidden_proto (_itoa_lower_digits) -#endif - -#if IS_IN (libc) -extern char *_itoa_word (_ITOA_WORD_TYPE value, char *buflim, - unsigned int base, - int upper_case) attribute_hidden; -#else -static inline char * __attribute__ ((unused, always_inline)) -_itoa_word (_ITOA_WORD_TYPE value, char *buflim, - unsigned int base, int upper_case) -{ - const char *digits = (upper_case - ? _itoa_upper_digits - : _itoa_lower_digits); - - switch (base) - { -# define SPECIAL(Base) \ - case Base: \ - do \ - *--buflim = digits[value % Base]; \ - while ((value /= Base) != 0); \ - break - - SPECIAL (10); - SPECIAL (16); - SPECIAL (8); - default: - do - *--buflim = digits[value % base]; - while ((value /= base) != 0); - } - return buflim; -} -# undef SPECIAL -#endif - -/* Similar to the _itoa functions, but output starts at buf and pointer - after the last written character is returned. */ -extern char *_fitoa_word (_ITOA_WORD_TYPE value, char *buf, - unsigned int base, - int upper_case) attribute_hidden; -extern char *_fitoa (unsigned long long value, char *buf, unsigned int base, - int upper_case) attribute_hidden; - -#if !_ITOA_NEEDED -/* No need for special long long versions. */ -# define _itoa(value, buf, base, upper_case) \ - _itoa_word (value, buf, base, upper_case) -# define _fitoa(value, buf, base, upper_case) \ - _fitoa_word (value, buf, base, upper_case) -#endif - -#endif /* itoa.h */ diff --git a/benchmark-src/bench-malloc-simple.c b/benchmark-src/bench-malloc-simple.c deleted file mode 100644 index dd5b305..0000000 --- a/benchmark-src/bench-malloc-simple.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Benchmark malloc and free functions. - Copyright (C) 2019-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include -#include -#include -#include "bench-timing.h" -#include "json-lib.h" - -/* Benchmark the malloc/free performance of a varying number of blocks of a - given size. This enables performance tracking of the t-cache and fastbins. - It tests 3 different scenarios: single-threaded using main arena, - multi-threaded using thread-arena, and main arena with SINGLE_THREAD_P - false. */ - -#define NUM_ITERS 200000 -#define NUM_ALLOCS 4 -#define MAX_ALLOCS 1600 - -typedef struct -{ - size_t iters; - size_t size; - int n; - timing_t elapsed; -} malloc_args; - -static void -do_benchmark (malloc_args *args, int **arr) -{ - timing_t start, stop; - size_t iters = args->iters; - size_t size = args->size; - int n = args->n; - - TIMING_NOW (start); - - for (int j = 0; j < iters; j++) - { - for (int i = 0; i < n; i++) - arr[i] = malloc (size); - - for (int i = 0; i < n; i++) - free (arr[i]); - } - - TIMING_NOW (stop); - - TIMING_DIFF (args->elapsed, start, stop); -} - -static malloc_args tests[3][NUM_ALLOCS]; -static int allocs[NUM_ALLOCS] = { 25, 100, 400, MAX_ALLOCS }; - -static void * -thread_test (void *p) -{ - int **arr = (int**)p; - - /* Run benchmark multi-threaded. */ - for (int i = 0; i < NUM_ALLOCS; i++) - do_benchmark (&tests[2][i], arr); - - return p; -} - -void -bench (unsigned long size) -{ - size_t iters = NUM_ITERS; - int **arr = (int**) malloc (MAX_ALLOCS * sizeof (void*)); - - for (int t = 0; t < 3; t++) - for (int i = 0; i < NUM_ALLOCS; i++) - { - tests[t][i].n = allocs[i]; - tests[t][i].size = size; - tests[t][i].iters = iters / allocs[i]; - - /* Do a quick warmup run. */ - if (t == 0) - do_benchmark (&tests[0][i], arr); - } - - /* Run benchmark single threaded in main_arena. */ - for (int i = 0; i < NUM_ALLOCS; i++) - do_benchmark (&tests[0][i], arr); - - /* Run benchmark in a thread_arena. */ - pthread_t t; - pthread_create (&t, NULL, thread_test, (void*)arr); - pthread_join (t, NULL); - - /* Repeat benchmark in main_arena with SINGLE_THREAD_P == false. */ - for (int i = 0; i < NUM_ALLOCS; i++) - do_benchmark (&tests[1][i], arr); - - free (arr); - - json_ctx_t json_ctx; - - json_init (&json_ctx, 0, stdout); - - json_document_begin (&json_ctx); - - json_attr_string (&json_ctx, "timing_type", TIMING_TYPE); - - json_attr_object_begin (&json_ctx, "functions"); - - json_attr_object_begin (&json_ctx, "malloc"); - - char s[100]; - double iters2 = iters; - - json_attr_object_begin (&json_ctx, ""); - json_attr_double (&json_ctx, "malloc_block_size", size); - - struct rusage usage; - getrusage (RUSAGE_SELF, &usage); - json_attr_double (&json_ctx, "max_rss", usage.ru_maxrss); - - for (int i = 0; i < NUM_ALLOCS; i++) - { - sprintf (s, "main_arena_st_allocs_%04d_time", allocs[i]); - json_attr_double (&json_ctx, s, tests[0][i].elapsed / iters2); - } - - for (int i = 0; i < NUM_ALLOCS; i++) - { - sprintf (s, "main_arena_mt_allocs_%04d_time", allocs[i]); - json_attr_double (&json_ctx, s, tests[1][i].elapsed / iters2); - } - - for (int i = 0; i < NUM_ALLOCS; i++) - { - sprintf (s, "thread_arena__allocs_%04d_time", allocs[i]); - json_attr_double (&json_ctx, s, tests[2][i].elapsed / iters2); - } - - json_attr_object_end (&json_ctx); - - json_attr_object_end (&json_ctx); - - json_attr_object_end (&json_ctx); - - json_document_end (&json_ctx); -} - -static void usage (const char *name) -{ - fprintf (stderr, "%s: \n", name); - exit (1); -} - -int -main (int argc, char **argv) -{ - long val = 16; - if (argc == 2) - val = strtol (argv[1], NULL, 0); - - if (argc > 2 || val <= 0) - usage (argv[0]); - - bench (val); - - return 0; -} diff --git a/benchmark-src/bench-malloc-thread.c b/benchmark-src/bench-malloc-thread.c deleted file mode 100644 index 04b98c0..0000000 --- a/benchmark-src/bench-malloc-thread.c +++ /dev/null @@ -1,297 +0,0 @@ -/* Benchmark malloc and free functions. - Copyright (C) 2013-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bench-timing.h" -#include "json-lib.h" - -/* Benchmark duration in seconds. */ -#define BENCHMARK_DURATION 10 -#define RAND_SEED 88 - -#ifndef NUM_THREADS -# define NUM_THREADS 1 -#endif - -/* Maximum memory that can be allocated at any one time is: - - NUM_THREADS * WORKING_SET_SIZE * MAX_ALLOCATION_SIZE - - However due to the distribution of the random block sizes - the typical amount allocated will be much smaller. */ -#define WORKING_SET_SIZE 1024 - -#define MIN_ALLOCATION_SIZE 4 -#define MAX_ALLOCATION_SIZE 32768 - -/* Get a random block size with an inverse square distribution. */ -static unsigned int -get_block_size (unsigned int rand_data) -{ - /* Inverse square. */ - const float exponent = -2; - /* Minimum value of distribution. */ - const float dist_min = MIN_ALLOCATION_SIZE; - /* Maximum value of distribution. */ - const float dist_max = MAX_ALLOCATION_SIZE; - - float min_pow = powf (dist_min, exponent + 1); - float max_pow = powf (dist_max, exponent + 1); - - float r = (float) rand_data / RAND_MAX; - - return (unsigned int) powf ((max_pow - min_pow) * r + min_pow, - 1 / (exponent + 1)); -} - -#define NUM_BLOCK_SIZES 8000 -#define NUM_OFFSETS ((WORKING_SET_SIZE) * 4) - -static unsigned int random_block_sizes[NUM_BLOCK_SIZES]; -static unsigned int random_offsets[NUM_OFFSETS]; - -static void -init_random_values (void) -{ - for (size_t i = 0; i < NUM_BLOCK_SIZES; i++) - random_block_sizes[i] = get_block_size (rand ()); - - for (size_t i = 0; i < NUM_OFFSETS; i++) - random_offsets[i] = rand () % WORKING_SET_SIZE; -} - -static unsigned int -get_random_block_size (unsigned int *state) -{ - unsigned int idx = *state; - - if (idx >= NUM_BLOCK_SIZES - 1) - idx = 0; - else - idx++; - - *state = idx; - - return random_block_sizes[idx]; -} - -static unsigned int -get_random_offset (unsigned int *state) -{ - unsigned int idx = *state; - - if (idx >= NUM_OFFSETS - 1) - idx = 0; - else - idx++; - - *state = idx; - - return random_offsets[idx]; -} - -static volatile bool timeout; - -static void -alarm_handler (int signum) -{ - timeout = true; -} - -/* Allocate and free blocks in a random order. */ -static size_t -malloc_benchmark_loop (void **ptr_arr) -{ - unsigned int offset_state = 0, block_state = 0; - size_t iters = 0; - - while (!timeout) - { - unsigned int next_idx = get_random_offset (&offset_state); - unsigned int next_block = get_random_block_size (&block_state); - - free (ptr_arr[next_idx]); - - ptr_arr[next_idx] = malloc (next_block); - - iters++; - } - - return iters; -} - -struct thread_args -{ - size_t iters; - void **working_set; - timing_t elapsed; -}; - -static void * -benchmark_thread (void *arg) -{ - struct thread_args *args = (struct thread_args *) arg; - size_t iters; - void *thread_set = args->working_set; - timing_t start, stop; - - TIMING_NOW (start); - iters = malloc_benchmark_loop (thread_set); - TIMING_NOW (stop); - - TIMING_DIFF (args->elapsed, start, stop); - args->iters = iters; - - return NULL; -} - -static timing_t -do_benchmark (size_t num_threads, size_t *iters) -{ - timing_t elapsed = 0; - - if (num_threads == 1) - { - timing_t start, stop; - void *working_set[WORKING_SET_SIZE]; - - memset (working_set, 0, sizeof (working_set)); - - TIMING_NOW (start); - *iters = malloc_benchmark_loop (working_set); - TIMING_NOW (stop); - - TIMING_DIFF (elapsed, start, stop); - } - else - { - struct thread_args args[num_threads]; - void *working_set[num_threads][WORKING_SET_SIZE]; - pthread_t threads[num_threads]; - - memset (working_set, 0, sizeof (working_set)); - - *iters = 0; - - for (size_t i = 0; i < num_threads; i++) - { - args[i].working_set = working_set[i]; - pthread_create(&threads[i], NULL, benchmark_thread, &args[i]); - } - - for (size_t i = 0; i < num_threads; i++) - { - pthread_join(threads[i], NULL); - TIMING_ACCUM (elapsed, args[i].elapsed); - *iters += args[i].iters; - } - } - return elapsed; -} - -static void usage(const char *name) -{ - fprintf (stderr, "%s: \n", name); - exit (1); -} - -int -main (int argc, char **argv) -{ - timing_t cur; - size_t iters = 0, num_threads = 1; - json_ctx_t json_ctx; - double d_total_s, d_total_i; - struct sigaction act; - - if (argc == 1) - num_threads = 1; - else if (argc == 2) - { - long ret; - - errno = 0; - ret = strtol(argv[1], NULL, 10); - - if (errno || ret == 0) - usage(argv[0]); - - num_threads = ret; - } - else - usage(argv[0]); - - init_random_values (); - - json_init (&json_ctx, 0, stdout); - - json_document_begin (&json_ctx); - - json_attr_string (&json_ctx, "timing_type", TIMING_TYPE); - - json_attr_object_begin (&json_ctx, "functions"); - - json_attr_object_begin (&json_ctx, "malloc"); - - json_attr_object_begin (&json_ctx, ""); - - memset (&act, 0, sizeof (act)); - act.sa_handler = &alarm_handler; - - sigaction (SIGALRM, &act, NULL); - - alarm (BENCHMARK_DURATION); - - cur = do_benchmark (num_threads, &iters); - - struct rusage usage; - getrusage(RUSAGE_SELF, &usage); - - d_total_s = cur; - d_total_i = iters; - - json_attr_double (&json_ctx, "duration", d_total_s); - json_attr_double (&json_ctx, "iterations", d_total_i); - json_attr_double (&json_ctx, "time_per_iteration", d_total_s / d_total_i); - json_attr_double (&json_ctx, "max_rss", usage.ru_maxrss); - - json_attr_double (&json_ctx, "threads", num_threads); - json_attr_double (&json_ctx, "min_size", MIN_ALLOCATION_SIZE); - json_attr_double (&json_ctx, "max_size", MAX_ALLOCATION_SIZE); - json_attr_double (&json_ctx, "random_seed", RAND_SEED); - - json_attr_object_end (&json_ctx); - - json_attr_object_end (&json_ctx); - - json_attr_object_end (&json_ctx); - - json_document_end (&json_ctx); - - return 0; -} diff --git a/benchmark-src/bench-timing.h b/benchmark-src/bench-timing.h deleted file mode 100644 index 28fad56..0000000 --- a/benchmark-src/bench-timing.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Define timing macros. - Copyright (C) 2013-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#undef attribute_hidden -#define attribute_hidden -#ifdef USE_CLOCK_GETTIME -# include -#else -# include -#endif -#include - -#define GL(x) _##x -#define GLRO(x) _##x -typedef hp_timing_t timing_t; - -#define TIMING_TYPE "hp_timing" - -#define TIMING_NOW(var) HP_TIMING_NOW (var) -#define TIMING_DIFF(diff, start, end) HP_TIMING_DIFF ((diff), (start), (end)) -#define TIMING_ACCUM(sum, diff) HP_TIMING_ACCUM_NT ((sum), (diff)) - -#define TIMING_PRINT_MEAN(d_total_s, d_iters) \ - printf ("\t%g", (d_total_s) / (d_iters)) diff --git a/benchmark-src/hp-timing-common.h b/benchmark-src/hp-timing-common.h deleted file mode 100644 index d59a27d..0000000 --- a/benchmark-src/hp-timing-common.h +++ /dev/null @@ -1,60 +0,0 @@ -/* High precision, low overhead timing functions. Generic version. - Copyright (C) 1998-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1998. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* In case a platform supports timers in the hardware the following macros - and types must be defined: - - - HP_TIMING_INLINE: this macro is non-zero if the functionality is not - implemented using function calls but instead uses some inlined code - which might simply consist of a few assembler instructions. We have to - know this since we might want to use the macros here in places where we - cannot make function calls. - - - hp_timing_t: This is the type for variables used to store the time - values. This type must be integral. - - - HP_TIMING_NOW: place timestamp for current time in variable given as - parameter. -*/ - -/* The target supports hp-timing. Share the common infrastructure. */ - -#include -#include -#include <_itoa.h> - -/* Compute the difference between START and END, storing into DIFF. */ -#define HP_TIMING_DIFF(Diff, Start, End) ((Diff) = (End) - (Start)) - -/* Accumulate ADD into SUM. No attempt is made to be thread-safe. */ -#define HP_TIMING_ACCUM_NT(Sum, Diff) ((Sum) += (Diff)) - -#define HP_TIMING_PRINT_SIZE (3 * sizeof (hp_timing_t) + 1) - -/* Write a decimal representation of the timing value into the given string. */ -#define HP_TIMING_PRINT(Dest, Len, Val) \ - do { \ - char __buf[HP_TIMING_PRINT_SIZE]; \ - char *__dest = (Dest); \ - size_t __len = (Len); \ - char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0); \ - size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len); \ - memcpy (__dest, __cp, __cp_len); \ - __dest[__cp_len - 1] = '\0'; \ - } while (0) diff --git a/benchmark-src/hp-timing.h b/benchmark-src/hp-timing.h deleted file mode 100644 index 196fef1..0000000 --- a/benchmark-src/hp-timing.h +++ /dev/null @@ -1,61 +0,0 @@ -/* High precision, low overhead timing functions. x86 version. - Copyright (C) 2018-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _HP_TIMING_H -#define _HP_TIMING_H 1 - -#include - -#if MINIMUM_ISA == 686 || MINIMUM_ISA == 8664 -/* We indeed have inlined functions. */ -# define HP_TIMING_INLINE (1) - -/* We use 64bit values for the times. */ -typedef unsigned long long int hp_timing_t; - -/* That's quite simple. Use the `rdtsc' instruction. Note that the value - might not be 100% accurate since there might be some more instructions - running in this moment. This could be changed by using a barrier like - 'cpuid' right before the `rdtsc' instruciton. But we are not interested - in accurate clock cycles here so we don't do this. - - NB: Use __builtin_ia32_rdtsc directly since including - makes building glibc very slow. */ -# ifdef USE_RDTSCP -/* RDTSCP waits until all previous instructions have executed and all - previous loads are globally visible before reading the counter. - RDTSC doesn't wait until all previous instructions have been executed - before reading the counter. */ -# define HP_TIMING_NOW(Var) \ - (__extension__ ({ \ - unsigned int __aux; \ - (Var) = __builtin_ia32_rdtscp (&__aux); \ - })) -# else -# define HP_TIMING_NOW(Var) ((Var) = __builtin_ia32_rdtsc ()) -# endif - -# include -#else -/* NB: Undefine _HP_TIMING_H so that will - be included. */ -# undef _HP_TIMING_H -# include -#endif - -#endif /* hp-timing.h */ diff --git a/benchmark-src/isa.h b/benchmark-src/isa.h deleted file mode 100644 index 38028e4..0000000 --- a/benchmark-src/isa.h +++ /dev/null @@ -1,24 +0,0 @@ -/* x86 ISA info. x86-64 version. - Copyright (C) 2018-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _ISA_H -#define _ISA_H - -#define MINIMUM_ISA 8664 - -#endif diff --git a/benchmark-src/json-lib.c b/benchmark-src/json-lib.c deleted file mode 100644 index 47ae82b..0000000 --- a/benchmark-src/json-lib.c +++ /dev/null @@ -1,240 +0,0 @@ -/* Simple library for printing JSON data. - Copyright (C) 2014-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -#include "json-lib.h" - -void -json_init (json_ctx_t *ctx, unsigned int indent_level, FILE *fp) -{ - ctx->indent_level = indent_level; - ctx->fp = fp; - ctx->first_element = true; -} - -static void -do_indent (json_ctx_t *ctx) -{ - char indent_buf[ctx->indent_level + 1]; - - memset (indent_buf, ' ', ctx->indent_level + 1); - indent_buf[ctx->indent_level] = '\0'; - - fputs (indent_buf, ctx->fp); -} - -void -json_document_begin (json_ctx_t *ctx) -{ - do_indent (ctx); - - fputs ("{\n", ctx->fp); - - ctx->indent_level++; - ctx->first_element = true; -} - -void -json_document_end (json_ctx_t *ctx) -{ - ctx->indent_level--; - - do_indent (ctx); - - fputs ("\n}", ctx->fp); -} - -void -json_attr_object_begin (json_ctx_t *ctx, const char *name) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": {\n", name); - - ctx->indent_level++; - ctx->first_element = true; -} - -void -json_attr_object_end (json_ctx_t *ctx) -{ - ctx->indent_level--; - ctx->first_element = false; - - fputs ("\n", ctx->fp); - - do_indent (ctx); - - fputs ("}", ctx->fp); -} - -void -json_attr_string (json_ctx_t *ctx, const char *name, const char *s) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - else - ctx->first_element = false; - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": \"%s\"", name, s); -} - -void -json_attr_uint (json_ctx_t *ctx, const char *name, uint64_t d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - else - ctx->first_element = false; - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": %" PRIu64 , name, d); -} - -void -json_attr_int (json_ctx_t *ctx, const char *name, int64_t d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - else - ctx->first_element = false; - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": %" PRId64 , name, d); -} - -void -json_attr_double (json_ctx_t *ctx, const char *name, double d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - else - ctx->first_element = false; - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": %g", name, d); -} - -void -json_array_begin (json_ctx_t *ctx, const char *name) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ",\n"); - - do_indent (ctx); - - fprintf (ctx->fp, "\"%s\": [", name); - - ctx->indent_level++; - ctx->first_element = true; -} - -void -json_array_end (json_ctx_t *ctx) -{ - ctx->indent_level--; - ctx->first_element = false; - - fputs ("]", ctx->fp); -} - -void -json_element_string (json_ctx_t *ctx, const char *s) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ", \"%s\"", s); - else - { - fprintf (ctx->fp, "\"%s\"", s); - ctx->first_element = false; - } -} - -void -json_element_uint (json_ctx_t *ctx, uint64_t d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ", %" PRIu64, d); - else - { - fprintf (ctx->fp, "%" PRIu64, d); - ctx->first_element = false; - } -} - -void -json_element_int (json_ctx_t *ctx, int64_t d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ", %" PRId64, d); - else - { - fprintf (ctx->fp, "%" PRId64, d); - ctx->first_element = false; - } -} - -void -json_element_double (json_ctx_t *ctx, double d) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ", %g", d); - else - { - fprintf (ctx->fp, "%g", d); - ctx->first_element = false; - } -} - -void -json_element_object_begin (json_ctx_t *ctx) -{ - if (!ctx->first_element) - fprintf (ctx->fp, ","); - - fputs ("\n", ctx->fp); - - do_indent (ctx); - - fputs ("{\n", ctx->fp); - - ctx->indent_level++; - ctx->first_element = true; -} - -void -json_element_object_end (json_ctx_t *ctx) -{ - ctx->indent_level--; - ctx->first_element = false; - - fputs ("\n", ctx->fp); - - do_indent (ctx); - - fputs ("}", ctx->fp); -} diff --git a/benchmark-src/json-lib.h b/benchmark-src/json-lib.h deleted file mode 100644 index fb44174..0000000 --- a/benchmark-src/json-lib.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Simple library for printing JSON data. - Copyright (C) 2014-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef __JSON_LIB_H__ -#define __JSON_LIB_H__ - -#include -#include -#include - -struct json_ctx -{ - FILE *fp; - unsigned int indent_level; - bool first_element; -}; - -typedef struct json_ctx json_ctx_t; - -void json_init (json_ctx_t *ctx, unsigned int indent_level, FILE *fp); -void json_document_begin (json_ctx_t *ctx); -void json_document_end (json_ctx_t *ctx); -void json_attr_object_begin (json_ctx_t *ctx, const char *name); -void json_attr_object_end (json_ctx_t *ctx); -void json_attr_string (json_ctx_t *ctx, const char *name, const char *s); -void json_attr_int (json_ctx_t *ctx, const char *name, int64_t d); -void json_attr_uint (json_ctx_t *ctx, const char *name, uint64_t d); -void json_attr_double (json_ctx_t *ctx, const char *name, double d); -void json_array_begin (json_ctx_t *ctx, const char *name); -void json_array_end (json_ctx_t *ctx); -void json_element_string (json_ctx_t *ctx, const char *s); -void json_element_int (json_ctx_t *ctx, int64_t d); -void json_element_uint (json_ctx_t *ctx, uint64_t d); -void json_element_double (json_ctx_t *ctx, double d); -void json_element_object_begin (json_ctx_t *ctx); -void json_element_object_end (json_ctx_t *ctx); - -#endif diff --git a/benchmark-src/libc-symbols.h b/benchmark-src/libc-symbols.h deleted file mode 100644 index 127ea65..0000000 --- a/benchmark-src/libc-symbols.h +++ /dev/null @@ -1,1089 +0,0 @@ -/* Support macros for making weak and strong aliases for symbols, - and for using symbol sets and linker warnings with GNU ld. - Copyright (C) 1995-2021 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _LIBC_SYMBOLS_H -#define _LIBC_SYMBOLS_H 1 - -/* This file is included implicitly in the compilation of every source file, - using -include. It includes config.h. */ - -/* Enable declarations of GNU extensions, since we are compiling them. */ -#define _GNU_SOURCE 1 - -#ifdef MODULE_NAME - -/* Use `#if IS_IN (module)` to detect what component is being compiled. */ -#define PASTE_NAME1(a,b) a##b -#define PASTE_NAME(a,b) PASTE_NAME1 (a,b) -#define IN_MODULE PASTE_NAME (MODULE_, MODULE_NAME) -#define IS_IN(lib) (IN_MODULE == MODULE_##lib) - -/* True if the current module is a versioned library. Versioned - library names culled from shlib-versions files are assigned a - MODULE_* value greater than MODULE_LIBS_BEGIN. */ -#define IS_IN_LIB (IN_MODULE > MODULE_LIBS_BEGIN) - -/* The testsuite, and some other ancillary code, should be compiled against - as close an approximation to the installed headers as possible. - Defining this symbol disables most internal-use-only declarations - provided by this header, and all those provided by other internal - wrapper headers. */ -#if IS_IN (testsuite) || defined IS_IN_build || defined __cplusplus -# define _ISOMAC 1 -#endif - -#else -/* The generation process for a few files created very early in the - build (notably libc-modules.h itself) involves preprocessing this - header without defining MODULE_NAME. Under these conditions, - internal declarations (especially from config.h) must be visible, - but IS_IN should always evaluate as false. */ -# define IS_IN(lib) 0 -# define IS_IN_LIB 0 -# define IN_MODULE (-1) -#endif - -#ifndef _ISOMAC - -/* This is defined for the compilation of all C library code. features.h - tests this to avoid inclusion of stubs.h while compiling the library, - before stubs.h has been generated. Some library code that is shared - with other packages also tests this symbol to see if it is being - compiled as part of the C library. We must define this before including - config.h, because it makes some definitions conditional on whether libc - itself is being compiled, or just some generator program. */ -#define _LIBC 1 - -/* Some files must be compiled with optimization on. */ -#if !defined __ASSEMBLER__ && !defined __OPTIMIZE__ -# error "glibc cannot be compiled without optimization" -#endif - -/* -ffast-math cannot be applied to the C library, as it alters the ABI. - Some test components that use -ffast-math are currently not part of - IS_IN (testsuite) for technical reasons, so we have a secondary override. */ -#if defined __FAST_MATH__ && !defined TEST_FAST_MATH -# error "glibc must not be compiled with -ffast-math" -#endif - -#include - -/* Obtain the definition of symbol_version_reference. */ -#include - -/* When PIC is defined and SHARED isn't defined, we are building PIE - by default. */ -#if defined PIC && !defined SHARED -# define BUILD_PIE_DEFAULT 1 -#else -# define BUILD_PIE_DEFAULT 0 -#endif - -/* Define this for the benefit of portable GNU code that wants to check it. - Code that checks with #if will not #include again, since we've - already done it (and this file is implicitly included in every compile, - via -include). Code that checks with #ifdef will #include , - but that file should always be idempotent (i.e., it's just #define/#undef - and nothing else anywhere should be changing the macro state it touches), - so it's harmless. */ -#define HAVE_CONFIG_H 0 - -/* Define these macros for the benefit of portable GNU code that wants to check - them. Of course, STDC_HEADERS is never false when building libc! */ -#define STDC_HEADERS 1 -#define HAVE_MBSTATE_T 1 -#define HAVE_MBSRTOWCS 1 -#define HAVE_LIBINTL_H 1 -#define HAVE_WCTYPE_H 1 -#define HAVE_ISWCTYPE 1 -#define ENABLE_NLS 1 - -/* The symbols in all the user (non-_) macros are C symbols. */ - -#ifndef __SYMBOL_PREFIX -# define __SYMBOL_PREFIX -#endif - -#ifndef C_SYMBOL_NAME -# define C_SYMBOL_NAME(name) name -#endif - -#ifndef ASM_LINE_SEP -# define ASM_LINE_SEP ; -#endif - -#ifndef __attribute_copy__ -/* Provide an empty definition when cdefs.h is not included. */ -# define __attribute_copy__(arg) -#endif - -#ifndef __ASSEMBLER__ -/* GCC understands weak symbols and aliases; use its interface where - possible, instead of embedded assembly language. */ - -/* Define ALIASNAME as a strong alias for NAME. */ -# define strong_alias(name, aliasname) _strong_alias(name, aliasname) -# define _strong_alias(name, aliasname) \ - extern __typeof (name) aliasname __attribute__ ((alias (#name))) \ - __attribute_copy__ (name); - -/* This comes between the return type and function name in - a function definition to make that definition weak. */ -# define weak_function __attribute__ ((weak)) -# define weak_const_function __attribute__ ((weak, __const__)) - -/* Define ALIASNAME as a weak alias for NAME. - If weak aliases are not available, this defines a strong alias. */ -# define weak_alias(name, aliasname) _weak_alias (name, aliasname) -# define _weak_alias(name, aliasname) \ - extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))) \ - __attribute_copy__ (name); - -/* Same as WEAK_ALIAS, but mark symbol as hidden. */ -# define weak_hidden_alias(name, aliasname) \ - _weak_hidden_alias (name, aliasname) -# define _weak_hidden_alias(name, aliasname) \ - extern __typeof (name) aliasname \ - __attribute__ ((weak, alias (#name), __visibility__ ("hidden"))) \ - __attribute_copy__ (name); - -/* Declare SYMBOL as weak undefined symbol (resolved to 0 if not defined). */ -# define weak_extern(symbol) _weak_extern (weak symbol) -# define _weak_extern(expr) _Pragma (#expr) - -/* In shared builds, the expression call_function_static_weak - (FUNCTION-SYMBOL, ARGUMENTS) invokes FUNCTION-SYMBOL (an - identifier) unconditionally, with the (potentially empty) argument - list ARGUMENTS. In static builds, if FUNCTION-SYMBOL has a - definition, the function is invoked as before; if FUNCTION-SYMBOL - is NULL, no call is performed. */ -# ifdef SHARED -# define call_function_static_weak(func, ...) func (__VA_ARGS__) -# else /* !SHARED */ -# define call_function_static_weak(func, ...) \ - ({ \ - extern __typeof__ (func) func weak_function; \ - (func != NULL ? func (__VA_ARGS__) : (void)0); \ - }) -# endif - -#else /* __ASSEMBLER__ */ - -# ifdef HAVE_ASM_SET_DIRECTIVE -# define strong_alias(original, alias) \ - .globl C_SYMBOL_NAME (alias) ASM_LINE_SEP \ - .set C_SYMBOL_NAME (alias),C_SYMBOL_NAME (original) -# define strong_data_alias(original, alias) strong_alias(original, alias) -# else -# define strong_alias(original, alias) \ - .globl C_SYMBOL_NAME (alias) ASM_LINE_SEP \ - C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) -# define strong_data_alias(original, alias) strong_alias(original, alias) -# endif - -# define weak_alias(original, alias) \ - .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \ - C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) - -# define weak_extern(symbol) \ - .weak C_SYMBOL_NAME (symbol) - -#endif /* __ASSEMBLER__ */ - -/* Determine the return address. */ -#define RETURN_ADDRESS(nr) \ - __builtin_extract_return_addr (__builtin_return_address (nr)) - -/* When a reference to SYMBOL is encountered, the linker will emit a - warning message MSG. */ -/* We want the .gnu.warning.SYMBOL section to be unallocated. */ -#define __make_section_unallocated(section_string) \ - asm (".section " section_string "\n\t.previous"); - -/* Tacking on "\n\t#" to the section name makes gcc put it's bogus - section attributes on what looks like a comment to the assembler. */ -#ifdef HAVE_SECTION_QUOTES -# define __sec_comment "\"\n\t#\"" -#else -# define __sec_comment "\n\t#" -#endif -#define link_warning(symbol, msg) \ - __make_section_unallocated (".gnu.warning." #symbol) \ - static const char __evoke_link_warning_##symbol[] \ - __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \ - = msg; - -/* A canned warning for sysdeps/stub functions. */ -#define stub_warning(name) \ - __make_section_unallocated (".gnu.glibc-stub." #name) \ - link_warning (name, #name " is not implemented and will always fail") - -/* Warning for linking functions calling dlopen into static binaries. */ -#ifdef SHARED -#define static_link_warning(name) -#else -#define static_link_warning(name) static_link_warning1(name) -#define static_link_warning1(name) \ - link_warning(name, "Using '" #name "' in statically linked applications \ -requires at runtime the shared libraries from the glibc version used \ -for linking") -#endif - -/* Resource Freeing Hooks: - - Normally a process exits and the OS cleans up any allocated - memory. However, when tooling like mtrace or valgrind is monitoring - the process we need to free all resources that are part of the - process in order to provide the consistency required to track - memory leaks. - - A single public API exists and is __libc_freeres(), and this is used - by applications like valgrind to freee resouces. - - There are 3 cases: - - (a) __libc_freeres - - In this case all you need to do is define the freeing routine: - - foo.c: - libfoo_freeres_fn (foo_freeres) - { - complex_free (mem); - } - - This ensures the function is called at the right point to free - resources. - - (b) __libc_freeres_ptr - - The framework for (a) iterates over the list of pointers-to-free - in (b) and frees them. - - foo.c: - libc_freeres_ptr (static char *foo_buffer); - - Freeing these resources alaways happens last and is equivalent - to registering a function that does 'free (foo_buffer)'. - - (c) Explicit lists of free routines to call or objects to free. - - It is the intended goal to remove (a) and (b) which have some - non-determinism based on link order, and instead use explicit - lists of functions and frees to resolve cleanup ordering issues - and make it easy to debug and maintain. - - As of today the following subsystems use (c): - - Per-thread cleanup: - * malloc/thread-freeres.c - - libdl cleanup: - * dlfcn/dlfreeres.c - - libpthread cleanup: - * nptl/nptlfreeres.c - - So if you need any shutdown routines to run you should add them - directly to the appropriate subsystem's shutdown list. */ - -/* Resource pointers to free in libc.so. */ -#define libc_freeres_ptr(decl) \ - __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \ - decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment))) - -/* Resource freeing functions from libc.so go in this section. */ -#define __libc_freeres_fn_section \ - __attribute__ ((__used__, section ("__libc_freeres_fn"))) - -/* Resource freeing functions for libc.so. */ -#define libc_freeres_fn(name) \ - static void name (void) __attribute_used__ __libc_freeres_fn_section; \ - text_set_element (__libc_subfreeres, name); \ - static void name (void) - -/* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes - alias to ORIGINAL, when the assembler supports such declarations - (such as in ELF). - This is only necessary when defining something in assembly, or playing - funny alias games where the size should be other than what the compiler - thinks it is. */ -#define declare_symbol_alias(symbol, original, type, size) \ - declare_symbol_alias_1 (symbol, original, type, size) -#ifdef __ASSEMBLER__ -# define declare_symbol_alias_1(symbol, original, type, size) \ - strong_alias (original, symbol); \ - .type C_SYMBOL_NAME (symbol), %##type; \ - .size C_SYMBOL_NAME (symbol), size -#else /* Not __ASSEMBLER__. */ -# define declare_symbol_alias_1(symbol, original, type, size) \ - asm (".globl " __SYMBOL_PREFIX #symbol \ - "\n\t" declare_symbol_alias_1_alias (symbol, original) \ - "\n\t.type " __SYMBOL_PREFIX #symbol ", " \ - "%" #type \ - "\n\t.size " __SYMBOL_PREFIX #symbol ", " #size); -# ifdef HAVE_ASM_SET_DIRECTIVE -# define declare_symbol_alias_1_alias(symbol, original) \ - ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX #original -# else -# define declare_symbol_alias_1_alias(symbol, original) \ - __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX #original -# endif /* HAVE_ASM_SET_DIRECTIVE */ -#endif /* __ASSEMBLER__ */ - - -/* - -*/ - -#ifdef HAVE_GNU_RETAIN -# define attribute_used_retain __attribute__ ((__used__, __retain__)) -#else -# define attribute_used_retain __attribute__ ((__used__)) -#endif - -/* Symbol set support macros. */ - -/* Make SYMBOL, which is in the text segment, an element of SET. */ -#define text_set_element(set, symbol) _elf_set_element(set, symbol) -/* Make SYMBOL, which is in the data segment, an element of SET. */ -#define data_set_element(set, symbol) _elf_set_element(set, symbol) -/* Make SYMBOL, which is in the bss segment, an element of SET. */ -#define bss_set_element(set, symbol) _elf_set_element(set, symbol) - -/* These are all done the same way in ELF. - There is a new section created for each set. */ -#ifdef SHARED -/* When building a shared library, make the set section writable, - because it will need to be relocated at run time anyway. */ -# define _elf_set_element(set, symbol) \ - static const void *__elf_set_##set##_element_##symbol##__ \ - attribute_used_retain __attribute__ ((section (#set))) = &(symbol) -#else -# define _elf_set_element(set, symbol) \ - static const void *const __elf_set_##set##_element_##symbol##__ \ - attribute_used_retain __attribute__ ((section (#set))) = &(symbol) -#endif - -/* Define SET as a symbol set. This may be required (it is in a.out) to - be able to use the set's contents. */ -#define symbol_set_define(set) symbol_set_declare(set) - -/* Declare SET for use in this module, if defined in another module. - In a shared library, this is always local to that shared object. - For static linking, the set might be wholly absent and so we use - weak references. */ -#define symbol_set_declare(set) \ - extern char const __start_##set[] __symbol_set_attribute; \ - extern char const __stop_##set[] __symbol_set_attribute; -#ifdef SHARED -# define __symbol_set_attribute attribute_hidden -#else -# define __symbol_set_attribute __attribute__ ((weak)) -#endif - -/* Return a pointer (void *const *) to the first element of SET. */ -#define symbol_set_first_element(set) ((void *const *) (&__start_##set)) - -/* Return true iff PTR (a void *const *) has been incremented - past the last element in SET. */ -#define symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set) - -#ifdef SHARED -# define symbol_version(real, name, version) \ - symbol_version_reference(real, name, version) -# define default_symbol_version(real, name, version) \ - _default_symbol_version(real, name, version) -/* See . */ -# ifdef __ASSEMBLER__ -# define _default_symbol_version(real, name, version) \ - _set_symbol_version (real, name@@version) -# else -# define _default_symbol_version(real, name, version) \ - _set_symbol_version (real, #name "@@" #version) -# endif - -/* Evalutes to a string literal for VERSION in LIB. */ -# define symbol_version_string(lib, version) \ - _symbol_version_stringify_1 (VERSION_##lib##_##version) -# define _symbol_version_stringify_1(arg) _symbol_version_stringify_2 (arg) -# define _symbol_version_stringify_2(arg) #arg - -#else /* !SHARED */ -# define symbol_version(real, name, version) -# define default_symbol_version(real, name, version) \ - strong_alias(real, name) -#endif - -#if defined SHARED || defined LIBC_NONSHARED \ - || (BUILD_PIE_DEFAULT && IS_IN (libc)) -# define attribute_hidden __attribute__ ((visibility ("hidden"))) -#else -# define attribute_hidden -#endif - -#define attribute_tls_model_ie __attribute__ ((tls_model ("initial-exec"))) - -#define attribute_relro __attribute__ ((section (".data.rel.ro"))) - - -/* Used to disable stack protection in sensitive places, like ifunc - resolvers and early static TLS init. */ -#ifdef HAVE_CC_NO_STACK_PROTECTOR -# define inhibit_stack_protector \ - __attribute__ ((__optimize__ ("-fno-stack-protector"))) -#else -# define inhibit_stack_protector -#endif - -/* The following macros are used for PLT bypassing within libc.so - (and if needed other libraries similarly). - First of all, you need to have the function prototyped somewhere, - say in foo/foo.h: - - int foo (int __bar); - - If calls to foo within libc.so should always go to foo defined in libc.so, - then in include/foo.h you add: - - libc_hidden_proto (foo) - - line and after the foo function definition: - - int foo (int __bar) - { - return __bar; - } - libc_hidden_def (foo) - - or - - int foo (int __bar) - { - return __bar; - } - libc_hidden_weak (foo) - - Similarly for global data. If references to foo within libc.so should - always go to foo defined in libc.so, then in include/foo.h you add: - - libc_hidden_proto (foo) - - line and after foo's definition: - - int foo = INITIAL_FOO_VALUE; - libc_hidden_data_def (foo) - - or - - int foo = INITIAL_FOO_VALUE; - libc_hidden_data_weak (foo) - - If foo is normally just an alias (strong or weak) to some other function, - you should use the normal strong_alias first, then add libc_hidden_def - or libc_hidden_weak: - - int baz (int __bar) - { - return __bar; - } - strong_alias (baz, foo) - libc_hidden_weak (foo) - - If the function should be internal to multiple objects, say ld.so and - libc.so, the best way is to use: - - #if IS_IN (libc) || IS_IN (rtld) - hidden_proto (foo) - #endif - - in include/foo.h and the normal macros at all function definitions - depending on what DSO they belong to. - - If versioned_symbol macro is used to define foo, - libc_hidden_ver macro should be used, as in: - - int __real_foo (int __bar) - { - return __bar; - } - versioned_symbol (libc, __real_foo, foo, GLIBC_2_1); - libc_hidden_ver (__real_foo, foo) */ - -#if defined SHARED && !defined NO_HIDDEN -# ifndef __ASSEMBLER__ -# define __hidden_proto_hiddenattr(attrs...) \ - __attribute__ ((visibility ("hidden"), ##attrs)) -# define hidden_proto(name, attrs...) \ - __hidden_proto (name, , __GI_##name, ##attrs) -# define hidden_tls_proto(name, attrs...) \ - __hidden_proto (name, __thread, __GI_##name, ##attrs) -# define __hidden_proto(name, thread, internal, attrs...) \ - extern thread __typeof (name) name __asm__ (__hidden_asmname (#internal)) \ - __hidden_proto_hiddenattr (attrs); -# define __hidden_asmname(name) \ - __hidden_asmname1 (__USER_LABEL_PREFIX__, name) -# define __hidden_asmname1(prefix, name) __hidden_asmname2(prefix, name) -# define __hidden_asmname2(prefix, name) #prefix name -# define __hidden_ver1(local, internal, name) \ - __hidden_ver2 (, local, internal, name) -# define __hidden_ver2(thread, local, internal, name) \ - extern thread __typeof (name) __EI_##name \ - __asm__(__hidden_asmname (#internal)); \ - extern thread __typeof (name) __EI_##name \ - __attribute__((alias (__hidden_asmname (#local)))) \ - __attribute_copy__ (name) -# define hidden_ver(local, name) __hidden_ver1(local, __GI_##name, name); -# define hidden_data_ver(local, name) hidden_ver(local, name) -# define hidden_def(name) __hidden_ver1(__GI_##name, name, name); -# define hidden_data_def(name) hidden_def(name) -# define hidden_tls_def(name) \ - __hidden_ver2 (__thread, __GI_##name, name, name); -# define hidden_weak(name) \ - __hidden_ver1(__GI_##name, name, name) __attribute__((weak)); -# define hidden_data_weak(name) hidden_weak(name) -# define hidden_nolink(name, lib, version) \ - __hidden_nolink1 (__GI_##name, __EI_##name, name, VERSION_##lib##_##version) -# define __hidden_nolink1(local, internal, name, version) \ - __hidden_nolink2 (local, internal, name, version) -# define __hidden_nolink2(local, internal, name, version) \ - extern __typeof (name) internal __attribute__ ((alias (#local))) \ - __attribute_copy__ (name); \ - __hidden_nolink3 (local, internal, #name "@" #version) -# define __hidden_nolink3(local, internal, vername) \ - __asm__ (".symver " #internal ", " vername); -# else -/* For assembly, we need to do the opposite of what we do in C: - in assembly gcc __REDIRECT stuff is not in place, so functions - are defined by its normal name and we need to create the - __GI_* alias to it, in C __REDIRECT causes the function definition - to use __GI_* name and we need to add alias to the real name. - There is no reason to use hidden_weak over hidden_def in assembly, - but we provide it for consistency with the C usage. - hidden_proto doesn't make sense for assembly but the equivalent - is to call via the HIDDEN_JUMPTARGET macro instead of JUMPTARGET. */ -# define hidden_def(name) strong_alias (name, __GI_##name) -# define hidden_weak(name) hidden_def (name) -# define hidden_ver(local, name) strong_alias (local, __GI_##name) -# define hidden_data_def(name) strong_data_alias (name, __GI_##name) -# define hidden_tls_def(name) hidden_data_def (name) -# define hidden_data_weak(name) hidden_data_def (name) -# define hidden_data_ver(local, name) strong_data_alias (local, __GI_##name) -# define HIDDEN_JUMPTARGET(name) __GI_##name -# endif -#else -# ifndef __ASSEMBLER__ -# if !defined SHARED && IS_IN (libc) && !defined LIBC_NONSHARED \ - && (!defined PIC || !defined NO_HIDDEN_EXTERN_FUNC_IN_PIE) \ - && !defined NO_HIDDEN -# define __hidden_proto_hiddenattr(attrs...) \ - __attribute__ ((visibility ("hidden"), ##attrs)) -# define hidden_proto(name, attrs...) \ - __hidden_proto (name, , name, ##attrs) -# define hidden_tls_proto(name, attrs...) \ - __hidden_proto (name, __thread, name, ##attrs) -# define __hidden_proto(name, thread, internal, attrs...) \ - extern thread __typeof (name) name __hidden_proto_hiddenattr (attrs); -# else -# define hidden_proto(name, attrs...) -# define hidden_tls_proto(name, attrs...) -# endif -# else -# define HIDDEN_JUMPTARGET(name) JUMPTARGET(name) -# endif /* Not __ASSEMBLER__ */ -# define hidden_weak(name) -# define hidden_def(name) -# define hidden_ver(local, name) -# define hidden_data_weak(name) -# define hidden_data_def(name) -# define hidden_tls_def(name) -# define hidden_data_ver(local, name) -# define hidden_nolink(name, lib, version) -#endif - -#if IS_IN (libc) -# define libc_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libc_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) -# define libc_hidden_def(name) hidden_def (name) -# define libc_hidden_weak(name) hidden_weak (name) -# define libc_hidden_nolink_sunrpc(name, version) hidden_nolink (name, libc, version) -# define libc_hidden_ver(local, name) hidden_ver (local, name) -# define libc_hidden_data_def(name) hidden_data_def (name) -# define libc_hidden_tls_def(name) hidden_tls_def (name) -# define libc_hidden_data_weak(name) hidden_data_weak (name) -# define libc_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libc_hidden_proto(name, attrs...) -# define libc_hidden_tls_proto(name, attrs...) -# define libc_hidden_def(name) -# define libc_hidden_weak(name) -# define libc_hidden_ver(local, name) -# define libc_hidden_data_def(name) -# define libc_hidden_tls_def(name) -# define libc_hidden_data_weak(name) -# define libc_hidden_data_ver(local, name) -#endif - -#if IS_IN (rtld) -# define rtld_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define rtld_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) -# define rtld_hidden_def(name) hidden_def (name) -# define rtld_hidden_weak(name) hidden_weak (name) -# define rtld_hidden_ver(local, name) hidden_ver (local, name) -# define rtld_hidden_data_def(name) hidden_data_def (name) -# define rtld_hidden_tls_def(name) hidden_tls_def (name) -# define rtld_hidden_data_weak(name) hidden_data_weak (name) -# define rtld_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define rtld_hidden_proto(name, attrs...) -# define rtld_hidden_tls_proto(name, attrs...) -# define rtld_hidden_def(name) -# define rtld_hidden_weak(name) -# define rtld_hidden_ver(local, name) -# define rtld_hidden_data_def(name) -# define rtld_hidden_tls_def(name) -# define rtld_hidden_data_weak(name) -# define rtld_hidden_data_ver(local, name) -#endif - -#if IS_IN (libm) -# define libm_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libm_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) -# define libm_hidden_def(name) hidden_def (name) -# define libm_hidden_weak(name) hidden_weak (name) -# define libm_hidden_ver(local, name) hidden_ver (local, name) -# define libm_hidden_data_def(name) hidden_data_def (name) -# define libm_hidden_tls_def(name) hidden_tls_def (name) -# define libm_hidden_data_weak(name) hidden_data_weak (name) -# define libm_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libm_hidden_proto(name, attrs...) -# define libm_hidden_tls_proto(name, attrs...) -# define libm_hidden_def(name) -# define libm_hidden_weak(name) -# define libm_hidden_ver(local, name) -# define libm_hidden_data_def(name) -# define libm_hidden_tls_def(name) -# define libm_hidden_data_weak(name) -# define libm_hidden_data_ver(local, name) -#endif - -#if IS_IN (libmvec) -# define libmvec_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libmvec_hidden_tls_proto(name, attrs...) hidden_tls_proto (name, ##attrs) -# define libmvec_hidden_def(name) hidden_def (name) -# define libmvec_hidden_weak(name) hidden_weak (name) -# define libmvec_hidden_ver(local, name) hidden_ver (local, name) -# define libmvec_hidden_data_def(name) hidden_data_def (name) -# define libmvec_hidden_tls_def(name) hidden_tls_def (name) -# define libmvec_hidden_data_weak(name) hidden_data_weak (name) -# define libmvec_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libmvec_hidden_proto(name, attrs...) -# define libmvec_hidden_tls_proto(name, attrs...) -# define libmvec_hidden_def(name) -# define libmvec_hidden_weak(name) -# define libmvec_hidden_ver(local, name) -# define libmvec_hidden_data_def(name) -# define libmvec_hidden_tls_def(name) -# define libmvec_hidden_data_weak(name) -# define libmvec_hidden_data_ver(local, name) -#endif - -#if IS_IN (libresolv) -# define libresolv_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libresolv_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libresolv_hidden_def(name) hidden_def (name) -# define libresolv_hidden_weak(name) hidden_weak (name) -# define libresolv_hidden_ver(local, name) hidden_ver (local, name) -# define libresolv_hidden_data_def(name) hidden_data_def (name) -# define libresolv_hidden_tls_def(name) hidden_tls_def (name) -# define libresolv_hidden_data_weak(name) hidden_data_weak (name) -# define libresolv_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libresolv_hidden_proto(name, attrs...) -# define libresolv_hidden_tls_proto(name, attrs...) -# define libresolv_hidden_def(name) -# define libresolv_hidden_weak(name) -# define libresolv_hidden_ver(local, name) -# define libresolv_hidden_data_def(name) -# define libresolv_hidden_tls_def(name) -# define libresolv_hidden_data_weak(name) -# define libresolv_hidden_data_ver(local, name) -#endif - -#if IS_IN (libpthread) -# define libpthread_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libpthread_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libpthread_hidden_def(name) hidden_def (name) -# define libpthread_hidden_weak(name) hidden_weak (name) -# define libpthread_hidden_ver(local, name) hidden_ver (local, name) -# define libpthread_hidden_data_def(name) hidden_data_def (name) -# define libpthread_hidden_tls_def(name) hidden_tls_def (name) -# define libpthread_hidden_data_weak(name) hidden_data_weak (name) -# define libpthread_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libpthread_hidden_proto(name, attrs...) -# define libpthread_hidden_tls_proto(name, attrs...) -# define libpthread_hidden_def(name) -# define libpthread_hidden_weak(name) -# define libpthread_hidden_ver(local, name) -# define libpthread_hidden_data_def(name) -# define libpthread_hidden_tls_def(name) -# define libpthread_hidden_data_weak(name) -# define libpthread_hidden_data_ver(local, name) -#endif - -#if IS_IN (librt) -# define librt_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define librt_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define librt_hidden_def(name) hidden_def (name) -# define librt_hidden_weak(name) hidden_weak (name) -# define librt_hidden_ver(local, name) hidden_ver (local, name) -# define librt_hidden_data_def(name) hidden_data_def (name) -# define librt_hidden_tls_def(name) hidden_tls_def (name) -# define librt_hidden_data_weak(name) hidden_data_weak (name) -# define librt_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define librt_hidden_proto(name, attrs...) -# define librt_hidden_tls_proto(name, attrs...) -# define librt_hidden_def(name) -# define librt_hidden_weak(name) -# define librt_hidden_ver(local, name) -# define librt_hidden_data_def(name) -# define librt_hidden_tls_def(name) -# define librt_hidden_data_weak(name) -# define librt_hidden_data_ver(local, name) -#endif - -#if IS_IN (libdl) -# define libdl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libdl_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libdl_hidden_def(name) hidden_def (name) -# define libdl_hidden_weak(name) hidden_weak (name) -# define libdl_hidden_ver(local, name) hidden_ver (local, name) -# define libdl_hidden_data_def(name) hidden_data_def (name) -# define libdl_hidden_tls_def(name) hidden_tls_def (name) -# define libdl_hidden_data_weak(name) hidden_data_weak (name) -# define libdl_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libdl_hidden_proto(name, attrs...) -# define libdl_hidden_tls_proto(name, attrs...) -# define libdl_hidden_def(name) -# define libdl_hidden_weak(name) -# define libdl_hidden_ver(local, name) -# define libdl_hidden_data_def(name) -# define libdl_hidden_tls_def(name) -# define libdl_hidden_data_weak(name) -# define libdl_hidden_data_ver(local, name) -#endif - -#if IS_IN (libnss_files) -# define libnss_files_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libnss_files_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libnss_files_hidden_def(name) hidden_def (name) -# define libnss_files_hidden_weak(name) hidden_weak (name) -# define libnss_files_hidden_ver(local, name) hidden_ver (local, name) -# define libnss_files_hidden_data_def(name) hidden_data_def (name) -# define libnss_files_hidden_tls_def(name) hidden_tls_def (name) -# define libnss_files_hidden_data_weak(name) hidden_data_weak (name) -# define libnss_files_hidden_data_ver(local, name) hidden_data_ver(local, name) -#else -# define libnss_files_hidden_proto(name, attrs...) -# define libnss_files_hidden_tls_proto(name, attrs...) -# define libnss_files_hidden_def(name) -# define libnss_files_hidden_weak(name) -# define libnss_files_hidden_ver(local, name) -# define libnss_files_hidden_data_def(name) -# define libnss_files_hidden_tls_def(name) -# define libnss_files_hidden_data_weak(name) -# define libnss_files_hidden_data_ver(local, name) -#endif - -#if IS_IN (libnsl) -# define libnsl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libnsl_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libnsl_hidden_nolink_def(name, version) hidden_nolink (name, libnsl, version) -# define libnsl_hidden_weak(name) hidden_weak (name) -# define libnsl_hidden_ver(local, name) hidden_ver (local, name) -# define libnsl_hidden_data_def(name) hidden_data_def (name) -# define libnsl_hidden_tls_def(name) hidden_tls_def (name) -# define libnsl_hidden_data_weak(name) hidden_data_weak (name) -# define libnsl_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libnsl_hidden_proto(name, attrs...) -# define libnsl_hidden_tls_proto(name, attrs...) -# define libnsl_hidden_weak(name) -# define libnsl_hidden_ver(local, name) -# define libnsl_hidden_data_def(name) -# define libnsl_hidden_tls_def(name) -# define libnsl_hidden_data_weak(name) -# define libnsl_hidden_data_ver(local, name) -#endif - -#define libc_hidden_builtin_proto(name, attrs...) libc_hidden_proto (name, ##attrs) -#define libc_hidden_builtin_def(name) libc_hidden_def (name) -#define libc_hidden_builtin_weak(name) libc_hidden_weak (name) -#define libc_hidden_builtin_ver(local, name) libc_hidden_ver (local, name) - -#define libc_hidden_ldbl_proto(name, attrs...) libc_hidden_proto (name, ##attrs) -#ifdef __ASSEMBLER__ -# define HIDDEN_BUILTIN_JUMPTARGET(name) HIDDEN_JUMPTARGET(name) -#endif - -#if IS_IN (libutil) -# define libutil_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libutil_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libutil_hidden_def(name) hidden_def (name) -# define libutil_hidden_weak(name) hidden_weak (name) -# define libutil_hidden_ver(local, name) hidden_ver (local, name) -# define libutil_hidden_data_def(name) hidden_data_def (name) -# define libutil_hidden_tls_def(name) hidden_tls_def (name) -# define libutil_hidden_data_weak(name) hidden_data_weak (name) -# define libutil_hidden_data_ver(local, name) hidden_data_ver (local, name) -#else -# define libutil_hidden_proto(name, attrs...) -# define libutil_hidden_tls_proto(name, attrs...) -# define libutil_hidden_def(name) -# define libutil_hidden_weak(name) -# define libutil_hidden_ver(local, name) -# define libutil_hidden_data_def(name) -# define libutil_hidden_tls_def(name) -# define libutil_hidden_data_weak(name) -# define libutil_hidden_data_ver(local, name) -#endif - -#if IS_IN (libanl) -# define libanl_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libanl_hidden_def(name) hidden_def (name) -#else -# define libanl_hidden_proto(name, attrs...) -# define libanl_hidden_def(name) -#endif - -/* Get some dirty hacks. */ -#include - -/* Move compatibility symbols out of the way by placing them all in a - special section. */ -#ifndef __ASSEMBLER__ -# define attribute_compat_text_section \ - __attribute__ ((section (".text.compat"))) -# define attribute_compat_data_section \ - __attribute__ ((section (".data.compat"))) -#else -# define compat_text_section .section ".text.compat", "ax"; -# define compat_data_section .section ".data.compat", "aw"; -#endif - -/* Helper / base macros for indirect function symbols. */ -#define __ifunc_resolver(type_name, name, expr, arg, init, classifier) \ - classifier inhibit_stack_protector \ - __typeof (type_name) *name##_ifunc (arg) \ - { \ - init (); \ - __typeof (type_name) *res = expr; \ - return res; \ - } - -#ifdef HAVE_GCC_IFUNC -# define __ifunc(type_name, name, expr, arg, init) \ - extern __typeof (type_name) name __attribute__ \ - ((ifunc (#name "_ifunc"))); \ - __ifunc_resolver (type_name, name, expr, arg, init, static) - -# define __ifunc_hidden(type_name, name, expr, arg, init) \ - __ifunc (type_name, name, expr, arg, init) -#else -/* Gcc does not support __attribute__ ((ifunc (...))). Use the old behaviour - as fallback. But keep in mind that the debug information for the ifunc - resolver functions is not correct. It contains the ifunc'ed function as - DW_AT_linkage_name. E.g. lldb uses this field and an inferior function - call of the ifunc'ed function will fail due to "no matching function for - call to ..." because the ifunc'ed function and the resolver function have - different signatures. (Gcc support is disabled at least on a ppc64le - Ubuntu 14.04 system.) */ - -# define __ifunc(type_name, name, expr, arg, init) \ - extern __typeof (type_name) name; \ - __typeof (type_name) *name##_ifunc (arg) __asm__ (#name); \ - __ifunc_resolver (type_name, name, expr, arg, init,) \ - __asm__ (".type " #name ", %gnu_indirect_function"); - -# define __ifunc_hidden(type_name, name, expr, arg, init) \ - extern __typeof (type_name) __libc_##name; \ - __ifunc (type_name, __libc_##name, expr, arg, init) \ - strong_alias (__libc_##name, name); -#endif /* !HAVE_GCC_IFUNC */ - -/* The following macros are used for indirect function symbols in libc.so. - First of all, you need to have the function prototyped somewhere, - say in foo.h: - - int foo (int __bar); - - If you have an implementation for foo which e.g. uses a special hardware - feature which isn't available on all machines where this libc.so will be - used but decideable if available at runtime e.g. via hwcaps, you can provide - two or multiple implementations of foo: - - int __foo_default (int __bar) - { - return __bar; - } - - int __foo_special (int __bar) - { - return __bar; - } - - If your function foo has no libc_hidden_proto (foo) defined for PLT - bypassing, you can use: - - #define INIT_ARCH() unsigned long int hwcap = __GLRO(dl_hwcap); - - libc_ifunc (foo, (hwcap & HWCAP_SPECIAL) ? __foo_special : __foo_default); - - This will define a resolver function for foo which returns __foo_special or - __foo_default depending on your specified expression. Please note that you - have to define a macro function INIT_ARCH before using libc_ifunc macro as - it is called by the resolver function before evaluating the specified - expression. In this example it is used to prepare the hwcap variable. - The resolver function is assigned to an ifunc'ed symbol foo. Calls to foo - from inside or outside of libc.so will be indirected by a PLT call. - - If your function foo has a libc_hidden_proto (foo) defined for PLT bypassing - and calls to foo within libc.so should always go to one specific - implementation of foo e.g. __foo_default then you have to add: - - __hidden_ver1 (__foo_default, __GI_foo, __foo_default); - - or a tweaked definition of libc_hidden_def macro after the __foo_default - function definition. Calls to foo within libc.so will always go directly to - __foo_default. Calls to foo from outside libc.so will be indirected by a - PLT call to ifunc'ed symbol foo which you have to define in a separate - compile unit: - - #define foo __redirect_foo - #include - #undef foo - - extern __typeof (__redirect_foo) __foo_default attribute_hidden; - extern __typeof (__redirect_foo) __foo_special attribute_hidden; - - libc_ifunc_redirected (__redirect_foo, foo, - (hwcap & HWCAP_SPECIAL) - ? __foo_special - : __foo_default); - - This will define the ifunc'ed symbol foo like above. The redirection of foo - in header file is needed to omit an additional defintion of __GI_foo which - would end in a linker error while linking libc.so. You have to specify - __redirect_foo as first parameter which is used within libc_ifunc_redirected - macro in conjunction with typeof to define the ifunc'ed symbol foo. - - If your function foo has a libc_hidden_proto (foo) defined and calls to foo - within or from outside libc.so should go via ifunc'ed symbol, then you have - to use: - - libc_ifunc_hidden (foo, foo, - (hwcap & HWCAP_SPECIAL) - ? __foo_special - : __foo_default); - libc_hidden_def (foo) - - The first parameter foo of libc_ifunc_hidden macro is used in the same way - as for libc_ifunc_redirected macro. */ - -#define libc_ifunc(name, expr) __ifunc (name, name, expr, void, INIT_ARCH) - -#define libc_ifunc_redirected(redirected_name, name, expr) \ - __ifunc (redirected_name, name, expr, void, INIT_ARCH) - -#define libc_ifunc_hidden(redirected_name, name, expr) \ - __ifunc_hidden (redirected_name, name, expr, void, INIT_ARCH) - -/* The body of the function is supposed to use __get_cpu_features - which will, if necessary, initialize the data first. */ -#define libm_ifunc_init() -#define libm_ifunc(name, expr) \ - __ifunc (name, name, expr, void, libm_ifunc_init) - -/* Add the compiler optimization to inhibit loop transformation to library - calls. This is used to avoid recursive calls in memset and memmove - default implementations. */ -#ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL -# define inhibit_loop_to_libcall \ - __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns"))) -#else -# define inhibit_loop_to_libcall -#endif - -/* These macros facilitate sharing source files with gnulib. - - They are here instead of sys/cdefs.h because they should not be - used in public header files. - - Their definitions should be kept consistent with the definitions in - gnulib-common.m4, but it is not necessary to cater to old non-GCC - compilers, since they will only be used while building glibc itself. - (Note that _GNUC_PREREQ cannot be used in this file.) */ - -/* Define as a marker that can be attached to declarations that might not - be used. This helps to reduce warnings, such as from - GCC -Wunused-parameter. */ -#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) -# define _GL_UNUSED __attribute__ ((__unused__)) -#else -# define _GL_UNUSED -#endif - -/* gcc supports the "unused" attribute on possibly unused labels, and - g++ has since version 4.5. Note to support C++ as well as C, - _GL_UNUSED_LABEL should be used with a trailing ; */ -#if !defined __cplusplus || __GNUC__ > 4 \ - || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -# define _GL_UNUSED_LABEL _GL_UNUSED -#else -# define _GL_UNUSED_LABEL -#endif - -/* The __pure__ attribute was added in gcc 2.96. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) -#else -# define _GL_ATTRIBUTE_PURE /* empty */ -#endif - -/* The __const__ attribute was added in gcc 2.95. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__)) -#else -# define _GL_ATTRIBUTE_CONST /* empty */ -#endif - -#endif /* !_ISOMAC */ -#endif /* libc-symbols.h */ diff --git a/benchmark-src/README.md b/glibc-benchmark-info.md similarity index 100% rename from benchmark-src/README.md rename to glibc-benchmark-info.md From 51c531b6fad5e791941da428d3ea41d9775104df Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sun, 27 Jun 2021 11:04:30 -0700 Subject: [PATCH 09/16] Update glibc-benchmark-info.md --- README.md | 2 +- glibc-benchmark-info.md | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dc241dc..c34c7c6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -See the included glibc benchmark source code and readme here: [benchmark-src](benchmark-src) +See also more glibc source code and build info. here: [glibc-benchmark-info.md](glibc-benchmark-info.md). # malloc-benchmarks diff --git a/glibc-benchmark-info.md b/glibc-benchmark-info.md index 83be582..f448571 100644 --- a/glibc-benchmark-info.md +++ b/glibc-benchmark-info.md @@ -1,10 +1,8 @@ -# Benchmark utility sources +# Glibc benchmark utility source code -The sources collected here are a small subset of the GNU libc benchmarking utility for `malloc` implementations. +The primary glibc malloc benchmarking utility is `glibc/benchtests/bech-malloc-thread.c`. It is automatically downloaded by this repo, then built and run when you call `make`. -Please see `glibc/benchtests/bech-malloc-thread.c` for the most up-to-date source code. - -You can obtain it here: https://www.gnu.org/software/libc/sources.html: +You can manually obtain the glibc source code here: https://www.gnu.org/software/libc/sources.html: ```bash git clone https://sourceware.org/git/glibc.git cd glibc @@ -17,7 +15,38 @@ See also: 1. https://kazoo.ga/a-simple-tool-to-test-malloc-performance/ -## Each of the above source files came from the following glibc paths: +## If you ever wish to manually build glibc and its benchtests, do so as follows: + +References: +1. https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html +1. This project's makefile +1. https://stackoverflow.com/questions/10412684/how-to-compile-my-own-glibc-c-standard-library-from-source-and-use-it/68153847#68153847 + + +```bash +# IMPORTANT: begin AT THE SAME DIRECTORY LEVEL as the `glibc` source code +# directory, NOT inside the `glibc` source code dir! In other words, if +# you are in the correct dir, running `ls` will show the `glibc` source +# code dir (that you just cloned) inside the dir you are in. +mkdir -p glibc-build +mkdir -p glibc-install +cd glibc-build +../glibc/configure --prefix="$(realpath "../glibc-install")" +time make -j8 # build with 8 threads (jobs); on a fast laptop this takes ~3 min. +time make install # (optional: install to the `glibc-install` dir you created) + +# Build the benchtests (everything inside the `glibc/benchtests` dir) too +time make bench-build -j8 +# Now you have this file you can use for malloc speed tests, for instance!: +# ../glibc-build/benchtests/bench-malloc-thread + +# To build **and run** all glibc benchtests, do: +time make bench +``` + +## If you'd like to manually extract the files you need to just build this benchtest, here are the paths of _some_ of them, to get you started: + +**Note: this technique is Not recommended, since it's hard to track down all of the source files needed, and build settings. Instead, just build glibc and its bench tests from the entire glibc source code as shown above.** ```bash glibc/benchtests/bench-malloc-simple.c # <=== this one From 4d127e8fa8dcfeffbe287774abde026a55c27547 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sun, 27 Jun 2021 12:55:50 -0700 Subject: [PATCH 10/16] Improve the results dirnames to be unique down to the second, not just the day... ...so that results are no longer overwritten just because you ran the benchmark tool more than once in a single day. --- Makefile | 8 ++++---- README.md | 6 +++--- bench_plot_results.py | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index a7327a6..48eaa8d 100755 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ ifdef NUMPROC parallel_flags := -j$(NUMPROC) else # default value: pull from the max number of hardware processes: `nproc` cmd output; ex: 8 -parallel_flags := -j$(nproc) +parallel_flags := -j$(shell nproc) endif ifdef POSTFIX @@ -55,7 +55,7 @@ ifdef RESULT_DIRNAME results_dir := $(RESULT_DIRNAME) else # default value -results_dir := results/$(shell date +%F)-$(benchmark_postfix) +results_dir := results/$(shell date '+%Y.%m.%d-%H%Mhrs-%Ssec')--$(benchmark_postfix) endif ifdef IMPLEMENTATIONS @@ -74,7 +74,7 @@ endif topdir=$(shell readlink -f .) -benchmark_result_json := results.json +benchmark_result_json := results.json # the suffix for the json file names benchmark_result_png := results.png glibc_url := git://sourceware.org/git/glibc.git @@ -170,7 +170,7 @@ collect_results: @echo -n "Number of CPU cores: " >>$(results_dir)/hardware-inventory.txt @grep "processor" /proc/cpuinfo | wc -l >>$(results_dir)/hardware-inventory.txt # NB: you may need to install `numactl` first with `sudo apt install numactl`. - @(which numactl >/dev/null 2>&1) && echo "NUMA informations:" >>$(results_dir)/hardware-inventory.txt + @(which numactl >/dev/null 2>&1) && echo "NUMA information (from 'numactl -H'):" >>$(results_dir)/hardware-inventory.txt @(which numactl >/dev/null 2>&1) && numactl -H >>$(results_dir)/hardware-inventory.txt plot_results: diff --git a/README.md b/README.md index c34c7c6..5090b44 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,12 @@ make time make ``` -Once you have run `make`, the plot will display. To re-plot the results without rerunning the tests, run: +Once you have run `make`, the plot will display. To re-plot the results without rerunning the tests, run the following, specifying the correct dirname: ```bash -make plot_results +RESULT_DIRNAME='results/my_dir_name' make plot_results ``` -Note that each time you run `make`, all of the benchmark results will be stored in a folder for your computer within the `results` dir, overwriting all previous results. So, if you wish to save previous benchmarking runs, be sure to rename your computer's folder in the `results` dir prior to running `make` again. +Note that each time you run `make`, all of the benchmark results will be stored in a folder for your computer within the `results` dir. You can customize the runs be setting environment variables as you call `make`. See the top of the `Makefile` for details. See the default values for `benchmark_nthreads` and `implem_list` in the `Makefile`. diff --git a/bench_plot_results.py b/bench_plot_results.py index d1b71a8..7fe0c0e 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -17,7 +17,8 @@ def plot_graphs(outfilename, benchmark_dict): """ plotlib.clf() plotlib.xlabel('Number of threads') - plotlib.ylabel('CPU cycles per malloc op') # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles + # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles + plotlib.ylabel('CPU cycles per malloc op') nmarker=0 max_x=[] @@ -45,13 +46,12 @@ def plot_graphs(outfilename, benchmark_dict): plotlib.xlim(0, max(max_x)*1.1) plotlib.ylim(0, max(max_y)*1.3) + outfilename_dir = os.path.dirname(outfilename) print("Writing plot into '%s'" % outfilename) - print("- - -\n" + - "Close the plot to terminate the program. Run `make plot_results` to plot the results\n" + - "again. Be sure to manually make a copy of the \"results\" folder (if you wish to\n" + - "save your results) before running `make` again, or else these results will be\n" + - "overwritten.\n" + - "- - -") + print(("- - -\n" + + "Close the plot to terminate the program. Run `RESULT_DIRNAME='{}' make plot_results`\n" + + "to plot the results again.\n" + + "- - -").format(outfilename_dir)) plotlib.legend(loc='upper left') plotlib.savefig(outfilename) plotlib.show() @@ -64,7 +64,7 @@ def main(args): print('Usage: %s ...' % sys.argv[0]) sys.exit(os.EX_USAGE) - bm = {} + bm = {} # benchmark dict for filepath in args[1:]: print("Parsing '{}'...".format(filepath)) with open(filepath, 'r') as benchfile: From f0630c82544fa2f8cf832cc5ee0057d6012ad788 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Sun, 27 Jun 2021 17:42:41 -0700 Subject: [PATCH 11/16] bench_collect_results.py: improve the cmd output ...to show the user exactly what the equivalent cmd would be if manually typed at the command-line. --- bench_collect_results.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/bench_collect_results.py b/bench_collect_results.py index a49a38d..6d5b6f5 100755 --- a/bench_collect_results.py +++ b/bench_collect_results.py @@ -102,8 +102,10 @@ def run_benchmark(outfile,thread_values,impl_name): last_nthreads = thread_values[len(thread_values)-1] bm = {} for nthreads in thread_values: + # run the external benchmark utility with the LD_PRELOAD trick try: + # 1. Set the `LD_PRELOAD` environment variable os.environ["LD_PRELOAD"] = impl_preload_libs[impl_name] if len(os.environ["LD_PRELOAD"])>0: # the tcmalloc/jemalloc shared libs require in turn C++ libs: @@ -113,14 +115,17 @@ def run_benchmark(outfile,thread_values,impl_name): utility_fname = benchmark_util[impl_name] - - # run the external benchmark utility with the LD_PRELOAD trick - print("Running for nthreads={}:\n LD_PRELOAD='{}' {} {}".format(nthreads,os.environ["LD_PRELOAD"],utility_fname,nthreads)) - + cmd = "{} {} >/tmp/benchmark-output".format(utility_fname, nthreads) + full_cmd = "LD_PRELOAD='{}' {}".format(os.environ["LD_PRELOAD"], cmd) + + print("Running this benchmark cmd for nthreads={}:".format(nthreads)) + print(" {}".format(full_cmd)) + + # 2. Call the benchmark cmd # the subprocess.check_output() method does not seem to work fine when launching # the ld-linux-x86-64.so.2 with --library-path #stdout = subprocess.check_output([utility_fname, nthreads]) - os.system("{} {} >/tmp/benchmark-output".format(utility_fname,nthreads)) + os.system(cmd) stdout = open('/tmp/benchmark-output', 'r').read() # produce valid JSON output: @@ -159,7 +164,7 @@ def main(args): print("----------------------------------------------------------------------------------------------") print("Testing implementation '{}'. Saving results into '{}'".format(implementations[idx],outfile)) - print("Will run tests for {} different number of threads".format(len(thread_values))) + print("Will run tests for {} different numbers of threads.".format(len(thread_values))) success = success + run_benchmark(outfile,thread_values,implementations[idx]) print("----------------------------------------------------------------------------------------------") From e0b3246716742795d7ab969e4daed48a8917c5d8 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Mon, 28 Jun 2021 09:42:07 -0700 Subject: [PATCH 12/16] Update scripts to collect hardware info first ...so the sudo pw is requested immediately when you run `make`. Also do a few other very minor improvements. --- Makefile | 8 +++++--- README.md | 3 ++- bench_collect_results.py | 13 ++++++++----- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 48eaa8d..a4eccc7 100755 --- a/Makefile +++ b/Makefile @@ -163,9 +163,8 @@ endif collect_results: @mkdir -p $(results_dir) - @echo "Starting to collect performance benchmarks." - ./bench_collect_results.py "$(implem_list)" $(results_dir)/$(benchmark_result_json) $(benchmark_nthreads) - @echo "Collecting hardware information in $(results_dir)/hardware-inventory.txt" + + @echo "Collecting hardware information (sudo required) in $(results_dir)/hardware-inventory.txt" @sudo lshw -short -class memory -class processor > $(results_dir)/hardware-inventory.txt @echo -n "Number of CPU cores: " >>$(results_dir)/hardware-inventory.txt @grep "processor" /proc/cpuinfo | wc -l >>$(results_dir)/hardware-inventory.txt @@ -173,6 +172,9 @@ collect_results: @(which numactl >/dev/null 2>&1) && echo "NUMA information (from 'numactl -H'):" >>$(results_dir)/hardware-inventory.txt @(which numactl >/dev/null 2>&1) && numactl -H >>$(results_dir)/hardware-inventory.txt + @echo "Starting to collect performance benchmarks." + ./bench_collect_results.py "$(implem_list)" $(results_dir)/$(benchmark_result_json) $(benchmark_nthreads) + plot_results: ./bench_plot_results.py $(results_dir)/$(benchmark_result_png) $(results_dir)/*.json diff --git a/README.md b/README.md index 5090b44..d1bf43d 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,8 @@ On the other machine where you want to plot results: git clone https://github.com/f18m/malloc-benchmarks.git cd malloc-benchmarks mv ../results . -make plot_results +# manually specify the correct `my_dir_name` below +RESULT_DIRNAME='results/my_dir_name' make plot_results ``` diff --git a/bench_collect_results.py b/bench_collect_results.py index 6d5b6f5..fc96449 100755 --- a/bench_collect_results.py +++ b/bench_collect_results.py @@ -26,19 +26,22 @@ 'jemalloc': jemalloc_install_dir + '/lib/libjemalloc.so' } -# to successfully preload the tcmalloc,jemalloc libs we will also need to preload the C++ standard lib and gcc_s lib: +# to successfully preload the tcmalloc,jemalloc libs we will also need to preload the C++ standard +# lib and gcc_s lib: preload_required_libs= [ 'libstdc++.so.6', 'libgcc_s.so.1' ] preload_required_libs_fullpaths = [] benchmark_util = { 'system_default': internal_benchmark_util, - # to test the latest GNU libc implementation downloaded and compiled locally we use another trick: - # we ask the dynamic linker of the just-built GNU libc to run the benchmarking utility using new GNU libc dyn libs: - 'glibc': glibc_install_dir + '/lib/ld-linux-x86-64.so.2 --library-path ' + glibc_install_dir + '/lib ' + internal_benchmark_util, + # to test the latest GNU libc implementation downloaded and compiled locally we use another + # trick: we ask the dynamic linker of the just-built GNU libc to run the benchmarking utility + # using the new GNU libc dynamic libs: + 'glibc': (glibc_install_dir + '/lib/ld-linux-x86-64.so.2 --library-path ' + glibc_install_dir + + '/lib ' + internal_benchmark_util), 'tcmalloc': internal_benchmark_util, - 'jemalloc': internal_benchmark_util + 'jemalloc': internal_benchmark_util, } def find(name, paths): From 41a049828a60efb8fd2fbe2783ed1e9eef231507 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Mon, 28 Jun 2021 11:17:33 -0700 Subject: [PATCH 13/16] bench_plot_results.py: wip: add a title and subtitle to the figure --- bench_plot_results.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/bench_plot_results.py b/bench_plot_results.py index 7fe0c0e..b185d24 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -15,17 +15,28 @@ def plot_graphs(outfilename, benchmark_dict): """Plots the given dictionary of benchmark results """ + # print("benchmark_dict = {}".format(benchmark_dict)) ####### plotlib.clf() + # main figure title + plotlib.suptitle("Malloc speed tests (tested w/glibc's `benchtests/bench-malloc-thread.c`)") plotlib.xlabel('Number of threads') # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles - plotlib.ylabel('CPU cycles per malloc op') + plotlib.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') nmarker=0 max_x=[] max_y=[] + first_itn = True ####### for impl_name in benchmark_dict.keys(): current_bm = benchmark_dict[impl_name] + #############3 + # if first_itn: + # first_itn = False + # # figure subtitle + # plotlib.title("[min, max] num bytes per malloc = [{}, {}]".format( + # current_bm[0].min_size, current_bm[0].min_size), fontsize=10) + # add a line plot X = [ x.threads for x in current_bm ] Y = [ y.time_per_iteration for y in current_bm ] @@ -64,7 +75,7 @@ def main(args): print('Usage: %s ...' % sys.argv[0]) sys.exit(os.EX_USAGE) - bm = {} # benchmark dict + benchmark_dict = {} for filepath in args[1:]: print("Parsing '{}'...".format(filepath)) with open(filepath, 'r') as benchfile: @@ -77,13 +88,13 @@ def main(args): sys.exit(2) #print json.dumps(bench_list, sort_keys=True, indent=4, separators=(',', ': ')) - bm[filename] = [] + benchmark_dict[filename] = [] for bench in bench_list: - bm[filename].append(BenchmarkPoint(bench['functions']['malloc']['']['threads'], bench['functions']['malloc']['']['time_per_iteration'])) + benchmark_dict[filename].append(BenchmarkPoint(bench['functions']['malloc']['']['threads'], bench['functions']['malloc']['']['time_per_iteration'])) - print('Found {} data points in {}...'.format(len(bm[filename]), filepath)) + print('Found {} data points in {}...'.format(len(benchmark_dict[filename]), filepath)) - plot_graphs(args[0], bm) + plot_graphs(args[0], benchmark_dict) if __name__ == '__main__': main(sys.argv[1:]) From a92083309250a0396db4f192d63d7da2cd893fa0 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Mon, 28 Jun 2021 12:14:33 -0700 Subject: [PATCH 14/16] bench_plot_results.py: add plot subtitle; improve plot data structures --- bench_plot_results.py | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/bench_plot_results.py b/bench_plot_results.py index b185d24..8be8aec 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -4,21 +4,28 @@ import sys import os import json -import collections import matplotlib.pyplot as plotlib -BenchmarkPoint = collections.namedtuple('BenchmarkPoint', ['threads', 'time_per_iteration']) filled_markers = ('o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', 'P', 'X') colours = ('r', 'g', 'b', 'black', 'yellow', 'purple') def plot_graphs(outfilename, benchmark_dict): """Plots the given dictionary of benchmark results """ - # print("benchmark_dict = {}".format(benchmark_dict)) ####### + # print("benchmark_dict = {}".format(benchmark_dict)) + + # any one of the data sets--just to grab some subtitle data that is common to all the data sets + a_key = list(benchmark_dict.keys())[0] + data_dict = benchmark_dict[a_key][0] + # print("data_dict = {}".format(data_dict)) + plotlib.clf() # main figure title plotlib.suptitle("Malloc speed tests (tested w/glibc's `benchtests/bench-malloc-thread.c`)") + # figure subtitle + plotlib.title("num bytes per malloc: min = {}; max = {}".format(data_dict["min_size"], + data_dict["max_size"]), fontsize=10) plotlib.xlabel('Number of threads') # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles plotlib.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') @@ -26,20 +33,14 @@ def plot_graphs(outfilename, benchmark_dict): nmarker=0 max_x=[] max_y=[] - first_itn = True ####### for impl_name in benchmark_dict.keys(): - current_bm = benchmark_dict[impl_name] - - #############3 - # if first_itn: - # first_itn = False - # # figure subtitle - # plotlib.title("[min, max] num bytes per malloc = [{}, {}]".format( - # current_bm[0].min_size, current_bm[0].min_size), fontsize=10) + data_list_of_dicts = benchmark_dict[impl_name] + # print("data_list_of_dicts = {}".format(data_list_of_dicts)) # add a line plot - X = [ x.threads for x in current_bm ] - Y = [ y.time_per_iteration for y in current_bm ] + X = [x["threads"] for x in data_list_of_dicts] + Y = [y["time_per_iteration"] for y in data_list_of_dicts] + lines = plotlib.plot(X, Y, '-' + filled_markers[nmarker], label=impl_name) plotlib.setp(lines, 'color', colours[nmarker]) @@ -82,17 +83,19 @@ def main(args): filename = os.path.basename(filepath) try: - bench_list = json.load(benchfile) + bench_list_of_dicts = json.load(benchfile) except Exception as ex: print("Invalid JSON file {}: {}".format(filepath, ex)) sys.exit(2) - #print json.dumps(bench_list, sort_keys=True, indent=4, separators=(',', ': ')) - + # print(json.dumps(bench_list_of_dicts, sort_keys=True, indent=4, + # separators=(',', ': '))) + benchmark_dict[filename] = [] - for bench in bench_list: - benchmark_dict[filename].append(BenchmarkPoint(bench['functions']['malloc']['']['threads'], bench['functions']['malloc']['']['time_per_iteration'])) + for bench in bench_list_of_dicts: + data_dict = bench["functions"]["malloc"][""] + benchmark_dict[filename].append(data_dict) - print('Found {} data points in {}...'.format(len(benchmark_dict[filename]), filepath)) + print(' Found {} data points in {}...'.format(len(benchmark_dict[filename]), filepath)) plot_graphs(args[0], benchmark_dict) From 21c17be727e73e54dd2261f3da9e32eb0669d259 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Mon, 28 Jun 2021 13:49:20 -0700 Subject: [PATCH 15/16] bench_plot_results.py: wip: start adding subplots ...so I can have 2 plots on the figure: one for speed and one for memory usage. --- bench_plot_results.py | 88 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/bench_plot_results.py b/bench_plot_results.py index 8be8aec..3f3e2bf 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -1,11 +1,11 @@ #!/usr/bin/python3 -"""Generates a figure that shows all benchmarking results +"""Generates some figures (plots) that shows all benchmarking results """ import sys import os import json -import matplotlib.pyplot as plotlib +import matplotlib.pyplot as plt filled_markers = ('o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', 'P', 'X') colours = ('r', 'g', 'b', 'black', 'yellow', 'purple') @@ -13,6 +13,7 @@ def plot_graphs(outfilename, benchmark_dict): """Plots the given dictionary of benchmark results """ + # print("outfilename = {}".format(outfilename)) # print("benchmark_dict = {}".format(benchmark_dict)) # any one of the data sets--just to grab some subtitle data that is common to all the data sets @@ -20,15 +21,28 @@ def plot_graphs(outfilename, benchmark_dict): data_dict = benchmark_dict[a_key][0] # print("data_dict = {}".format(data_dict)) - plotlib.clf() + # Begin plot + + plt.figure() + plt.clf() # main figure title - plotlib.suptitle("Malloc speed tests (tested w/glibc's `benchtests/bench-malloc-thread.c`)") + plt.suptitle("Malloc speed tests (tested w/glibc's `benchtests/bench-malloc-thread.c`)") + + rows = 2 + cols = 1 + + # Subplot 1 + + plt.subplot(rows, cols, 1) + # figure subtitle - plotlib.title("num bytes per malloc: min = {}; max = {}".format(data_dict["min_size"], - data_dict["max_size"]), fontsize=10) - plotlib.xlabel('Number of threads') + plt.title("num bytes per malloc: min = {}; max = {}".format(data_dict["min_size"], + data_dict["max_size"]), fontsize=10, pad=30) # more `pad` shifts the subtitle UP more + + plt.grid(alpha=.5) # alpha=0 is fully transparent; 1 is fully opaque + plt.xlabel('Number of threads') # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles - plotlib.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') + plt.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') nmarker=0 max_x=[] @@ -41,8 +55,8 @@ def plot_graphs(outfilename, benchmark_dict): X = [x["threads"] for x in data_list_of_dicts] Y = [y["time_per_iteration"] for y in data_list_of_dicts] - lines = plotlib.plot(X, Y, '-' + filled_markers[nmarker], label=impl_name) - plotlib.setp(lines, 'color', colours[nmarker]) + lines = plt.plot(X, Y, '-' + filled_markers[nmarker], label=impl_name) + plt.setp(lines, 'color', colours[nmarker]) # remember max X/Y # In case you only ran some of the tests, don't attempt to get `max()` on an empty list--ie: @@ -54,9 +68,50 @@ def plot_graphs(outfilename, benchmark_dict): nmarker=nmarker+1 - # set some graph global props: - plotlib.xlim(0, max(max_x)*1.1) - plotlib.ylim(0, max(max_y)*1.3) + # set some graph global properties: + plt.xlim(0, max(max_x)*1.1) + plt.ylim(0, max(max_y)*1.3) + plt.legend(loc='upper left') + + # Subplot 2 + + plt.subplot(rows, cols, 2) + + plt.grid(alpha=.5) + plt.xlabel('Number of threads') + # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles + plt.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') + + nmarker=0 + max_x=[] + max_y=[] + for impl_name in benchmark_dict.keys(): + data_list_of_dicts = benchmark_dict[impl_name] + # print("data_list_of_dicts = {}".format(data_list_of_dicts)) + + # add a line plot + X = [x["threads"] for x in data_list_of_dicts] + Y = [y["time_per_iteration"] for y in data_list_of_dicts] + + lines = plt.plot(X, Y, '-' + filled_markers[nmarker], label=impl_name) + plt.setp(lines, 'color', colours[nmarker]) + + # remember max X/Y + # In case you only ran some of the tests, don't attempt to get `max()` on an empty list--ie: + # for a benchmark you didn't run. Only operate if the lists aren't empty. + if X: + max_x.append(max(X)) + if Y: + max_y.append(max(Y)) + + nmarker=nmarker+1 + + # set some graph global properties: + plt.xlim(0, max(max_x)*1.1) + plt.ylim(0, max(max_y)*1.3) + plt.legend(loc='upper left') + + # Save and show plots outfilename_dir = os.path.dirname(outfilename) print("Writing plot into '%s'" % outfilename) @@ -64,9 +119,10 @@ def plot_graphs(outfilename, benchmark_dict): "Close the plot to terminate the program. Run `RESULT_DIRNAME='{}' make plot_results`\n" + "to plot the results again.\n" + "- - -").format(outfilename_dir)) - plotlib.legend(loc='upper left') - plotlib.savefig(outfilename) - plotlib.show() + figure = plt.gcf() # get current figure + figure.set_size_inches(8, 8) + plt.savefig(outfilename) + plt.show() def main(args): From ce35a51b8576bc0e73b541f0431804e1618aedc1 Mon Sep 17 00:00:00 2001 From: Gabriel Staples Date: Mon, 28 Jun 2021 14:06:06 -0700 Subject: [PATCH 16/16] bench_plot_results.py: finish adding RAM usage plot! Max Resident Set Size (RSS) RAM usage (in MB) --- README.md | 3 +++ bench_plot_results.py | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d1bf43d..f9d3242 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ They will: of malloc implementations and numbers of threads 1. Use [Python matplotlib](https://matplotlib.org/) to produce a plot of the results +**Other high-quality malloc benchmark tools:** +1. https://github.com/daanx/mimalloc-bench + ## Dependencies diff --git a/bench_plot_results.py b/bench_plot_results.py index 3f3e2bf..aed78e6 100755 --- a/bench_plot_results.py +++ b/bench_plot_results.py @@ -21,7 +21,9 @@ def plot_graphs(outfilename, benchmark_dict): data_dict = benchmark_dict[a_key][0] # print("data_dict = {}".format(data_dict)) + # ------------------------- # Begin plot + # ------------------------- plt.figure() plt.clf() @@ -31,7 +33,9 @@ def plot_graphs(outfilename, benchmark_dict): rows = 2 cols = 1 + # ------------------------- # Subplot 1 + # ------------------------- plt.subplot(rows, cols, 1) @@ -73,32 +77,31 @@ def plot_graphs(outfilename, benchmark_dict): plt.ylim(0, max(max_y)*1.3) plt.legend(loc='upper left') + # ------------------------- # Subplot 2 + # ------------------------- plt.subplot(rows, cols, 2) plt.grid(alpha=.5) plt.xlabel('Number of threads') - # bench-malloc-thread uses RDTSC counter for reporting time => CPU clock cycles - plt.ylabel('CPU cycles per sum of (1 free + 1 malloc) op') + plt.ylabel('Max Resident Set Size (RSS) RAM usage (in MB)') nmarker=0 max_x=[] max_y=[] for impl_name in benchmark_dict.keys(): data_list_of_dicts = benchmark_dict[impl_name] - # print("data_list_of_dicts = {}".format(data_list_of_dicts)) # add a line plot X = [x["threads"] for x in data_list_of_dicts] - Y = [y["time_per_iteration"] for y in data_list_of_dicts] + # rss default units are in kB, so convert to MB + Y = [y["max_rss"]/1000 for y in data_list_of_dicts] lines = plt.plot(X, Y, '-' + filled_markers[nmarker], label=impl_name) plt.setp(lines, 'color', colours[nmarker]) # remember max X/Y - # In case you only ran some of the tests, don't attempt to get `max()` on an empty list--ie: - # for a benchmark you didn't run. Only operate if the lists aren't empty. if X: max_x.append(max(X)) if Y: @@ -111,7 +114,9 @@ def plot_graphs(outfilename, benchmark_dict): plt.ylim(0, max(max_y)*1.3) plt.legend(loc='upper left') + # ------------------------- # Save and show plots + # ------------------------- outfilename_dir = os.path.dirname(outfilename) print("Writing plot into '%s'" % outfilename) @@ -120,8 +125,9 @@ def plot_graphs(outfilename, benchmark_dict): "to plot the results again.\n" + "- - -").format(outfilename_dir)) figure = plt.gcf() # get current figure - figure.set_size_inches(8, 8) - plt.savefig(outfilename) + figure.set_size_inches(9, 9) + plt.savefig(outfilename, dpi=200) + print("Done.") plt.show()