summaryrefslogtreecommitdiff
path: root/benchmarks/stdio_benchmark.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2017-08-23 09:52:50 -0700
committerElliott Hughes <enh@google.com>2017-08-23 14:03:43 -0700
commit938bece9e0c5d7d67d137dbfbba1e2d244c95b35 (patch)
treecb655541a4b96f3af5c854a80793af05833235b5 /benchmarks/stdio_benchmark.cpp
parent57e07a150e536f79d78f8203b0c807087b5c854b (diff)
Benchmark fgetln(3) and getline(3) as well as fgets(3).
On Pixel 2016, there's about 1us overhead for getline versus fgets. fgetln(3) is worse still because of the intermediate buffering (though it might actually be better if you were only reading one line whose length was less than BUFSIZ). Also use somewhat realistic input for these benchmarks: /dev/zero makes no sense at all. Bug: N/A Test: ran benchmarks Change-Id: I4a319825a37ac3849014c4c6b31523c1e200c641
Diffstat (limited to 'benchmarks/stdio_benchmark.cpp')
-rw-r--r--benchmarks/stdio_benchmark.cpp71
1 files changed, 66 insertions, 5 deletions
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 3f5e0f138..0e7f668f3 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -19,9 +19,20 @@
#include <stdio_ext.h>
#include <stdlib.h>
+#include <android-base/test_utils.h>
#include <benchmark/benchmark.h>
#include "util.h"
+static void FillFile(TemporaryFile& tf) {
+ char line[256];
+ memset(line, 'x', sizeof(line));
+ line[sizeof(line) - 1] = '\0';
+
+ FILE* fp = fopen(tf.path, "w");
+ for (size_t i = 0; i < 4096; ++i) fputs(line, fp);
+ fclose(fp);
+}
+
template <typename Fn>
void ReadWriteTest(benchmark::State& state, Fn f, bool buffered) {
size_t chunk_size = state.range(0);
@@ -65,14 +76,39 @@ void BM_stdio_fwrite_unbuffered(benchmark::State& state) {
}
BIONIC_BENCHMARK(BM_stdio_fwrite_unbuffered);
+#if !defined(__GLIBC__)
+static void FopenFgetlnFclose(benchmark::State& state, bool no_locking) {
+ TemporaryFile tf;
+ FillFile(tf);
+ while (state.KeepRunning()) {
+ FILE* fp = fopen(tf.path, "re");
+ if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
+ size_t length;
+ while (fgetln(fp, &length) != nullptr) {
+ }
+ fclose(fp);
+ }
+}
+
+static void BM_stdio_fopen_fgetln_fclose_locking(benchmark::State& state) {
+ FopenFgetlnFclose(state, false);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_locking);
+
+void BM_stdio_fopen_fgetln_fclose_no_locking(benchmark::State& state) {
+ FopenFgetlnFclose(state, true);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_fgetln_fclose_no_locking);
+#endif
+
static void FopenFgetsFclose(benchmark::State& state, bool no_locking) {
- size_t nbytes = state.range(0);
- char buf[nbytes];
+ TemporaryFile tf;
+ FillFile(tf);
+ char buf[BUFSIZ];
while (state.KeepRunning()) {
- FILE* fp = fopen("/dev/zero", "re");
+ FILE* fp = fopen(tf.path, "re");
if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
- if (fgets(buf, sizeof(buf), fp) == nullptr) {
- errx(1, "ERROR: fgets of %zu bytes failed.", nbytes);
+ while (fgets(buf, sizeof(buf), fp) != nullptr) {
}
fclose(fp);
}
@@ -88,6 +124,31 @@ void BM_stdio_fopen_fgets_fclose_no_locking(benchmark::State& state) {
}
BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking);
+static void FopenGetlineFclose(benchmark::State& state, bool no_locking) {
+ TemporaryFile tf;
+ FillFile(tf);
+ while (state.KeepRunning()) {
+ FILE* fp = fopen(tf.path, "re");
+ if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
+ char* line = nullptr;
+ size_t n = 0;
+ while (getline(&line, &n, fp) != -1) {
+ }
+ free(line);
+ fclose(fp);
+ }
+}
+
+static void BM_stdio_fopen_getline_fclose_locking(benchmark::State& state) {
+ FopenGetlineFclose(state, false);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_locking);
+
+void BM_stdio_fopen_getline_fclose_no_locking(benchmark::State& state) {
+ FopenGetlineFclose(state, true);
+}
+BIONIC_BENCHMARK(BM_stdio_fopen_getline_fclose_no_locking);
+
static void FopenFgetcFclose(benchmark::State& state, bool no_locking) {
size_t nbytes = state.range(0);
while (state.KeepRunning()) {