1 | /* Measure memcpy performance. |
2 | Copyright (C) 2016-2022 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 | #define MIN_SIZE 32768 |
20 | #define MAX_SIZE (1024*1024) |
21 | #define NUM_TESTS 16384 |
22 | |
23 | #define MIN_PAGE_SIZE (MAX_SIZE + getpagesize()) |
24 | #define TEST_MAIN |
25 | #define TEST_NAME "memcpy" |
26 | #include "bench-string.h" |
27 | #include <assert.h> |
28 | #include "json-lib.h" |
29 | |
30 | IMPL (memcpy, 1) |
31 | |
32 | typedef struct { uint16_t size; uint16_t freq; } freq_data_t; |
33 | typedef struct { uint8_t align; uint16_t freq; } align_data_t; |
34 | |
35 | #define SIZE_NUM 65536 |
36 | #define SIZE_MASK (SIZE_NUM-1) |
37 | static uint8_t size_arr[SIZE_NUM]; |
38 | |
39 | /* Frequency data for memcpy of less than 4096 bytes based on SPEC2017. */ |
40 | static freq_data_t size_freq[] = |
41 | { |
42 | {32,22320}, { 16,9554}, { 8,8915}, {152,5327}, { 4,2159}, {292,2035}, |
43 | { 12,1608}, { 24,1343}, {1152,895}, {144, 813}, {884, 733}, {284, 721}, |
44 | {120, 661}, { 2, 649}, {882, 550}, { 5, 475}, { 7, 461}, {108, 460}, |
45 | { 10, 361}, { 9, 361}, { 6, 334}, { 3, 326}, {464, 308}, {2048,303}, |
46 | { 1, 298}, { 64, 250}, { 11, 197}, {296, 194}, { 68, 187}, { 15, 185}, |
47 | {192, 184}, {1764,183}, { 13, 173}, {560, 126}, {160, 115}, {288, 96}, |
48 | {104, 96}, {1144, 83}, { 18, 80}, { 23, 78}, { 40, 77}, { 19, 68}, |
49 | { 48, 63}, { 17, 57}, { 72, 54}, {1280, 51}, { 20, 49}, { 28, 47}, |
50 | { 22, 46}, {640, 45}, { 25, 41}, { 14, 40}, { 56, 37}, { 27, 35}, |
51 | { 35, 33}, {384, 33}, { 29, 32}, { 80, 30}, {4095, 22}, {232, 22}, |
52 | { 36, 19}, {184, 17}, { 21, 17}, {256, 16}, { 44, 15}, { 26, 15}, |
53 | { 31, 14}, { 88, 14}, {176, 13}, { 33, 12}, {1024, 12}, {208, 11}, |
54 | { 62, 11}, {128, 10}, {704, 10}, {324, 10}, { 96, 10}, { 60, 9}, |
55 | {136, 9}, {124, 9}, { 34, 8}, { 30, 8}, {480, 8}, {1344, 8}, |
56 | {273, 7}, {520, 7}, {112, 6}, { 52, 6}, {344, 6}, {336, 6}, |
57 | {504, 5}, {168, 5}, {424, 5}, { 0, 4}, { 76, 3}, {200, 3}, |
58 | {512, 3}, {312, 3}, {240, 3}, {960, 3}, {264, 2}, {672, 2}, |
59 | { 38, 2}, {328, 2}, { 84, 2}, { 39, 2}, {216, 2}, { 42, 2}, |
60 | { 37, 2}, {1608, 2}, { 70, 2}, { 46, 2}, {536, 2}, {280, 1}, |
61 | {248, 1}, { 47, 1}, {1088, 1}, {1288, 1}, {224, 1}, { 41, 1}, |
62 | { 50, 1}, { 49, 1}, {808, 1}, {360, 1}, {440, 1}, { 43, 1}, |
63 | { 45, 1}, { 78, 1}, {968, 1}, {392, 1}, { 54, 1}, { 53, 1}, |
64 | { 59, 1}, {376, 1}, {664, 1}, { 58, 1}, {272, 1}, { 66, 1}, |
65 | {2688, 1}, {472, 1}, {568, 1}, {720, 1}, { 51, 1}, { 63, 1}, |
66 | { 86, 1}, {496, 1}, {776, 1}, { 57, 1}, {680, 1}, {792, 1}, |
67 | {122, 1}, {760, 1}, {824, 1}, {552, 1}, { 67, 1}, {456, 1}, |
68 | {984, 1}, { 74, 1}, {408, 1}, { 75, 1}, { 92, 1}, {576, 1}, |
69 | {116, 1}, { 65, 1}, {117, 1}, { 82, 1}, {352, 1}, { 55, 1}, |
70 | {100, 1}, { 90, 1}, {696, 1}, {111, 1}, {880, 1}, { 79, 1}, |
71 | {488, 1}, { 61, 1}, {114, 1}, { 94, 1}, {1032, 1}, { 98, 1}, |
72 | { 87, 1}, {584, 1}, { 85, 1}, {648, 1}, {0, 0} |
73 | }; |
74 | |
75 | #define ALIGN_NUM 1024 |
76 | #define ALIGN_MASK (ALIGN_NUM-1) |
77 | static uint8_t src_align_arr[ALIGN_NUM]; |
78 | static uint8_t dst_align_arr[ALIGN_NUM]; |
79 | |
80 | /* Source alignment frequency for memcpy based on SPEC2017. */ |
81 | static align_data_t src_align_freq[] = |
82 | { |
83 | {8, 300}, {16, 292}, {32, 168}, {64, 153}, {4, 79}, {2, 14}, {1, 18}, {0, 0} |
84 | }; |
85 | |
86 | /* Destination alignment frequency for memcpy based on SPEC2017. */ |
87 | static align_data_t dst_align_freq[] = |
88 | { |
89 | {8, 265}, {16, 263}, {64, 209}, {32, 174}, {4, 90}, {2, 10}, {1, 13}, {0, 0} |
90 | }; |
91 | |
92 | typedef struct |
93 | { |
94 | uint64_t src : 24; |
95 | uint64_t dst : 24; |
96 | uint64_t len : 16; |
97 | } copy_t; |
98 | |
99 | static copy_t test_arr[NUM_TESTS]; |
100 | |
101 | typedef char *(*proto_t) (char *, const char *, size_t); |
102 | |
103 | static void |
104 | init_copy_distribution (void) |
105 | { |
106 | int i, j, freq, size, n; |
107 | |
108 | for (n = i = 0; (freq = size_freq[i].freq) != 0; i++) |
109 | for (j = 0, size = size_freq[i].size; j < freq; j++) |
110 | size_arr[n++] = size; |
111 | assert (n == SIZE_NUM); |
112 | |
113 | for (n = i = 0; (freq = src_align_freq[i].freq) != 0; i++) |
114 | for (j = 0, size = src_align_freq[i].align; j < freq; j++) |
115 | src_align_arr[n++] = size - 1; |
116 | assert (n == ALIGN_NUM); |
117 | |
118 | for (n = i = 0; (freq = dst_align_freq[i].freq) != 0; i++) |
119 | for (j = 0, size = dst_align_freq[i].align; j < freq; j++) |
120 | dst_align_arr[n++] = size - 1; |
121 | assert (n == ALIGN_NUM); |
122 | } |
123 | |
124 | |
125 | static void |
126 | do_one_test (json_ctx_t *json_ctx, impl_t *impl, char *dst, char *src, |
127 | copy_t *copy, size_t n) |
128 | { |
129 | timing_t start, stop, cur; |
130 | size_t iters = INNER_LOOP_ITERS_MEDIUM; |
131 | |
132 | for (int j = 0; j < n; j++) |
133 | CALL (impl, dst + copy[j].dst, src + copy[j].src, copy[j].len); |
134 | |
135 | TIMING_NOW (start); |
136 | for (int i = 0; i < iters; ++i) |
137 | for (int j = 0; j < n; j++) |
138 | CALL (impl, dst + copy[j].dst, src + copy[j].src, copy[j].len); |
139 | TIMING_NOW (stop); |
140 | |
141 | TIMING_DIFF (cur, start, stop); |
142 | |
143 | json_element_double (ctx: json_ctx, d: (double) cur / (double) iters); |
144 | } |
145 | |
146 | static void |
147 | do_test (json_ctx_t *json_ctx, size_t max_size) |
148 | { |
149 | int i; |
150 | |
151 | memset (buf1, 1, max_size); |
152 | |
153 | /* Create a random set of copies with the given size and alignment |
154 | distributions. */ |
155 | for (i = 0; i < NUM_TESTS; i++) |
156 | { |
157 | test_arr[i].dst = (rand () & (max_size - 1)); |
158 | test_arr[i].dst &= ~dst_align_arr[rand () & ALIGN_MASK]; |
159 | test_arr[i].src = (rand () & (max_size - 1)); |
160 | test_arr[i].src &= ~src_align_arr[rand () & ALIGN_MASK]; |
161 | test_arr[i].len = size_arr[rand () & SIZE_MASK]; |
162 | } |
163 | |
164 | json_element_object_begin (ctx: json_ctx); |
165 | json_attr_uint (ctx: json_ctx, name: "length" , d: (double) max_size); |
166 | json_array_begin (ctx: json_ctx, name: "timings" ); |
167 | |
168 | FOR_EACH_IMPL (impl, 0) |
169 | do_one_test (json_ctx, impl, dst: (char *) buf2, src: (char *) buf1, copy: test_arr, n: i); |
170 | |
171 | json_array_end (ctx: json_ctx); |
172 | json_element_object_end (ctx: json_ctx); |
173 | } |
174 | |
175 | int |
176 | test_main (void) |
177 | { |
178 | json_ctx_t json_ctx; |
179 | |
180 | test_init (); |
181 | init_copy_distribution (); |
182 | |
183 | json_init (ctx: &json_ctx, indent_level: 0, stdout); |
184 | |
185 | json_document_begin (ctx: &json_ctx); |
186 | json_attr_string (ctx: &json_ctx, name: "timing_type" , TIMING_TYPE); |
187 | |
188 | json_attr_object_begin (ctx: &json_ctx, name: "functions" ); |
189 | json_attr_object_begin (ctx: &json_ctx, TEST_NAME); |
190 | json_attr_string (ctx: &json_ctx, name: "bench-variant" , s: "random" ); |
191 | |
192 | json_array_begin (ctx: &json_ctx, name: "ifuncs" ); |
193 | FOR_EACH_IMPL (impl, 0) |
194 | json_element_string (ctx: &json_ctx, s: impl->name); |
195 | json_array_end (ctx: &json_ctx); |
196 | |
197 | json_array_begin (ctx: &json_ctx, name: "results" ); |
198 | for (int i = MIN_SIZE; i <= MAX_SIZE; i = i * 2) |
199 | do_test (json_ctx: &json_ctx, max_size: i); |
200 | |
201 | json_array_end (ctx: &json_ctx); |
202 | json_attr_object_end (ctx: &json_ctx); |
203 | json_attr_object_end (ctx: &json_ctx); |
204 | json_document_end (ctx: &json_ctx); |
205 | |
206 | return ret; |
207 | } |
208 | |
209 | #include <support/test-driver.c> |
210 | |