Skip to content

Commit 1eaf96e

Browse files
committed
LMDB native test harness (C)
1 parent 6d4c789 commit 1eaf96e

File tree

4 files changed

+403
-0
lines changed

4 files changed

+403
-0
lines changed

upstream-bench/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Upstream LMDB Benchmark
2+
3+
This directory contains the upstream C benchmark provided by the LMDB maintainer in response to [ITS#10406](https://bugs.openldap.org/show_bug.cgi?id=10406) - our report of write performance regression.
4+
5+
## Purpose
6+
7+
This benchmark serves as an authoritative baseline for validating LMDB performance across versions:
8+
- Uses native C code (eliminates JNI overhead)
9+
- Provided directly by LMDB maintainer
10+
- Matches our Java benchmark scenario (sequential append with integer keys)
11+
- Enables comparison between Java and C performance characteristics
12+
13+
## Files
14+
15+
- `mtest-append-original.c` - Upstream benchmark code from ITS#10406 (unmodified)
16+
- `mtest-append.c` - Modified benchmark for testing different scenarios
17+
- `run-upstream-bench.sh` - Test harness to run across multiple LMDB versions
18+
- `target/` - Build artifacts and results (gitignored)
19+
- `target/mtest-append` - Compiled benchmark binary
20+
- `target/results/` - Benchmark results for each LMDB version
21+
22+
## Benchmark Characteristics
23+
24+
- **Operation**: Sequential writes using `MDB_APPEND` flag
25+
- **Key Type**: Integer keys (`MDB_INTEGERKEY`)
26+
- **Entry Count**: 1,000,000
27+
- **Value Size**: 100 bytes (zeroed)
28+
- **Commit Frequency**: Every 1,000 entries (1,000 transactions total)
29+
- **Flags**: `MDB_NOSYNC` (for consistency with Java benchmarks)
30+
- **Iterations**: 3 runs per version
31+
32+
## Usage
33+
34+
```bash
35+
./run-upstream-bench.sh
36+
```
37+
38+
Results are saved to `target/results/upstream-LMDB_<version>.txt`
39+
40+
The script automatically:
41+
1. Checks out each LMDB version from the OpenLDAP repository
42+
2. Compiles the LMDB library
43+
3. Compiles and runs the benchmark
44+
4. Generates a summary comparison table
45+
46+
## Performance Expectations
47+
48+
Each benchmark iteration completes in ~0.075 seconds on modern hardware.
49+
Total runtime for all 14 versions (3 iterations each): ~1 minute.
50+
51+
## Comparison with Java Benchmarks
52+
53+
This C benchmark can be compared with LmdbJava benchmarks at https://lmdb-benchmark.lmdbjava.org/
54+
55+
Key differences:
56+
- C benchmark uses raw LMDB API (no JNI overhead)
57+
- C benchmark commits every 1,000 entries vs Java's single-transaction approach
58+
- Results help isolate whether regressions are in LMDB itself or JNI layer
59+
60+
## License
61+
62+
Licensed under the OpenLDAP Public License (see mtest-append-original.c for copyright details).
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* mtest-append.c - Howard Chu's benchmark from ITS#10406 */
2+
/*
3+
* Copyright 2011-2021 Howard Chu, Symas Corp.
4+
* All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted only as authorized by the OpenLDAP
8+
* Public License.
9+
*
10+
* A copy of this license is available in the file LICENSE in the
11+
* top-level directory of the distribution or, alternatively, at
12+
* <http://www.OpenLDAP.org/license.html>.
13+
*/
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <time.h>
17+
#include <sys/time.h>
18+
19+
#include "lmdb.h"
20+
21+
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22+
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23+
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24+
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
25+
26+
int main(int argc,char * argv[])
27+
{
28+
int i = 0, j = 0, rc;
29+
MDB_env *env;
30+
MDB_dbi dbi;
31+
MDB_val key, data;
32+
MDB_txn *txn;
33+
int count = 1000000;
34+
char sval[100] = "";
35+
struct timeval beg, end;
36+
37+
E(mdb_env_create(&env));
38+
E(mdb_env_set_mapsize(env, 1048576000));
39+
E(mdb_env_open(env, "./testdb", MDB_NOSYNC, 0664));
40+
41+
E(mdb_txn_begin(env, NULL, 0, &txn));
42+
E(mdb_dbi_open(txn, NULL, MDB_INTEGERKEY, &dbi));
43+
44+
key.mv_size = sizeof(int);
45+
key.mv_data = &i;
46+
47+
data.mv_size = sizeof(sval);
48+
data.mv_data = sval;
49+
printf("Adding %d values\n", count);
50+
gettimeofday(&beg, NULL);
51+
for (i=0;i<count;i++) {
52+
E(mdb_put(txn, dbi, &key, &data, MDB_APPEND));
53+
j++;
54+
if (j == 1000) {
55+
E(mdb_txn_commit(txn));
56+
E(mdb_txn_begin(env, NULL, 0, &txn));
57+
j = 0;
58+
}
59+
}
60+
E(mdb_txn_commit(txn));
61+
gettimeofday(&end, NULL);
62+
63+
mdb_dbi_close(env, dbi);
64+
mdb_env_close(env);
65+
66+
end.tv_usec -= beg.tv_usec;
67+
if (end.tv_usec < 0) {
68+
end.tv_usec += 1000000;
69+
end.tv_sec--;
70+
}
71+
end.tv_sec -= beg.tv_sec;
72+
printf("Added %d values in %ld.%06ldsec\n", count, end.tv_sec, end.tv_usec);
73+
74+
return 0;
75+
}

upstream-bench/mtest-append.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* mtest-append.c - Howard Chu's benchmark from ITS#10406 */
2+
/*
3+
* Copyright 2011-2021 Howard Chu, Symas Corp.
4+
* All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted only as authorized by the OpenLDAP
8+
* Public License.
9+
*
10+
* A copy of this license is available in the file LICENSE in the
11+
* top-level directory of the distribution or, alternatively, at
12+
* <http://www.OpenLDAP.org/license.html>.
13+
*/
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <time.h>
17+
#include <sys/time.h>
18+
19+
#include "lmdb.h"
20+
21+
#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22+
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23+
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24+
"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
25+
26+
int main(int argc,char * argv[])
27+
{
28+
int i = 0, j = 0, rc;
29+
MDB_env *env;
30+
MDB_dbi dbi;
31+
MDB_val key, data;
32+
MDB_txn *txn;
33+
MDB_cursor *cursor = NULL;
34+
int count = 1000000;
35+
char sval[100] = "";
36+
struct timeval beg, end;
37+
38+
E(mdb_env_create(&env));
39+
E(mdb_env_set_mapsize(env, 1048576000));
40+
E(mdb_env_open(env, "./testdb", MDB_NOSYNC, 0664));
41+
42+
E(mdb_txn_begin(env, NULL, 0, &txn));
43+
E(mdb_dbi_open(txn, NULL, MDB_INTEGERKEY, &dbi));
44+
45+
key.mv_size = sizeof(int);
46+
key.mv_data = &i;
47+
48+
data.mv_size = sizeof(sval);
49+
data.mv_data = sval;
50+
printf("Adding %d values\n", count);
51+
gettimeofday(&beg, NULL);
52+
for (i=0;i<count;i++) {
53+
if (!cursor)
54+
E(mdb_cursor_open(txn, dbi, &cursor));
55+
E(mdb_cursor_put(cursor, &key, &data, MDB_APPEND));
56+
j++;
57+
if (j == 1000) {
58+
mdb_cursor_close(cursor);
59+
cursor = NULL;
60+
E(mdb_txn_commit(txn));
61+
E(mdb_txn_begin(env, NULL, 0, &txn));
62+
j = 0;
63+
}
64+
}
65+
if (cursor)
66+
mdb_cursor_close(cursor);
67+
E(mdb_txn_commit(txn));
68+
gettimeofday(&end, NULL);
69+
70+
mdb_dbi_close(env, dbi);
71+
mdb_env_close(env);
72+
73+
end.tv_usec -= beg.tv_usec;
74+
if (end.tv_usec < 0) {
75+
end.tv_usec += 1000000;
76+
end.tv_sec--;
77+
}
78+
end.tv_sec -= beg.tv_sec;
79+
printf("Added %d values in %ld.%06ldsec\n", count, end.tv_sec, end.tv_usec);
80+
81+
return 0;
82+
}

0 commit comments

Comments
 (0)