Splitting up 27_io/basic_istream/ignore/wchar_t/94749.cc (takes too long)

Jonathan Wakely jwakely@redhat.com
Fri Jun 9 20:40:15 GMT 2023


On Fri, 9 Jun 2023 at 17:20, Hans-Peter Nilsson <hp@axis.com> wrote:

> Hi!
>
> The test 27_io/basic_istream/ignore/wchar_t/94749.cc takes
> about 10 minutes to run for cris-elf in the "gdb simulator"
> here on my arguably way-past-retirement machine (and it
> looks like it gained a minute with LRA).  I've seen it
> timing out every now and then on busy days with load >
> `nproc`.  Usually it happens some time after I've forgot
> about why. :)
>
> It has had some performance surgery before (pruning for
> simulators, doubling timeout for ilp32).  I'd probably just
> try cutting along the function boundaries and keep those
> parts separate that have >1 min execution time.
>

test01, test02, test03 and test04 should run almost instantly. On my system
they take about 5 microseconds each. So I don't think splitting those up
will help.

test05 extracts INT_MAX characters from a stream, which is a LOT of work.
It doesn't actually read those from a file, the "stream" is a custom
streambuf that contains a buffer of millions of wchar_t and "reading" from
the stream just increments a counter into that buffer. But we do have to
allocate memory for that buffer and then zero-init that buffer. That's a
lot of cycles. Then once we've done that, we need to keep looping until we
overflow a 32-bit counter (we don't increment by 1 every loop, so it
overflows pretty quickly).

Then we do it again and again and again! Each time takes about half a
second for me.

I thought it would help to avoid re-allocating the buffer and zeroing it
again. If we reuse the same buffer, then we just have to loop until we
overflow the 32-bit counter. That would make the whole test run much
faster, which would reduce the total time for a testsuite run. Splitting
the file up into smaller files would not decrease the total time, only
decrease the time for that single test so it doesn't time out.

I've attached a patch that does that. I makes very little difference for
me, probably because allocating zero-filled pages isn't actually expensive
on linux. Maybe it will make a differene for your simulator though?

You could also try reducing the size of the buffer:
+#ifdef SIMULATOR_TEST
+  static const streamsize bufsz = 16 << limits::digits10;
+#else
  static const streamsize bufsz = 2048 << limits::digits10;
+#endif

test06 is the really slow part, that takes 10+ seconds for me. But that
entire function should already be skipped for simulators.

We can probably skip test05 for simulators too, none of the code it tests
is platform-specific, so as long as it's being tested on x86 we don't
really need to test it on cris-elf too.
-------------- next part --------------
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/ignore/wchar_t/94749.cc b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/wchar_t/94749.cc
index 65e0a326c10..040e94aa4d6 100644
--- a/libstdc++-v3/testsuite/27_io/basic_istream/ignore/wchar_t/94749.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/ignore/wchar_t/94749.cc
@@ -89,7 +89,7 @@ struct buff : std::basic_streambuf<typename T::char_type, T>
   typedef std::streamsize		  streamsize;
   typedef std::numeric_limits<streamsize> limits;
 
-  buff() : count(0), buf() { }
+  buff() : count(0), nonzero_chars(), buf() { }
 
   int_type underflow()
   {
@@ -112,12 +112,23 @@ struct buff : std::basic_streambuf<typename T::char_type, T>
       buf[headroom+1] = L'3';
       this->setg(buf, buf, buf + headroom + 2);
       count = limits::max();
+      nonzero_chars = headroom - 1;
     }
 
     return buf[0];
   }
 
+  void reset()
+  {
+    buf[nonzero_chars] = char_type();
+    buf[nonzero_chars+1] = char_type();
+    buf[nonzero_chars+2] = char_type();
+    nonzero_chars = 0;
+    count = 0;
+  }
+
   streamsize count;
+  streamsize nonzero_chars;
 
   static const streamsize bufsz = 2048 << limits::digits10;
   char_type buf[bufsz + 2];
@@ -132,7 +143,8 @@ test05()
 
   typedef std::char_traits<C> T;
 
-  std::basic_istream<C, T> in(new buff<T>);
+  buff<T>* pbuf = new buff<T>;
+  std::basic_istream<C, T> in(pbuf);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'1');
   VERIFY(in.good());
@@ -141,7 +153,9 @@ test05()
   VERIFY(in.get() == L'3');
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'2');
   VERIFY(in.good());
@@ -150,7 +164,9 @@ test05()
   VERIFY(in.get() == L'3');
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'3');
   VERIFY(in.good());
@@ -158,7 +174,9 @@ test05()
   VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'4');
   VERIFY(in.eof());
@@ -166,7 +184,8 @@ test05()
   VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(0);
+  in.rdbuf(0);
+  delete pbuf;
 }
 
 void
@@ -177,7 +196,8 @@ test06()
 
   typedef __gnu_cxx::char_traits<C> T;
 
-  std::basic_istream<C, T> in(new buff<T>);
+  buff<T>* pbuf = new buff<T>;
+  std::basic_istream<C, T> in(pbuf);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'1');
   VERIFY(in.good());
@@ -186,7 +206,9 @@ test06()
   VERIFY(in.get() == L'3');
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'2');
   VERIFY(in.good());
@@ -195,7 +217,9 @@ test06()
   VERIFY(in.get() == L'3');
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'3');
   VERIFY(in.good());
@@ -203,7 +227,9 @@ test06()
   VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(new buff<T>);
+  pbuf->reset();
+  in.clear();
+  VERIFY(in.gcount() == 0);
 
   in.ignore(std::numeric_limits<std::streamsize>::max(), L'4');
   VERIFY(in.eof());
@@ -211,7 +237,8 @@ test06()
   VERIFY(in.gcount() == std::numeric_limits<std::streamsize>::max());
   VERIFY(in.get() == T::eof());
 
-  delete in.rdbuf(0);
+  in.rdbuf(0);
+  delete pbuf;
 }
 
 int


More information about the Libstdc++ mailing list