UnigramDev/Unigram/develop • 0ef54e8 • 4 files, +110/-27
Parse the receive path off TDLib's buffer, behind TdPointerParser
Client.Receive and Client.Execute hand td_receive's pointer straight to
ClientJson.FromPtr: no copy into a managed buffer, and no byte-at-a-time scan
for the terminator, which was 9-12% of the old parse and would have been a
fifth of this one. TdJsonReader needs no length when the buffer is
NUL-terminated - TdJsonReader.NulTerminated says so at the call site - which
is what deletes the scan without patching td_receive to return it.
Both are alternatives, not replacements: the Utf8JsonReader code is still
there in the #else, and one property drives both halves. TdPointerParser sets
the constant Client.cs reads and turns on the generator mode that emits the
parsers it calls, so false puts the whole thing back. FromJson_* is emitted
either way and still parses what the instant view editor hands back.
Not built - Telegram.csproj is not buildable here. Client.cs, ClientJson.cs,
PtrClientJson.cs and TdJsonReader.cs do compile both ways, checked by a
throwaway project outside the repo; ClientService and everything downstream of
Receive have only been read.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 0579837 • 5 files, +40/-6
Put the last three FromJson callers behind one string entry point
RichHtml and RichEditorCommands parse JSON that arrives as text from the
instant view editor, and each did its own Encoding.UTF8.GetBytes into a span.
ClientJson.FromJson(string) does it once, and follows TD_POINTER_PARSER like
everything else: it encodes one byte longer than the text and hands the
pointer reader its terminator, or falls back to the span overload.
These were the only callers of the Utf8JsonReader parsers left outside
Client.cs, so this is what has to happen before that set can be dropped from
the app altogether.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • e38afd9 • 8 files, +253/-9
Count what Client.Receive actually deserializes
The benchmark measures the parser over a fixed corpus in a loop, which says
how fast it can go and nothing about how much of it a session asks for.
TdThroughput counts updates, bytes and time inside the parse, and reports that
time as a share of wall clock - the number that decides whether the 2.4x is
worth anything outside a benchmark.
A runtime switch rather than [Conditional] like Instrumentation and Profiler,
because the interesting build is .NET Native Release, which is exactly the
configuration that never defines INSTRUMENTATION. Off it costs a static read
per update. On it costs two timestamps, plus a scan for the payload length on
the pointer path, which happens after the interval is closed so it slows
ingestion rather than flattering the rate.
Diagnostics > TDLib JSON turns it on and shows it; the counters are read when
the page opens rather than bound live, since a ticking readout would be a
second observer of the thread being measured.
Not built.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Post #20693
33