| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2014 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
| Anders Lewis | a98a5fb | 2017-08-09 16:52:19 -0700 | [diff] [blame] | 17 | #include <err.h> | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 18 | #include <stdio.h> | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 19 | #include <stdio_ext.h> | 
| Elliott Hughes | c217373 | 2015-05-13 13:18:04 -0700 | [diff] [blame] | 20 | #include <stdlib.h> | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 21 |  | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 22 | #include <android-base/test_utils.h> | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 23 | #include <benchmark/benchmark.h> | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 24 | #include "util.h" | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 25 |  | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 26 | static void FillFile(TemporaryFile& tf) { | 
|  | 27 | char line[256]; | 
|  | 28 | memset(line, 'x', sizeof(line)); | 
|  | 29 | line[sizeof(line) - 1] = '\0'; | 
|  | 30 |  | 
|  | 31 | FILE* fp = fopen(tf.path, "w"); | 
|  | 32 | for (size_t i = 0; i < 4096; ++i) fputs(line, fp); | 
|  | 33 | fclose(fp); | 
|  | 34 | } | 
|  | 35 |  | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 36 | template <typename Fn> | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 37 | void ReadWriteTest(benchmark::State& state, Fn f, bool buffered) { | 
| Martijn Coenen | be763d8 | 2016-11-14 14:16:08 +0100 | [diff] [blame] | 38 | size_t chunk_size = state.range(0); | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 39 |  | 
| Elliott Hughes | d706fe5 | 2017-08-22 15:26:07 -0700 | [diff] [blame] | 40 | FILE* fp = fopen("/dev/zero", "r+e"); | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 41 | __fsetlocking(fp, FSETLOCKING_BYCALLER); | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 42 | char* buf = new char[chunk_size]; | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 43 |  | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 44 | if (!buffered) { | 
|  | 45 | setvbuf(fp, 0, _IONBF, 0); | 
|  | 46 | } | 
|  | 47 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 48 | while (state.KeepRunning()) { | 
| Elliott Hughes | d706fe5 | 2017-08-22 15:26:07 -0700 | [diff] [blame] | 49 | if (f(buf, chunk_size, 1, fp) != 1) { | 
|  | 50 | errx(1, "ERROR: op of %zu bytes failed.", chunk_size); | 
|  | 51 | } | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 52 | } | 
|  | 53 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 54 | state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(chunk_size)); | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 55 | delete[] buf; | 
|  | 56 | fclose(fp); | 
|  | 57 | } | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 58 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 59 | void BM_stdio_fread(benchmark::State& state) { | 
|  | 60 | ReadWriteTest(state, fread, true); | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 61 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 62 | BIONIC_BENCHMARK(BM_stdio_fread); | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 63 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 64 | void BM_stdio_fwrite(benchmark::State& state) { | 
|  | 65 | ReadWriteTest(state, fwrite, true); | 
| Elliott Hughes | b28e490 | 2014-03-11 11:19:06 -0700 | [diff] [blame] | 66 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 67 | BIONIC_BENCHMARK(BM_stdio_fwrite); | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 68 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 69 | void BM_stdio_fread_unbuffered(benchmark::State& state) { | 
|  | 70 | ReadWriteTest(state, fread, false); | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 71 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 72 | BIONIC_BENCHMARK(BM_stdio_fread_unbuffered); | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 73 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 74 | void BM_stdio_fwrite_unbuffered(benchmark::State& state) { | 
|  | 75 | ReadWriteTest(state, fwrite, false); | 
| Elliott Hughes | 47dc7c9 | 2014-12-01 13:12:18 -0800 | [diff] [blame] | 76 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 77 | BIONIC_BENCHMARK(BM_stdio_fwrite_unbuffered); | 
| Elliott Hughes | 1cf32f8 | 2015-01-16 17:08:31 -0800 | [diff] [blame] | 78 |  | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 79 | #if !defined(__GLIBC__) | 
|  | 80 | static void FopenFgetlnFclose(benchmark::State& state, bool no_locking) { | 
|  | 81 | TemporaryFile tf; | 
|  | 82 | FillFile(tf); | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 83 | while (state.KeepRunning()) { | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 84 | FILE* fp = fopen(tf.path, "re"); | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 85 | if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER); | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 86 | size_t length; | 
|  | 87 | while (fgetln(fp, &length) != nullptr) { | 
|  | 88 | } | 
|  | 89 | fclose(fp); | 
|  | 90 | } | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | static void BM_stdio_fopen_fgetln_fclose_locking(benchmark::State& state) { | 
|  | 94 | FopenFgetlnFclose(state, false); | 
|  | 95 | } | 
|  | 96 | BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_locking); | 
|  | 97 |  | 
|  | 98 | void BM_stdio_fopen_fgetln_fclose_no_locking(benchmark::State& state) { | 
|  | 99 | FopenFgetlnFclose(state, true); | 
|  | 100 | } | 
|  | 101 | BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_no_locking); | 
|  | 102 | #endif | 
|  | 103 |  | 
|  | 104 | static void FopenFgetsFclose(benchmark::State& state, bool no_locking) { | 
|  | 105 | TemporaryFile tf; | 
|  | 106 | FillFile(tf); | 
|  | 107 | char buf[BUFSIZ]; | 
|  | 108 | while (state.KeepRunning()) { | 
|  | 109 | FILE* fp = fopen(tf.path, "re"); | 
|  | 110 | if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER); | 
|  | 111 | while (fgets(buf, sizeof(buf), fp) != nullptr) { | 
| Anders Lewis | a98a5fb | 2017-08-09 16:52:19 -0700 | [diff] [blame] | 112 | } | 
| Elliott Hughes | 1cf32f8 | 2015-01-16 17:08:31 -0800 | [diff] [blame] | 113 | fclose(fp); | 
|  | 114 | } | 
|  | 115 | } | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 116 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 117 | static void BM_stdio_fopen_fgets_fclose_locking(benchmark::State& state) { | 
|  | 118 | FopenFgetsFclose(state, false); | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 119 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 120 | BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_locking); | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 121 |  | 
| Elliott Hughes | 281e06b | 2016-02-17 10:23:52 -0800 | [diff] [blame] | 122 | void BM_stdio_fopen_fgets_fclose_no_locking(benchmark::State& state) { | 
|  | 123 | FopenFgetsFclose(state, true); | 
| Elliott Hughes | 8c4994b | 2015-01-20 18:09:05 -0800 | [diff] [blame] | 124 | } | 
| Anders Lewis | a7b0f88 | 2017-07-24 20:01:13 -0700 | [diff] [blame] | 125 | BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking); | 
| Anders Lewis | ac4f4b4 | 2017-08-08 18:29:51 -0700 | [diff] [blame] | 126 |  | 
| Elliott Hughes | 938bece | 2017-08-23 09:52:50 -0700 | [diff] [blame] | 127 | static void FopenGetlineFclose(benchmark::State& state, bool no_locking) { | 
|  | 128 | TemporaryFile tf; | 
|  | 129 | FillFile(tf); | 
|  | 130 | while (state.KeepRunning()) { | 
|  | 131 | FILE* fp = fopen(tf.path, "re"); | 
|  | 132 | if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER); | 
|  | 133 | char* line = nullptr; | 
|  | 134 | size_t n = 0; | 
|  | 135 | while (getline(&line, &n, fp) != -1) { | 
|  | 136 | } | 
|  | 137 | free(line); | 
|  | 138 | fclose(fp); | 
|  | 139 | } | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | static void BM_stdio_fopen_getline_fclose_locking(benchmark::State& state) { | 
|  | 143 | FopenGetlineFclose(state, false); | 
|  | 144 | } | 
|  | 145 | BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_locking); | 
|  | 146 |  | 
|  | 147 | void BM_stdio_fopen_getline_fclose_no_locking(benchmark::State& state) { | 
|  | 148 | FopenGetlineFclose(state, true); | 
|  | 149 | } | 
|  | 150 | BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_no_locking); | 
|  | 151 |  | 
| Anders Lewis | ac4f4b4 | 2017-08-08 18:29:51 -0700 | [diff] [blame] | 152 | static void FopenFgetcFclose(benchmark::State& state, bool no_locking) { | 
|  | 153 | size_t nbytes = state.range(0); | 
|  | 154 | while (state.KeepRunning()) { | 
|  | 155 | FILE* fp = fopen("/dev/zero", "re"); | 
|  | 156 | if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER); | 
|  | 157 | volatile int c __attribute__((unused)); | 
|  | 158 | for (size_t i = 0; i < nbytes; ++i) { | 
|  | 159 | c = fgetc(fp); | 
|  | 160 | } | 
|  | 161 | fclose(fp); | 
|  | 162 | } | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | static void BM_stdio_fopen_fgetc_fclose_locking(benchmark::State& state) { | 
|  | 166 | FopenFgetcFclose(state, false); | 
|  | 167 | } | 
|  | 168 | BIONIC_BENCHMARK(BM_stdio_fopen_fgetc_fclose_locking); | 
|  | 169 |  | 
|  | 170 | void BM_stdio_fopen_fgetc_fclose_no_locking(benchmark::State& state) { | 
|  | 171 | FopenFgetcFclose(state, true); | 
|  | 172 | } | 
|  | 173 | BIONIC_BENCHMARK(BM_stdio_fopen_fgetc_fclose_no_locking); | 
| Elliott Hughes | 9280599 | 2017-10-26 15:41:49 -0700 | [diff] [blame] | 174 |  | 
|  | 175 | static void BM_stdio_printf_literal(benchmark::State& state) { | 
|  | 176 | while (state.KeepRunning()) { | 
|  | 177 | char buf[BUFSIZ]; | 
|  | 178 | snprintf(buf, sizeof(buf), "this is just a literal string with no format specifiers"); | 
|  | 179 | } | 
|  | 180 | } | 
|  | 181 | BIONIC_BENCHMARK(BM_stdio_printf_literal); | 
|  | 182 |  | 
|  | 183 | static void BM_stdio_printf_s(benchmark::State& state) { | 
|  | 184 | while (state.KeepRunning()) { | 
|  | 185 | char buf[BUFSIZ]; | 
|  | 186 | snprintf(buf, sizeof(buf), "this is a more typical error message with detail: %s", | 
|  | 187 | "No such file or directory"); | 
|  | 188 | } | 
|  | 189 | } | 
|  | 190 | BIONIC_BENCHMARK(BM_stdio_printf_s); | 
|  | 191 |  | 
|  | 192 | static void BM_stdio_printf_d(benchmark::State& state) { | 
|  | 193 | while (state.KeepRunning()) { | 
|  | 194 | char buf[BUFSIZ]; | 
|  | 195 | snprintf(buf, sizeof(buf), "this is a more typical error message with detail: %d", 123456); | 
|  | 196 | } | 
|  | 197 | } | 
|  | 198 | BIONIC_BENCHMARK(BM_stdio_printf_d); | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 199 |  | 
|  | 200 | static void BM_stdio_printf_1$s(benchmark::State& state) { | 
|  | 201 | while (state.KeepRunning()) { | 
|  | 202 | char buf[BUFSIZ]; | 
|  | 203 | snprintf(buf, sizeof(buf), "this is a more typical error message with detail: %1$s", | 
|  | 204 | "No such file or directory"); | 
|  | 205 | } | 
|  | 206 | } | 
|  | 207 | BIONIC_BENCHMARK(BM_stdio_printf_1$s); |