1 /*
2  * ryw_benchmark.c
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include "test.h"
22 #include <foundationdb/fdb_c.h>
23 #include <foundationdb/fdb_c_options.g.h>
24 
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 
31 pthread_t netThread;
32 
33 int numKeys = 10000;
34 int keySize = 16;
35 uint8_t** keys;
36 
insertData(FDBTransaction * tr)37 void insertData(FDBTransaction *tr) {
38 	fdb_transaction_clear_range(tr, (uint8_t*)"", 0, (uint8_t*)"\xff", 1);
39 
40 	uint8_t *v = (uint8_t*)"foo";
41 	uint32_t i;
42 	for(i = 0; i <= numKeys; ++i) {
43 		fdb_transaction_set(tr, keys[i], keySize, v, 3);
44 	}
45 }
46 
runTest(int (* testFxn)(FDBTransaction *,struct ResultSet *),FDBTransaction * tr,struct ResultSet * rs,const char * kpiName)47 int runTest(int (*testFxn)(FDBTransaction*, struct ResultSet*), FDBTransaction *tr, struct ResultSet *rs, const char *kpiName) {
48 	int numRuns = 25;
49 	int *results = malloc(sizeof(int)*numRuns);
50 	int i = 0;
51 	for(; i < numRuns; ++i) {
52 		results[i] = testFxn(tr, rs);
53 		if(results[i] < 0) {
54 			free(results);
55 			return -1;
56 		}
57 	}
58 
59 	int result = median(results, numRuns);
60 	free(results);
61 
62 	addKpi(rs, kpiName, result, "keys/s");
63 
64 	return result;
65 }
66 
getSingle(FDBTransaction * tr,struct ResultSet * rs)67 int getSingle(FDBTransaction *tr, struct ResultSet *rs) {
68 	int present;
69 	uint8_t const *value;
70 	int length;
71 	int i;
72 
73 	double start = getTime();
74 	for(i = 0; i < numKeys; ++i) {
75 		FDBFuture *f = fdb_transaction_get(tr, keys[5001], keySize, 0);
76 		if(getError(fdb_future_block_until_ready(f), "GetSingle (block for get)", rs)) return -1;
77 		if(getError(fdb_future_get_value(f, &present, &value, &length), "GetSingle (get result)", rs)) return -1;
78 		fdb_future_destroy(f);
79 	}
80 	double end = getTime();
81 
82 	return numKeys / (end - start);
83 }
84 
getManySequential(FDBTransaction * tr,struct ResultSet * rs)85 int getManySequential(FDBTransaction *tr, struct ResultSet *rs) {
86 	int present;
87 	uint8_t const *value;
88 	int length;
89 	int i;
90 
91 	double start = getTime();
92 	for(i = 0; i < numKeys; ++i) {
93 		FDBFuture *f = fdb_transaction_get(tr, keys[i], keySize, 0);
94 		if(getError(fdb_future_block_until_ready(f), "GetManySequential (block for get)", rs)) return -1;
95 		if(getError(fdb_future_get_value(f, &present, &value, &length), "GetManySequential (get result)", rs)) return -1;
96 		fdb_future_destroy(f);
97 	}
98 	double end = getTime();
99 
100 	return numKeys / (end - start);
101 }
102 
getRangeBasic(FDBTransaction * tr,struct ResultSet * rs)103 int getRangeBasic(FDBTransaction *tr, struct ResultSet *rs) {
104 	int count;
105 	const FDBKeyValue *kvs;
106 	int more;
107 	int i;
108 
109 	double start = getTime();
110 	for(i = 0; i < 100; ++i) {
111 		FDBFuture *f = fdb_transaction_get_range(tr, FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[0], keySize), FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[numKeys], keySize), numKeys, 0, 0, 1, 0, 0);
112 
113 		if(getError(fdb_future_block_until_ready(f), "GetRangeBasic (block for get range)", rs)) return -1;
114 		if(getError(fdb_future_get_keyvalue_array(f, &kvs, &count, &more), "GetRangeBasic (get range results)", rs)) return -1;
115 
116 		if(count != numKeys) {
117 			fprintf(stderr, "Bad count %d (expected %d)\n", count, numKeys);
118 			addError(rs, "GetRangeBasic bad count");
119 			return -1;
120 		}
121 	}
122 	double end = getTime();
123 
124 	return 100 * numKeys / (end - start);
125 }
126 
singleClearGetRange(FDBTransaction * tr,struct ResultSet * rs)127 int singleClearGetRange(FDBTransaction *tr, struct ResultSet *rs) {
128 	int count;
129 	const FDBKeyValue *kvs;
130 	int more;
131 	int i;
132 
133 	for(i = 0; i < numKeys; i+=2) {
134 		fdb_transaction_clear(tr, keys[i], keySize);
135 	}
136 
137 	double start = getTime();
138 	for(i = 0; i < 100; ++i) {
139 		FDBFuture *f = fdb_transaction_get_range(tr, FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[0], keySize), FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[numKeys], keySize), numKeys, 0, 0, 1, 0, 0);
140 
141 		if(getError(fdb_future_block_until_ready(f), "SingleClearGetRange (block for get range)", rs)) return -1;
142 		if(getError(fdb_future_get_keyvalue_array(f, &kvs, &count, &more), "SingleClearGetRange (get range results)", rs)) return -1;
143 
144 		fdb_future_destroy(f);
145 
146 		if(count != numKeys/2) {
147 			fprintf(stderr, "Bad count %d (expected %d)\n", count, numKeys);
148 			addError(rs, "SingleClearGetRange bad count");
149 			return -1;
150 		}
151 	}
152 	double end = getTime();
153 
154 	insertData(tr);
155 	return 100 * numKeys / 2 / (end - start);
156 }
157 
clearRangeGetRange(FDBTransaction * tr,struct ResultSet * rs)158 int clearRangeGetRange(FDBTransaction *tr, struct ResultSet *rs) {
159 	int count;
160 	const FDBKeyValue *kvs;
161 	int more;
162 	int i;
163 
164 	for(i = 0; i < numKeys; i+=4) {
165 		fdb_transaction_clear_range(tr, keys[i], keySize, keys[i+1], keySize);
166 	}
167 
168 	double start = getTime();
169 	for(i = 0; i < 100; ++i) {
170 		FDBFuture *f = fdb_transaction_get_range(tr, FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[0], keySize), FDB_KEYSEL_LAST_LESS_OR_EQUAL(keys[numKeys], keySize), numKeys, 0, 0, 1, 0, 0);
171 
172 		if(getError(fdb_future_block_until_ready(f), "ClearRangeGetRange (block for get range)", rs)) return -1;
173 		if(getError(fdb_future_get_keyvalue_array(f, &kvs, &count, &more), "ClearRangeGetRange (get range results)", rs)) return -1;
174 
175 		fdb_future_destroy(f);
176 
177 		if(count != numKeys*3/4) {
178 			fprintf(stderr, "Bad count %d (expected %d)\n", count, numKeys*3/4);
179 			addError(rs, "ClearRangeGetRange bad count");
180 			return -1;
181 		}
182 	}
183 	double end = getTime();
184 
185 	insertData(tr);
186 	return 100 * numKeys * 3 / 4 / (end - start);
187 }
188 
interleavedSetsGets(FDBTransaction * tr,struct ResultSet * rs)189 int interleavedSetsGets(FDBTransaction *tr, struct ResultSet *rs) {
190 	int present;
191 	uint8_t const *value;
192 	int length;
193 	int i;
194 
195 	uint8_t *k = (uint8_t*)"foo";
196 	uint8_t v[10];
197 	int num = 1;
198 
199 	double start = getTime();
200 	sprintf((char*)v, "%d", num);
201 	fdb_transaction_set(tr, k, 3, v, strlen((char*)v));
202 
203 	for(i = 0; i < 10000; ++i) {
204 		FDBFuture *f = fdb_transaction_get(tr, k, 3, 0);
205 		if(getError(fdb_future_block_until_ready(f), "InterleavedSetsGets (block for get)", rs)) return -1;
206 		if(getError(fdb_future_get_value(f, &present, &value, &length), "InterleavedSetsGets (get result)", rs)) return -1;
207 		fdb_future_destroy(f);
208 
209 		sprintf((char*)v, "%d", ++num);
210 		fdb_transaction_set(tr, k, 3, v, strlen((char*)v));
211 	}
212 	double end = getTime();
213 
214 	return 10000 / (end - start);
215 }
216 
runTests(struct ResultSet * rs)217 void runTests(struct ResultSet *rs) {
218 	FDBDatabase *db = openDatabase(rs, &netThread);
219 
220 	FDBTransaction *tr;
221 	checkError(fdb_database_create_transaction(db, &tr), "create transaction", rs);
222 
223 	FDBFuture *f = fdb_transaction_get_read_version(tr);
224 	checkError(fdb_future_block_until_ready(f), "block for read version", rs);
225 
226 	int64_t version;
227 	checkError(fdb_future_get_version(f, &version), "get version", rs);
228 	fdb_future_destroy(f);
229 
230 	insertData(tr);
231 
232 	runTest(&getSingle, tr, rs, "C: get single cached value throughput");
233 	runTest(&getManySequential, tr, rs, "C: get sequential cached values throughput");
234 	runTest(&getRangeBasic, tr, rs, "C: get range cached values throughput");
235 	runTest(&singleClearGetRange, tr, rs, "C: get range cached values with clears throughput");
236 	runTest(&clearRangeGetRange, tr, rs, "C: get range cached values with clear ranges throughput");
237 	runTest(&interleavedSetsGets, tr, rs, "C: interleaved sets and gets on a single key throughput");
238 
239 	fdb_transaction_destroy(tr);
240 	fdb_database_destroy(db);
241 	fdb_stop_network();
242 }
243 
main(int argc,char ** argv)244 int main(int argc, char **argv) {
245 	srand(time(NULL));
246 	struct ResultSet *rs = newResultSet();
247 	checkError(fdb_select_api_version(610), "select API version", rs);
248 	printf("Running RYW Benchmark test at client version: %s\n", fdb_get_client_version());
249 
250 	keys = generateKeys(numKeys, keySize);
251 	runTests(rs);
252 	writeResultSet(rs);
253 	freeResultSet(rs);
254 	freeKeys(keys, numKeys);
255 
256 	return 0;
257 }
258 
259