# YCSB for ESP-IDF
Yahoo! Cloud Serving Benchmark ported to C for ESP-IDF — benchmark any key-value store on ESP32.
## Features
- **Core YCSB workloads**: load phase + run phase with configurable read/update/insert/scan/read-modify-write ratios
- **Distributions**: uniform, zipfian (scrambled), hotspot, sequential, latest, exponential
- **Multi-threaded**: spawns FreeRTOS tasks for concurrent benchmarking
- **Latency stats**: p50, p95, p99, min, max, average per operation type
- **Pluggable backends**: implement the `ycsb_db_t` function pointer struct — works with any storage (RAM, SPIFFS, network, PBFT consensus)
- **Zero heap in hot path**: static buffers, stack-allocated values
## Quick Start
```bash
idf.py add-dependency phukrit7171/ycsb
```
```c
#include "ycsb.h"
// 1. Implement your backend
ycsb_status_t my_read(void *ctx, ycsb_key_t table, ycsb_key_t key,
const ycsb_key_t *fields, int field_count,
ycsb_value_t *out) {
/* ... read from your KV store ... */
return YCSB_OK;
}
// 2. Create a DB descriptor
ycsb_db_t my_db = {
.read = my_read,
.insert = my_insert,
.update = my_update,
.del = my_delete,
.scan = my_scan,
};
// 3. Run the benchmark
void app_main(void) {
ycsb_config_t cfg;
ycsb_config_init(&cfg);
cfg.request_distribution = YCSB_DIST_ZIPFIAN;
cfg.read_proportion = 0.5;
cfg.update_proportion = 0.5;
ycsb_run(&cfg, &my_db);
}
```
## Preset Workloads
```c
#include "workloads/workloada.h" // update-heavy (50/50 read/update, zipfian)
#include "workloads/workloadb.h" // read-mostly (95/5 read/update, zipfian)
#include "workloads/workloadc.h" // read-only (100% read, zipfian)
ycsb_config_t cfg;
YCSB_WORKLOAD_A_INIT(&cfg);
ycsb_run(&cfg, &my_db);
```
## Workload Reference
| Workload | Read | Update | Insert | Scan | RMW | Distribution |
|----------|------|--------|--------|------|-----|-------------|
| A | 50% | 50% | — | — | — | zipfian |
| B | 95% | 5% | — | — | — | zipfian |
| C | 100% | — | — | — | — | zipfian |
| D | 95% | — | 5% | — | — | latest |
| E | 5% | — | — | 95% | — | zipfian |
| F | 50% | — | — | — | 50% | zipfian |
## Configuration (Defaults)
| Field | Default | Description |
|-------|---------|-------------|
| `record_count` | 1000 | Number of records to load |
| `operation_count` | 1000 | Total transaction operations |
| `field_count` | 10 | Fields per record |
| `field_length` | 100 | Bytes per field |
| `thread_count` | 1 | FreeRTOS worker tasks |
| `read_proportion` | 0.95 | Fraction of reads |
| `update_proportion` | 0.05 | Fraction of updates |
| `zero_padding` | 1 | Key padding (user00000001) |
| `table` | "usertable" | Database table name |
## Integrating with esp-tinybft
Place this integration code in your combined project:
```c
#include "ycsb.h"
#include "esp-tinybft.h"
static ycsb_status_t bft_read(void *ctx, ycsb_key_t table, ycsb_key_t key,
const ycsb_key_t *fields, int field_count,
ycsb_value_t *out) {
Byz_req req; Byz_rep rep;
Byz_alloc_request(&req, 256);
/* marshal: [op=READ][table_len][table][key_len][key][field_count] */
int len = marshal_read(&req, table, key, fields, field_count);
req.size = len;
Byz_invoke(&req, &rep, false);
/* unmarshal rep.contents into ycsb_value_t */
Byz_free_reply(&rep);
Byz_free_request(&req);
return YCSB_OK;
}
void app_main(void) {
Byz_init_client("config.txt", "priv.der", 0);
ycsb_db_t bft_db = {
.read = bft_read,
.insert = bft_insert,
.update = bft_update,
.del = bft_delete,
};
ycsb_config_t cfg;
ycsb_config_init(&cfg);
ycsb_run(&cfg, &bft_db);
}
```
## License
Apache 2.0 — derived from the original [YCSB](https://github.com/brianfrankcooper/YCSB) by Yahoo! Inc.
40e029b3ac27fd5a6a50fb1b9f508f89f4014bdf
idf.py add-dependency "phukrit7171/ycsb^0.1.0"