Class BinaryThreadRecorder

java.lang.Object
fr.bl.drit.flow.agent.BinaryThreadRecorder
All Implemented Interfaces:
Recorder, ThreadRecorder, Closeable, AutoCloseable

public class BinaryThreadRecorder extends Object implements ThreadRecorder
Records a call tree in a compact binary format.

Overview

The generated .flow file is a linear sequence of events without any global header. Two event types exist:

  • ENTER: a method entry event
  • EXIT: one or more consecutive method exits

Method identifiers are numeric values assigned by a MethodIdMapping and stored in a separate file. The mapping associates a method identifier with a fully qualified method signature.

Event Structure

Each event starts with a single byte that encodes both:

  • the event type (ENTER or EXIT), and
  • the beginning of an unsigned variable-length integer.

The most significant bit (bit 7) determines the event type:

Packed First Byte Layout

The first byte of every event has the following structure:


   bit 7     : flag (1 = ENTER, 0 = EXIT)
   bit 6     : continuation bit (1 = more bytes follow)
   bits 5-0  : lowest 6 bits of the encoded value
 

The encoded value depends on the event type:

  • For ENTER events: the value is the method ID.
  • For EXIT events: the value is the number of additional consecutive exits.

Variable-Length Integer Encoding

All integer values are encoded as unsigned variable-length integers in a format equivalent to LEB128.

After the first byte, if the continuation bit (bit 6) is set, the remaining higher-order bits of the value are encoded using standard 7-bit groups:


   bit 7     : continuation (1 = more bytes follow)
   bits 6-0  : next 7 bits of the value
 

Each subsequent byte contributes 7 additional bits to the value. Decoding proceeds by accumulating payload bits while continuation bits are set.

ENTER Event

An ENTER event encodes a single method entry as [flag=1][methodId]. The methodId refers to the numeric identifier defined in the ID mapping file.

Example with methodId = 1: 1000 0001

Example with methodId = 8192: 1100 0000 0000 0001

EXIT Event

EXIT events are run-length encoded.

Instead of writing one byte per exit, consecutive exits are accumulated internally and flushed as a single event.

  • If exactly one exit occurred: [flag=0] (no continuation, no payload)
  • If n > 1 consecutive exits occurred: [flag=0][n - 1]

This means:

  • value == 0 represents a single exit.
  • value == k represents k + 1 consecutive exits.

This run-length encoding significantly reduces file size when methods return in bursts.

Decoding Algorithm (High-Level)

  1. Read first byte.
  2. Extract event type from bit 7.
  3. Extract continuation bit from bit 6.
  4. Extract lower 6 bits as initial value.
  5. If continuation is set, read additional LEB128 bytes and accumulate 7-bit groups.
  6. If ENTER: emit method entry with decoded methodId.
  7. If EXIT: emit value + 1 exits.
See Also:
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final byte
    Highest bit is 1 (0x80).
    static final byte
    Highest bit is 0 (0x00).
    protected final String
    The file containing the call tree data of the recorder's thread.
    static final byte
    Continuation bit in a varint, the highest bit (0x80).
    static final byte
    Flag bit, the highest bit (0x80).
    static final byte
    Continuation bit in a packed varint, second highest bit (0x40).
    static final byte
    Payload in a packed varint, the lowest 6 bits (0x3F).
    static final byte
    Payload in a varint, the lowest 7 bits (0x7F).
    static final long
    Rest of payload to encode in following varint bytes, all but 7 lowest bits (~0x7FL).
    protected final OutputStream
    Output stream for the binary call tree data of the recorder's thread.
    protected long
    Pending consecutive exits.
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    void
    enter(long methodId)
    Emit a method enter event with the given method ID.
    void
    Emit a method exit event.
    protected void
    Flush a pending exit event if there is one.
     
    protected void
    writeFlagAndVarInt(int flag, long value)
    Write unsigned variable-length integer with a 1-bit flag packed into the first byte.
    protected void
    writeVarInt(long value)
    Write an unsigned variable-length integer (LEB128-style).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • F_ENTER

      public static final byte F_ENTER
      Highest bit is 1 (0x80).
      See Also:
    • F_EXIT

      public static final byte F_EXIT
      Highest bit is 0 (0x00).
      See Also:
    • M_FLAG

      public static final byte M_FLAG
      Flag bit, the highest bit (0x80).
      See Also:
    • M_CONT

      public static final byte M_CONT
      Continuation bit in a varint, the highest bit (0x80).
      See Also:
    • M_PAYLOAD

      public static final byte M_PAYLOAD
      Payload in a varint, the lowest 7 bits (0x7F).
      See Also:
    • M_PAYLOAD_REST

      public static final long M_PAYLOAD_REST
      Rest of payload to encode in following varint bytes, all but 7 lowest bits (~0x7FL).
      See Also:
    • M_PACK_CONT

      public static final byte M_PACK_CONT
      Continuation bit in a packed varint, second highest bit (0x40).
      See Also:
    • M_PACK_PAYLOAD

      public static final byte M_PACK_PAYLOAD
      Payload in a packed varint, the lowest 6 bits (0x3F).
      See Also:
    • out

      protected final OutputStream out
      Output stream for the binary call tree data of the recorder's thread.
    • fileName

      protected final String fileName
      The file containing the call tree data of the recorder's thread.
    • pendingExits

      protected long pendingExits
      Pending consecutive exits.
  • Constructor Details

    • BinaryThreadRecorder

      public BinaryThreadRecorder(Path outputDir) throws IOException
      Parameters:
      outputDir - Path to output directory
      Throws:
      IOException - If an I/O error occurs when opening an output stream.
  • Method Details

    • getFileName

      public String getFileName()
      Returns:
      The file name this recorder is writing to
    • enter

      public void enter(long methodId) throws IOException
      Description copied from interface: Recorder
      Emit a method enter event with the given method ID.
      Specified by:
      enter in interface Recorder
      Parameters:
      methodId - The ID of the method to trace
      Throws:
      IOException - If an I/O error occurs when emitting the event.
    • exit

      public void exit() throws IOException
      Description copied from interface: Recorder
      Emit a method exit event.
      Specified by:
      exit in interface Recorder
      Throws:
      IOException - If an I/O error occurs when emitting the event.
    • flushPendingExits

      protected void flushPendingExits() throws IOException
      Flush a pending exit event if there is one.
      Throws:
      IOException - If an I/O error occurs when writing to file.
    • writeVarInt

      protected void writeVarInt(long value) throws IOException
      Write an unsigned variable-length integer (LEB128-style).
      
         bit 7     : continuation (1 if more bytes follow)
         bits 6-0  : next 7 bits of value
       
      Parameters:
      value - The positive integer to encode
      Throws:
      IOException - If an I/O error occurs when writing to file.
    • writeFlagAndVarInt

      protected void writeFlagAndVarInt(int flag, long value) throws IOException
      Write unsigned variable-length integer with a 1-bit flag packed into the first byte.

      First byte layout:

      
         bit 7     : flag
         bit 6     : continuation (1 if more bytes follow)
         bits 5-0  : lowest 6 bits of value
       
      Following bytes (if any) are encoded using writeVarInt.
      Parameters:
      flag - The event flag
      value - The positive integer to encode
      Throws:
      IOException - If an I/O error occurs when writing to file.
    • close

      public void close() throws IOException
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Throws:
      IOException