Skip to content

Commit 0dfebc3

Browse files
committed
perf(sync): add sync benchmark tracing
Add a sync benchmark harness with debug step traces and network endpoint timing logs.
1 parent 52231c6 commit 0dfebc3

5 files changed

Lines changed: 686 additions & 4 deletions

File tree

Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ endif
166166
T_LDFLAGS += -fprofile-arcs -ftest-coverage
167167
endif
168168

169+
ifdef SYNC_BENCH_DEBUG
170+
CFLAGS += -DCLOUDSYNC_NETWORK_TRACE
171+
endif
172+
169173
# Native network support only for Apple platforms
170174
ifdef NATIVE_NETWORK
171175
RELEASE_OBJ += $(patsubst %.m, $(BUILD_RELEASE)/%_m.o, $(notdir $(wildcard $(NETWORK_DIR)/*.m)))
@@ -237,6 +241,23 @@ e2e: $(TARGET) $(DIST_DIR)/integration$(EXE)
237241
fi; \
238242
./$(DIST_DIR)/integration$(EXE)
239243

244+
# Run the sync performance benchmark. This is intentionally separate from e2e
245+
# because timings depend on network/server load and polling configuration.
246+
sync-bench: $(TARGET) $(DIST_DIR)/sync_bench$(EXE)
247+
@if [ -f .env ]; then \
248+
export $$(grep -v '^#' .env | xargs); \
249+
fi; \
250+
if [ -n "$(SYNC_BENCH_DATABASE_ID)" ]; then export SYNC_BENCH_DATABASE_ID="$(SYNC_BENCH_DATABASE_ID)"; fi; \
251+
if [ -n "$(SYNC_BENCH_CLOUDSYNC_ADDRESS)" ]; then export SYNC_BENCH_CLOUDSYNC_ADDRESS="$(SYNC_BENCH_CLOUDSYNC_ADDRESS)"; fi; \
252+
if [ -n "$(SYNC_BENCH_APIKEY)" ]; then export SYNC_BENCH_APIKEY="$(SYNC_BENCH_APIKEY)"; fi; \
253+
if [ -n "$(SYNC_BENCH_POLL_DELAY_MS)" ]; then export SYNC_BENCH_POLL_DELAY_MS="$(SYNC_BENCH_POLL_DELAY_MS)"; fi; \
254+
if [ -n "$(SYNC_BENCH_MAX_POLLS)" ]; then export SYNC_BENCH_MAX_POLLS="$(SYNC_BENCH_MAX_POLLS)"; fi; \
255+
if [ -n "$(SYNC_BENCH_OUTPUT)" ]; then export SYNC_BENCH_OUTPUT="$(SYNC_BENCH_OUTPUT)"; fi; \
256+
./$(DIST_DIR)/sync_bench$(EXE)
257+
258+
sync-bench-debug:
259+
$(MAKE) SYNC_BENCH_DEBUG=1 sync-bench
260+
240261
OPENSSL_TARBALL = $(OPENSSL_DIR)/$(OPENSSL_VERSION).tar.gz
241262

242263
$(OPENSSL_TARBALL):

src/network/network.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
#include <inttypes.h>
1212
#include <stdlib.h>
1313

14+
#ifdef CLOUDSYNC_NETWORK_TRACE
15+
#ifdef _WIN32
16+
#include <windows.h>
17+
#else
18+
#include <time.h>
19+
#endif
20+
#endif
21+
1422
#include "network.h"
1523
#include "../utils.h"
1624
#include "../dbutils.h"
@@ -58,6 +66,47 @@ struct network_data {
5866
char *status_endpoint;
5967
};
6068

69+
#ifdef CLOUDSYNC_NETWORK_TRACE
70+
double network_trace_now_ms(void) {
71+
#ifdef _WIN32
72+
LARGE_INTEGER freq;
73+
LARGE_INTEGER counter;
74+
QueryPerformanceFrequency(&freq);
75+
QueryPerformanceCounter(&counter);
76+
return ((double)counter.QuadPart * 1000.0) / (double)freq.QuadPart;
77+
#else
78+
struct timespec ts;
79+
clock_gettime(CLOCK_MONOTONIC, &ts);
80+
return ((double)ts.tv_sec * 1000.0) + ((double)ts.tv_nsec / 1000000.0);
81+
#endif
82+
}
83+
84+
const char *network_trace_endpoint_name(network_data *data, const char *endpoint) {
85+
if (!data || !endpoint) return "unknown";
86+
if (data->check_endpoint && strcmp(endpoint, data->check_endpoint) == 0) return "check";
87+
if (data->upload_endpoint && strcmp(endpoint, data->upload_endpoint) == 0) return "upload-url";
88+
if (data->apply_endpoint && strcmp(endpoint, data->apply_endpoint) == 0) return "apply";
89+
if (data->status_endpoint && strcmp(endpoint, data->status_endpoint) == 0) return "status";
90+
return "artifact";
91+
}
92+
93+
const char *network_trace_result_name(int code) {
94+
switch (code) {
95+
case CLOUDSYNC_NETWORK_OK: return "ok";
96+
case CLOUDSYNC_NETWORK_ERROR: return "error";
97+
case CLOUDSYNC_NETWORK_BUFFER: return "buffer";
98+
default: return "unknown";
99+
}
100+
}
101+
102+
void network_trace_log(network_data *data, const char *method, const char *endpoint, long http_status, int result_code, size_t bytes, double elapsed_ms) {
103+
fprintf(stderr,
104+
"[cloudsync-network] endpoint=%s method=%s http_status=%ld result=%s bytes=%zu elapsed_ms=%.2f\n",
105+
network_trace_endpoint_name(data, endpoint), method, http_status,
106+
network_trace_result_name(result_code), bytes, elapsed_ms);
107+
}
108+
#endif
109+
61110
typedef struct {
62111
char *buffer;
63112
size_t balloc;
@@ -210,6 +259,10 @@ NETWORK_RESULT network_receive_buffer (network_data *data, const char *endpoint,
210259
struct curl_slist* headers = NULL;
211260
char errbuf[CURL_ERROR_SIZE] = {0};
212261
long response_code = 0;
262+
const char *method = (json_payload || is_post_request) ? "POST" : "GET";
263+
#ifdef CLOUDSYNC_NETWORK_TRACE
264+
double trace_start_ms = network_trace_now_ms();
265+
#endif
213266

214267
CURL *curl = curl_easy_init();
215268
if (!curl) return (NETWORK_RESULT){CLOUDSYNC_NETWORK_ERROR, NULL, 0, NULL, NULL};
@@ -299,6 +352,9 @@ NETWORK_RESULT network_receive_buffer (network_data *data, const char *endpoint,
299352
result.blen = buffer ? blen : rc;
300353
}
301354

355+
#ifdef CLOUDSYNC_NETWORK_TRACE
356+
network_trace_log(data, method, endpoint, response_code, result.code, result.blen, network_trace_now_ms() - trace_start_ms);
357+
#endif
302358
return result;
303359
}
304360

@@ -321,6 +377,10 @@ bool network_send_buffer (network_data *data, const char *endpoint, const char *
321377
bool result = false;
322378
char errbuf[CURL_ERROR_SIZE] = {0};
323379
CURLcode rc = CURLE_OK;
380+
long response_code = 0;
381+
#ifdef CLOUDSYNC_NETWORK_TRACE
382+
double trace_start_ms = network_trace_now_ms();
383+
#endif
324384

325385
// init curl
326386
CURL *curl = curl_easy_init();
@@ -393,9 +453,16 @@ bool network_send_buffer (network_data *data, const char *endpoint, const char *
393453

394454
// perform the upload
395455
rc = curl_easy_perform(curl);
456+
if (curl) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
396457
if (rc == CURLE_OK) result = true;
397458

398459
cleanup:
460+
#ifdef CLOUDSYNC_NETWORK_TRACE
461+
network_trace_log(data, "PUT", endpoint, response_code,
462+
result ? CLOUDSYNC_NETWORK_OK : CLOUDSYNC_NETWORK_ERROR,
463+
result ? (size_t)blob_size : 0,
464+
network_trace_now_ms() - trace_start_ms);
465+
#endif
399466
if (curl) curl_easy_cleanup(curl);
400467
if (headers) curl_slist_free_all(headers);
401468
return result;

src/network/network.m

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ void network_buffer_cleanup (void *xdata) {
1414
}
1515

1616
bool network_send_buffer(network_data *data, const char *endpoint, const char *authentication, const void *blob, int blob_size) {
17+
#ifdef CLOUDSYNC_NETWORK_TRACE
18+
double trace_start_ms = network_trace_now_ms();
19+
#endif
1720
NSString *urlString = [NSString stringWithUTF8String:endpoint];
1821
NSURL *url = [NSURL URLWithString:urlString];
19-
if (!url) return false;
22+
if (!url) {
23+
#ifdef CLOUDSYNC_NETWORK_TRACE
24+
network_trace_log(data, "PUT", endpoint, 0, CLOUDSYNC_NETWORK_ERROR, 0, network_trace_now_ms() - trace_start_ms);
25+
#endif
26+
return false;
27+
}
2028

2129
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
2230
[request setHTTPMethod:@"PUT"];
@@ -37,6 +45,7 @@ bool network_send_buffer(network_data *data, const char *endpoint, const char *a
3745
[request setHTTPBody:bodyData];
3846

3947
__block bool success = false;
48+
__block NSInteger statusCode = 0;
4049
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
4150

4251
NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
@@ -47,7 +56,7 @@ bool network_send_buffer(network_data *data, const char *endpoint, const char *a
4756
NSURLResponse * _Nullable response,
4857
NSError * _Nullable error) {
4958
if (!error && [response isKindOfClass:[NSHTTPURLResponse class]]) {
50-
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
59+
statusCode = [(NSHTTPURLResponse *)response statusCode];
5160
success = (statusCode >= 200 && statusCode < 300);
5261
}
5362
dispatch_semaphore_signal(sema);
@@ -57,11 +66,22 @@ bool network_send_buffer(network_data *data, const char *endpoint, const char *a
5766
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
5867
[session finishTasksAndInvalidate];
5968

69+
#ifdef CLOUDSYNC_NETWORK_TRACE
70+
network_trace_log(data, "PUT", endpoint, (long)statusCode,
71+
success ? CLOUDSYNC_NETWORK_OK : CLOUDSYNC_NETWORK_ERROR,
72+
success ? (size_t)blob_size : 0,
73+
network_trace_now_ms() - trace_start_ms);
74+
#endif
75+
6076
return success;
6177
}
6278

6379

6480
NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint, const char *authentication, bool zero_terminated, bool is_post_request, char *json_payload, const char **extra_headers, int nextra_headers) {
81+
#ifdef CLOUDSYNC_NETWORK_TRACE
82+
double trace_start_ms = network_trace_now_ms();
83+
#endif
84+
const char *method = (json_payload || is_post_request) ? "POST" : "GET";
6585

6686
NSString *urlString = [NSString stringWithUTF8String:endpoint];
6787
NSURL *url = [NSURL URLWithString:urlString];
@@ -72,6 +92,9 @@ NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint,
7292
result.buffer = (char *)msg.UTF8String;
7393
result.xdata = (void *)CFBridgingRetain(msg);
7494
result.xfree = network_buffer_cleanup;
95+
#ifdef CLOUDSYNC_NETWORK_TRACE
96+
network_trace_log(data, method, endpoint, 0, result.code, 0, network_trace_now_ms() - trace_start_ms);
97+
#endif
7598
return result;
7699
}
77100

@@ -134,7 +157,11 @@ NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint,
134157
if (!responseError && (statusCode >= 200 && statusCode < 300)) {
135158
// check if OK should be returned
136159
if (responseData == nil || [responseData length] == 0) {
137-
return (NETWORK_RESULT){CLOUDSYNC_NETWORK_OK, NULL, 0, NULL, NULL};
160+
NETWORK_RESULT result = {CLOUDSYNC_NETWORK_OK, NULL, 0, NULL, NULL};
161+
#ifdef CLOUDSYNC_NETWORK_TRACE
162+
network_trace_log(data, method, endpoint, (long)statusCode, result.code, 0, network_trace_now_ms() - trace_start_ms);
163+
#endif
164+
return result;
138165
}
139166

140167
// otherwise return a buffer
@@ -144,7 +171,11 @@ NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint,
144171
NSString *utf8String = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
145172
if (!utf8String) {
146173
NSString *msg = @"Response is not valid UTF-8";
147-
return (NETWORK_RESULT){CLOUDSYNC_NETWORK_ERROR, (char *)msg.UTF8String, 0, (void *)CFBridgingRetain(msg), network_buffer_cleanup};
174+
NETWORK_RESULT error_result = {CLOUDSYNC_NETWORK_ERROR, (char *)msg.UTF8String, 0, (void *)CFBridgingRetain(msg), network_buffer_cleanup};
175+
#ifdef CLOUDSYNC_NETWORK_TRACE
176+
network_trace_log(data, method, endpoint, (long)statusCode, error_result.code, 0, network_trace_now_ms() - trace_start_ms);
177+
#endif
178+
return error_result;
148179
}
149180
result.buffer = (char *)utf8String.UTF8String;
150181
result.xdata = (void *)CFBridgingRetain(utf8String);
@@ -155,6 +186,9 @@ NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint,
155186
result.blen = [responseData length];
156187
result.xfree = network_buffer_cleanup;
157188

189+
#ifdef CLOUDSYNC_NETWORK_TRACE
190+
network_trace_log(data, method, endpoint, (long)statusCode, result.code, result.blen, network_trace_now_ms() - trace_start_ms);
191+
#endif
158192
return result;
159193
}
160194

@@ -178,5 +212,8 @@ NETWORK_RESULT network_receive_buffer(network_data *data, const char *endpoint,
178212
result.xfree = network_buffer_cleanup;
179213
result.blen = responseError ? (size_t)errorCode : (size_t)statusCode;
180214

215+
#ifdef CLOUDSYNC_NETWORK_TRACE
216+
network_trace_log(data, method, endpoint, (long)statusCode, result.code, 0, network_trace_now_ms() - trace_start_ms);
217+
#endif
181218
return result;
182219
}

src/network/network_private.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,12 @@ bool network_data_set_endpoints (network_data *data, char *auth, char *check, ch
4141
bool network_send_buffer(network_data *data, const char *endpoint, const char *authentication, const void *blob, int blob_size);
4242
NETWORK_RESULT network_receive_buffer (network_data *data, const char *endpoint, const char *authentication, bool zero_terminated, bool is_post_request, char *json_payload, const char **extra_headers, int nextra_headers);
4343

44+
#ifdef CLOUDSYNC_NETWORK_TRACE
45+
const char *network_trace_endpoint_name(network_data *data, const char *endpoint);
46+
const char *network_trace_result_name(int code);
47+
void network_trace_log(network_data *data, const char *method, const char *endpoint, long http_status, int result_code, size_t bytes, double elapsed_ms);
48+
double network_trace_now_ms(void);
49+
#endif
50+
4451

4552
#endif

0 commit comments

Comments
 (0)