> For the complete documentation index, see [llms.txt](https://docs.xplatform.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xplatform.com/performance/benchmark-suite/modules/serialization-module.md).

# Serialization Module

The Serialization module benchmarks message encoding and decoding performance using X Platform's Xbuf2 binary serialization format.

## Overview

Message serialization/deserialization is a critical operation in messaging systems. This benchmark measures the overhead of:

* **Encoding**: Converting POJO messages to wire format
* **Decoding**: Converting wire format back to POJOs

The benchmark uses the same `Car` message model used in the [AEP Module](/performance/benchmark-suite/modules/aep-module.md) canonical benchmark.

## Test Program

**Class**: `com.neeve.perf.serialization.Driver`

The benchmark can be invoked through the X Platform Interactive CLI or directly.

## Message Formats

### xbuf2 / xbuf2.serial

Tests serialization with sequential/predictable data:

```bash
java -cp "libs/*" com.neeve.perf.serialization.Driver --provider xbuf2.serial
```

**Characteristics**:

* Predictable data patterns
* Consistent serialized size
* Best-case performance

### xbuf2.random

Tests serialization with random data:

```bash
java -cp "libs/*" com.neeve.perf.serialization.Driver --provider xbuf2.random
```

**Characteristics**:

* Random data in all fields
* Variable serialized size
* More realistic performance

## Test Message

The `Car` message contains:

**Simple Fields**:

* timestamp (long)
* serialNumber (int)
* modelYear (short)
* available (boolean)
* code (enum)
* vehicleCode (string)

**Complex Fields**:

* engine (nested object)
* extras (bit set)
* someNumbers (int array)

**Repeated Fields**:

* performanceFigures (array of objects)
* fuelFigures (array of objects)

**Typical Size**: \~200 bytes serialized

## Command-Line Parameters

| Parameter    | Short | Default | Description                                              |
| ------------ | ----- | ------- | -------------------------------------------------------- |
| `--provider` | `-p`  | xbuf2   | Serialization provider: `xbuf2.serial` or `xbuf2.random` |

## Running the Benchmark

### Basic Usage

```bash
# Extract distribution
tar xvf nvx-perf-serialization-{version}-dist-linux-x86-64.tar.gz
cd nvx-perf-serialization-{version}

# Run with sequential data
$JAVA_HOME/bin/java -cp "libs/*" com.neeve.perf.serialization.Driver --provider xbuf2.serial
```

### Test with Random Data

```bash
$JAVA_HOME/bin/java -cp "libs/*" com.neeve.perf.serialization.Driver --provider xbuf2.random
```

## Interpreting Results

The benchmark outputs median and mean latencies for encoding and decoding operations.

**Example Output**:

```
Calculating nanoTime() overhead...
...22 nanos
PROV                      RUN TYPE  SIZE  MED   MEAN
xbuf2.serial              1   ENC   178   245   247
xbuf2.serial              1   DEC   178   238   240
xbuf2.serial              2   ENC   178   243   245
xbuf2.serial              2   DEC   178   236   238
xbuf2.serial              3   ENC   178   244   246
xbuf2.serial              3   DEC   178   237   239
```

### Result Columns

* **PROV**: Serialization provider
* **RUN**: Run number (multiple runs for consistency)
* **TYPE**: Operation type (ENC=encode, DEC=decode)
* **SIZE**: Serialized size in bytes
* **MED**: Median latency in nanoseconds
* **MEAN**: Mean latency in nanoseconds

### Typical Results (Linux x86-64)

| Operation | Sequential Data | Random Data | Size        |
| --------- | --------------- | ----------- | ----------- |
| Encode    | \~240-250ns     | \~250-280ns | \~178 bytes |
| Decode    | \~235-245ns     | \~245-275ns | \~178 bytes |

### Performance Characteristics

1. **Encode vs Decode**:
   * Encoding and decoding have similar overhead
   * Both operations are highly optimized
2. **Sequential vs Random**:
   * Random data \~5-10% slower due to less predictable access patterns
   * Sequential data represents best-case performance
3. **Message Size**:
   * Overhead scales roughly linearly with message complexity
   * The Car message is moderately complex

## Access Patterns

The benchmark demonstrates two message access patterns:

### Indirect Access (POJO)

Standard object-oriented access via getters/setters:

```java
// Encoding
Car car = Car.create();
car.setTimestamp(System.currentTimeMillis());
car.setSerialNumber(12345);
car.setManufacturer("Toyota");
// ... set other fields
byte[] encoded = car.encode();

// Decoding
Car decoded = Car.create();
decoded.decode(encoded);
long timestamp = decoded.getTimestamp();
int serialNumber = decoded.getSerialNumber();
String manufacturer = decoded.getManufacturer();
```

### Direct Access (Serializer/Deserializer)

Zero-copy access via serializers (shown in benchmark code):

```java
// Encoding
Car.Serializer serializer = new Car.Serializer();
serializer.handleTimestamp(System.currentTimeMillis());
serializer.handleSerialNumber(12345);
// ... handle other fields
byte[] encoded = serializer.getEncodedBytes();

// Decoding
Car.Deserializer deserializer = new Car.Deserializer();
deserializer.run(new MyCallback(), encoded);
```

**Direct access is faster (used in high-performance scenarios)**

## Performance Tuning

### For Lowest Latency

1. Use direct serialization (serializer/deserializer)
2. Reuse serializer/deserializer instances
3. Pre-allocate buffers
4. Minimize nested object depth

### For Ease of Use

1. Use indirect access (POJO getters/setters)
2. Accept \~10-15% overhead for better code readability
3. Good for most business applications

## Comparison with AEP Module

The [AEP Module](/performance/benchmark-suite/modules/aep-module.md) canonical benchmark includes serialization overhead as part of end-to-end latency:

* **Serialization Benchmark**: \~480ns (encode + decode)
* **AEP Benchmark**: \~27µs (includes serialization + all other operations)

**Serialization represents \~1.7% of end-to-end latency**

## Best Practices

### Message Design

1. **Keep messages compact**: Fewer fields = faster serialization
2. **Use primitives where possible**: Avoid excessive nesting
3. **Size arrays appropriately**: Large arrays increase overhead
4. **Consider field ordering**: Group frequently-accessed fields

### Code Patterns

```java
// GOOD: Reuse serializer instance
Car.Serializer serializer = new Car.Serializer();
for (Car car : cars) {
    serializer.reset();
    // populate serializer
    byte[] encoded = serializer.getEncodedBytes();
}

// BAD: Create new serializer each time
for (Car car : cars) {
    Car.Serializer serializer = new Car.Serializer(); // Allocation overhead!
    byte[] encoded = serializer.getEncodedBytes();
}
```

## Next Steps

* Review [AEP Module](/performance/benchmark-suite/modules/aep-module.md) to see serialization in end-to-end context
* Explore [Link Module](/performance/benchmark-suite/modules/link-module.md) for messaging transport benchmarks
* Return to [Modules Overview](/performance/benchmark-suite/modules.md) for other modules
