benchtests: Fix validate_benchout.py exceptions
[platform/upstream/glibc.git] / benchtests / bench-malloc-simple.c
1 /* Benchmark malloc and free functions.
2    Copyright (C) 2019-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <malloc.h>
23 #include <sys/resource.h>
24 #include "bench-timing.h"
25 #include "json-lib.h"
26
27 /* Benchmark the malloc/free performance of a varying number of blocks of a
28    given size.  This enables performance tracking of the t-cache and fastbins.
29    It tests 3 different scenarios: single-threaded using main arena,
30    multi-threaded using thread-arena, and main arena with SINGLE_THREAD_P
31    false.  */
32
33 #define NUM_ITERS 200000
34 #define NUM_ALLOCS 4
35 #define MAX_ALLOCS 1600
36
37 typedef struct
38 {
39   size_t iters;
40   size_t size;
41   int n;
42   timing_t elapsed;
43 } malloc_args;
44
45 static void
46 do_benchmark (malloc_args *args, int **arr)
47 {
48   timing_t start, stop;
49   size_t iters = args->iters;
50   size_t size = args->size;
51   int n = args->n;
52
53   TIMING_NOW (start);
54
55   for (int j = 0; j < iters; j++)
56     {
57       for (int i = 0; i < n; i++)
58         arr[i] = malloc (size);
59
60       for (int i = 0; i < n; i++)
61         free (arr[i]);
62     }
63
64   TIMING_NOW (stop);
65
66   TIMING_DIFF (args->elapsed, start, stop);
67 }
68
69 static malloc_args tests[3][NUM_ALLOCS];
70 static int allocs[NUM_ALLOCS] = { 25, 100, 400, MAX_ALLOCS };
71
72 static void *
73 thread_test (void *p)
74 {
75   int **arr = (int**)p;
76
77   /* Run benchmark multi-threaded.  */
78   for (int i = 0; i < NUM_ALLOCS; i++)
79     do_benchmark (&tests[2][i], arr);
80
81   return p;
82 }
83
84 void
85 bench (unsigned long size)
86 {
87   size_t iters = NUM_ITERS;
88   int **arr = (int**) malloc (MAX_ALLOCS * sizeof (void*));
89
90   for (int t = 0; t < 3; t++)
91     for (int i = 0; i < NUM_ALLOCS; i++)
92       {
93         tests[t][i].n = allocs[i];
94         tests[t][i].size = size;
95         tests[t][i].iters = iters / allocs[i];
96
97         /* Do a quick warmup run.  */
98         if (t == 0)
99           do_benchmark (&tests[0][i], arr);
100       }
101
102   /* Run benchmark single threaded in main_arena.  */
103   for (int i = 0; i < NUM_ALLOCS; i++)
104     do_benchmark (&tests[0][i], arr);
105
106   /* Run benchmark in a thread_arena.  */
107   pthread_t t;
108   pthread_create (&t, NULL, thread_test, (void*)arr);
109   pthread_join (t, NULL);
110
111   /* Repeat benchmark in main_arena with SINGLE_THREAD_P == false.  */
112   for (int i = 0; i < NUM_ALLOCS; i++)
113     do_benchmark (&tests[1][i], arr);
114
115   free (arr);
116
117   json_ctx_t json_ctx;
118
119   json_init (&json_ctx, 0, stdout);
120
121   json_document_begin (&json_ctx);
122
123   json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
124
125   json_attr_object_begin (&json_ctx, "functions");
126
127   json_attr_object_begin (&json_ctx, "malloc");
128
129   char s[100];
130   double iters2 = iters;
131
132   json_attr_object_begin (&json_ctx, "");
133   json_attr_double (&json_ctx, "malloc_block_size", size);
134
135   struct rusage usage;
136   getrusage (RUSAGE_SELF, &usage);
137   json_attr_double (&json_ctx, "max_rss", usage.ru_maxrss);
138
139   for (int i = 0; i < NUM_ALLOCS; i++)
140     {
141       sprintf (s, "main_arena_st_allocs_%04d_time", allocs[i]);
142       json_attr_double (&json_ctx, s, tests[0][i].elapsed / iters2);
143     }
144
145   for (int i = 0; i < NUM_ALLOCS; i++)
146     {
147       sprintf (s, "main_arena_mt_allocs_%04d_time", allocs[i]);
148       json_attr_double (&json_ctx, s, tests[1][i].elapsed / iters2);
149     }
150
151   for (int i = 0; i < NUM_ALLOCS; i++)
152     {
153       sprintf (s, "thread_arena__allocs_%04d_time", allocs[i]);
154       json_attr_double (&json_ctx, s, tests[2][i].elapsed / iters2);
155     }
156
157   json_attr_object_end (&json_ctx);
158
159   json_attr_object_end (&json_ctx);
160
161   json_attr_object_end (&json_ctx);
162
163   json_document_end (&json_ctx);
164 }
165
166 static void usage (const char *name)
167 {
168   fprintf (stderr, "%s: <alloc_size>\n", name);
169   exit (1);
170 }
171
172 int
173 main (int argc, char **argv)
174 {
175   long val = 16;
176   if (argc == 2)
177     val = strtol (argv[1], NULL, 0);
178
179   if (argc > 2 || val <= 0)
180     usage (argv[0]);
181
182   bench (val);
183
184   return 0;
185 }