[lldb] Find the end of a gdb-remote packet in linear time (#238530)
GDBRemoteCommunication::CheckForPacket appends each read, at most 8 KiB,
to m_bytes and then searches all of m_bytes for the '#' that ends the
first packet. A packet of S bytes is searched about S / 8 KiB times, so
receiving it takes time quadratic in S. With "process plugin packet
speed-test", a 32 MiB reply took 1.7 s, a 64 MiB reply 8.5 s and a 128
MiB reply 38.6 s. jThreadsInfo replies reach these sizes when a process
has tens of thousands of threads, as a GPU process can.
Resume the search where the previous call stopped. A packet cannot
contain an unescaped '#', so bytes already searched never need searching
again. Only the two paths that wait for more bytes record the position,
and neither changes m_bytes; every other path, including all of those
that remove bytes, leaves it at zero. DecompressPacket can rewrite
m_bytes before the search, so compressed connections still search from
the start. The 128 MiB reply now takes 0.73 s.
Searching only the bytes that the current call appends would not be
enough: a '#' can arrive in one read and its checksum in the next, and a
read can deliver more than one packet, leaving a complete packet in
m_bytes for a later call that appends nothing.
The new unit test splits a packet across two reads at every position,
and checks that a packet that arrives in the same read as the end of a
longer one is found without another read.
AI Usage note: AI was used to assist with this PR.