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
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 3f5e0f1..0e7f668 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 @@
 }
 BIONIC_BENCHMARK(BM_stdio_fwrite_unbuffered);
 
-static void FopenFgetsFclose(benchmark::State& state, bool no_locking) {
-  size_t nbytes = state.range(0);
-  char buf[nbytes];
+#if !defined(__GLIBC__)
+static void FopenFgetlnFclose(benchmark::State& state, bool no_locking) {
+  TemporaryFile tf;
+  FillFile(tf);
   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);
+    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) {
+  TemporaryFile tf;
+  FillFile(tf);
+  char buf[BUFSIZ];
+  while (state.KeepRunning()) {
+    FILE* fp = fopen(tf.path, "re");
+    if (no_locking) __fsetlocking(fp, FSETLOCKING_BYCALLER);
+    while (fgets(buf, sizeof(buf), fp) != nullptr) {
     }
     fclose(fp);
   }
@@ -88,6 +124,31 @@
 }
 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()) {