I wanted to understand the PStats protocol, since it is currently undocumented. I realised the best way to do that was to hack up my own implementation of a PStats server. I succeeded, and now I want to share my code for others to study, so that others can make their own PStats implementation if they wish.
The PStats protocol is actually quite simple. The client and server start the exchange by sending control messages over a TCP connection, with each control message prefixed with a 32-bit message length (excluding the length itself) and then an 8-bit message type, followed by the actual message data. All data is little-endian.
Afer the client connects, it sends a message identifying itself which includes a protocol version number. It also sends separate messages that identify all the available collectors and threads, both by unique index. (It keeps track of the ones it’s already sent, so that when new collectors or threads appear, it only sends the new ones.)
The server also sends a message identifying itself, but the server message contains a UDP port number for a UDP socket it opens. While control messages are always sent over TCP, the client can send frame data over either UDP or TCP (gracefully falling back to TCP if UDP fails). The UDP message format is slightly different; there is no length header, but there is a checksum, that is simply a 16-bit sum of all the message bytes.
Here is the code. It’s written in Node.js. You can just run node index.js and then start up any Panda application with “want-pstats 1” (or shift+S in pview).
Hi rdb! Would it be possible to update your code snippets to work on the latest version of pstats? I’m getting out of range errors, and I’m not familiar on working with datagrams in Javascript.
Here’s a trace for more context:
Panda Stats version 3.2 connected from DESKTOP-D35OS5N
Slowest 6 collectors of frame 2 on thread Main:
-----------------------------------------------
Frame took 0.0 ms
took 0.0 ms
node:internal/buffer:88
RangeError [ERR_OUT_OF_RANGE]: The value of "offset" is out of range. It must be >= 0 and <= 1073. Received 1075
at boundsError (node:internal/buffer:88:9)
at Buffer.readFloatForwards [as readFloatLE] (node:internal/buffer:534:5)
at DatagramIterator.getFloat32 (F:\projects\pstats\datagram.js:116:33)
at Client.readDatagram (F:\projects\pstats\client.js:121:34)
at Client.read (F:\projects\pstats\client.js:54:18)
at Socket.<anonymous> (F:\projects\pstats\index.js:26:24)
at Socket.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:559:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:510:3)
at Readable.push (node:internal/streams/readable:390:5)