blob: 858aeb9809ad87ea0a9fdd9438182e78ccad74d5 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
nnoble8a67b5c2014-12-12 10:48:34 -080034#include "src/core/statistics/census_log.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
Craig Tiller1d2e2192015-02-09 15:25:21 -080038#include <grpc/support/cpu.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039#include <grpc/support/log.h>
40#include <grpc/support/port_platform.h>
41#include <grpc/support/sync.h>
42#include <grpc/support/thd.h>
43#include <grpc/support/time.h>
aveitch482a5be2014-12-15 10:25:12 -080044#include <grpc/support/useful.h>
Craig Tiller8ad8a412015-02-25 08:36:40 -080045#include "test/core/util/test_config.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080046
47/* Fills in 'record' of size 'size'. Each byte in record is filled in with the
48 same value. The value is extracted from 'record' pointer. */
Craig Tillera82950e2015-09-22 12:33:20 -070049static void write_record(char *record, size_t size) {
Craig Tiller7536af02015-12-22 13:49:30 -080050 char data = (uintptr_t)record % 255;
Craig Tillera82950e2015-09-22 12:33:20 -070051 memset(record, data, size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052}
53
54/* Reads fixed size records. Returns the number of records read in
55 'num_records'. */
Craig Tillera82950e2015-09-22 12:33:20 -070056static void read_records(size_t record_size, const char *buffer,
Craig Tiller7536af02015-12-22 13:49:30 -080057 size_t buffer_size, int32_t *num_records) {
58 int32_t ix;
Craig Tillera82950e2015-09-22 12:33:20 -070059 GPR_ASSERT(buffer_size >= record_size);
60 GPR_ASSERT(buffer_size % record_size == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080061 *num_records = buffer_size / record_size;
Craig Tillera82950e2015-09-22 12:33:20 -070062 for (ix = 0; ix < *num_records; ++ix) {
63 size_t jx;
64 const char *record = buffer + (record_size * ix);
Craig Tiller7536af02015-12-22 13:49:30 -080065 char data = (uintptr_t)record % 255;
Craig Tillera82950e2015-09-22 12:33:20 -070066 for (jx = 0; jx < record_size; ++jx) {
67 GPR_ASSERT(data == record[jx]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068 }
Craig Tillera82950e2015-09-22 12:33:20 -070069 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070}
71
72/* Tries to write the specified number of records. Stops when the log gets
73 full. Returns the number of records written. Spins for random
74 number of times, up to 'max_spin_count', between writes. */
Craig Tiller7536af02015-12-22 13:49:30 -080075static size_t write_records_to_log(int writer_id, int32_t record_size,
76 int32_t num_records,
77 int32_t max_spin_count) {
78 int32_t ix;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079 int counter = 0;
Craig Tillera82950e2015-09-22 12:33:20 -070080 for (ix = 0; ix < num_records; ++ix) {
Craig Tiller7536af02015-12-22 13:49:30 -080081 int32_t jx;
82 int32_t spin_count = max_spin_count ? rand() % max_spin_count : 0;
Craig Tillera82950e2015-09-22 12:33:20 -070083 char *record;
84 if (counter++ == num_records / 10) {
85 printf(" Writer %d: %d out of %d written\n", writer_id, ix,
86 num_records);
87 counter = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088 }
Craig Tillera82950e2015-09-22 12:33:20 -070089 record = (char *)(census_log_start_write(record_size));
90 if (record == NULL) {
91 return ix;
92 }
93 write_record(record, record_size);
94 census_log_end_write(record, record_size);
95 for (jx = 0; jx < spin_count; ++jx) {
96 GPR_ASSERT(jx >= 0);
97 }
98 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080099 return num_records;
100}
101
102/* Performs a single read iteration. Returns the number of records read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700103static size_t perform_read_iteration(size_t record_size) {
Craig Tiller45724b32015-09-22 10:42:19 -0700104 const void *read_buffer = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800105 size_t bytes_available;
106 size_t records_read = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700107 census_log_init_reader();
108 while ((read_buffer = census_log_read_next(&bytes_available))) {
Craig Tiller7536af02015-12-22 13:49:30 -0800109 int32_t num_records = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700110 read_records(record_size, (const char *)read_buffer, bytes_available,
111 &num_records);
112 records_read += num_records;
113 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800114 return records_read;
115}
116
117/* Asserts that the log is empty. */
Craig Tillera82950e2015-09-22 12:33:20 -0700118static void assert_log_empty(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800119 size_t bytes_available;
Craig Tillera82950e2015-09-22 12:33:20 -0700120 census_log_init_reader();
121 GPR_ASSERT(census_log_read_next(&bytes_available) == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800122}
123
124/* Given log size and record size, computes the minimum usable space. */
Craig Tiller7536af02015-12-22 13:49:30 -0800125static int32_t min_usable_space(size_t log_size, size_t record_size) {
126 int32_t usable_space;
127 int32_t num_blocks =
Craig Tillera82950e2015-09-22 12:33:20 -0700128 GPR_MAX(log_size / CENSUS_LOG_MAX_RECORD_SIZE, gpr_cpu_num_cores());
Craig Tiller7536af02015-12-22 13:49:30 -0800129 int32_t waste_per_block = CENSUS_LOG_MAX_RECORD_SIZE % record_size;
aveitch482a5be2014-12-15 10:25:12 -0800130 /* In the worst case, all except one core-local block is full. */
Craig Tiller7536af02015-12-22 13:49:30 -0800131 int32_t num_full_blocks = num_blocks - 1;
132 usable_space = (int32_t)log_size -
Craig Tillera82950e2015-09-22 12:33:20 -0700133 (num_full_blocks * CENSUS_LOG_MAX_RECORD_SIZE) -
134 ((num_blocks - num_full_blocks) * waste_per_block);
135 GPR_ASSERT(usable_space > 0);
aveitch482a5be2014-12-15 10:25:12 -0800136 return usable_space;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800137}
138
139/* Fills the log and verifies data. If 'no fragmentation' is true, records
140 are sized such that CENSUS_LOG_2_MAX_RECORD_SIZE is a multiple of record
141 size. If not a circular log, verifies that the number of records written
142 match the number of records read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700143static void fill_log(size_t log_size, int no_fragmentation, int circular_log) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800144 int size;
Craig Tiller7536af02015-12-22 13:49:30 -0800145 int32_t records_written;
146 int32_t usable_space;
147 int32_t records_read;
Craig Tillera82950e2015-09-22 12:33:20 -0700148 if (no_fragmentation) {
149 int log2size = rand() % (CENSUS_LOG_2_MAX_RECORD_SIZE + 1);
150 size = (1 << log2size);
151 } else {
152 while (1) {
153 size = 1 + (rand() % CENSUS_LOG_MAX_RECORD_SIZE);
154 if (CENSUS_LOG_MAX_RECORD_SIZE % size) {
155 break;
156 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157 }
Craig Tillera82950e2015-09-22 12:33:20 -0700158 }
159 printf(" Fill record size: %d\n", size);
160 records_written = write_records_to_log(
161 0 /* writer id */, size, (log_size / size) * 2, 0 /* spin count */);
162 usable_space = min_usable_space(log_size, size);
163 GPR_ASSERT(records_written * size >= usable_space);
164 records_read = perform_read_iteration(size);
165 if (!circular_log) {
166 GPR_ASSERT(records_written == records_read);
167 }
168 assert_log_empty();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800169}
170
171/* Structure to pass args to writer_thread */
Craig Tillera82950e2015-09-22 12:33:20 -0700172typedef struct writer_thread_args {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800173 /* Index of this thread in the writers vector. */
174 int index;
175 /* Record size. */
176 size_t record_size;
177 /* Number of records to write. */
Craig Tiller7536af02015-12-22 13:49:30 -0800178 int32_t num_records;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800179 /* Used to signal when writer is complete */
Craig Tiller45724b32015-09-22 10:42:19 -0700180 gpr_cv *done;
181 gpr_mu *mu;
182 int *count;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183} writer_thread_args;
184
185/* Writes the given number of records of random size (up to kMaxRecordSize) and
186 random data to the specified log. */
Craig Tillera82950e2015-09-22 12:33:20 -0700187static void writer_thread(void *arg) {
188 writer_thread_args *args = (writer_thread_args *)arg;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800189 /* Maximum number of times to spin between writes. */
Craig Tiller7536af02015-12-22 13:49:30 -0800190 static const int32_t MAX_SPIN_COUNT = 50;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800191 int records_written = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700192 printf(" Writer: %d\n", args->index);
193 while (records_written < args->num_records) {
194 records_written += write_records_to_log(args->index, args->record_size,
195 args->num_records - records_written,
196 MAX_SPIN_COUNT);
197 if (records_written < args->num_records) {
198 /* Ran out of log space. Sleep for a bit and let the reader catch up.
199 This should never happen for circular logs. */
200 printf(" Writer stalled due to out-of-space: %d out of %d written\n",
201 records_written, args->num_records);
202 gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800203 }
Craig Tillera82950e2015-09-22 12:33:20 -0700204 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800205 /* Done. Decrement count and signal. */
Craig Tillera82950e2015-09-22 12:33:20 -0700206 gpr_mu_lock(args->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800207 (*args->count)--;
Craig Tillera82950e2015-09-22 12:33:20 -0700208 gpr_cv_broadcast(args->done);
209 printf(" Writer done: %d\n", args->index);
210 gpr_mu_unlock(args->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800211}
212
213/* struct to pass args to reader_thread */
Craig Tillera82950e2015-09-22 12:33:20 -0700214typedef struct reader_thread_args {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800215 /* Record size. */
216 size_t record_size;
217 /* Interval between read iterations. */
Craig Tiller7536af02015-12-22 13:49:30 -0800218 int32_t read_iteration_interval_in_msec;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800219 /* Total number of records. */
Craig Tiller7536af02015-12-22 13:49:30 -0800220 int32_t total_records;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800221 /* Signalled when reader should stop. */
222 gpr_cv stop;
223 int stop_flag;
224 /* Used to signal when reader has finished */
Craig Tiller45724b32015-09-22 10:42:19 -0700225 gpr_cv *done;
226 gpr_mu *mu;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800227 int running;
228} reader_thread_args;
229
230/* Reads and verifies the specified number of records. Reader can also be
231 stopped via gpr_cv_signal(&args->stop). Sleeps for 'read_interval_in_msec'
232 between read iterations. */
Craig Tillera82950e2015-09-22 12:33:20 -0700233static void reader_thread(void *arg) {
Craig Tiller7536af02015-12-22 13:49:30 -0800234 int32_t records_read = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700235 reader_thread_args *args = (reader_thread_args *)arg;
Craig Tiller7536af02015-12-22 13:49:30 -0800236 int32_t num_iterations = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800237 gpr_timespec interval;
238 int counter = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700239 printf(" Reader starting\n");
murgatroid99309830f2016-02-05 11:30:00 -0800240 interval = gpr_time_from_micros((int64_t)args->read_iteration_interval_in_msec * 1000,
Craig Tillera82950e2015-09-22 12:33:20 -0700241 GPR_TIMESPAN);
242 gpr_mu_lock(args->mu);
243 while (!args->stop_flag && records_read < args->total_records) {
244 gpr_cv_wait(&args->stop, args->mu, interval);
245 if (!args->stop_flag) {
246 records_read += perform_read_iteration(args->record_size);
247 GPR_ASSERT(records_read <= args->total_records);
248 if (counter++ == 100000) {
249 printf(" Reader: %d out of %d read\n", records_read,
250 args->total_records);
251 counter = 0;
252 }
253 ++num_iterations;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254 }
Craig Tillera82950e2015-09-22 12:33:20 -0700255 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800256 /* Done */
257 args->running = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700258 gpr_cv_broadcast(args->done);
259 printf(" Reader: records: %d, iterations: %d\n", records_read,
260 num_iterations);
261 gpr_mu_unlock(args->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800262}
263
264/* Creates NUM_WRITERS writers where each writer writes NUM_RECORDS_PER_WRITER
265 records. Also, starts a reader that iterates over and reads blocks every
266 READ_ITERATION_INTERVAL_IN_MSEC. */
267/* Number of writers. */
268#define NUM_WRITERS 5
Craig Tillera82950e2015-09-22 12:33:20 -0700269static void multiple_writers_single_reader(int circular_log) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800270 /* Sleep interval between read iterations. */
Craig Tiller7536af02015-12-22 13:49:30 -0800271 static const int32_t READ_ITERATION_INTERVAL_IN_MSEC = 10;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800272 /* Number of records written by each writer. */
Craig Tiller7536af02015-12-22 13:49:30 -0800273 static const int32_t NUM_RECORDS_PER_WRITER = 10 * 1024 * 1024;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800274 /* Maximum record size. */
275 static const size_t MAX_RECORD_SIZE = 10;
276 int ix;
277 gpr_thd_id id;
278 gpr_cv writers_done;
279 int writers_count = NUM_WRITERS;
Craig Tillera82950e2015-09-22 12:33:20 -0700280 gpr_mu writers_mu; /* protects writers_done and writers_count */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800281 writer_thread_args writers[NUM_WRITERS];
282 gpr_cv reader_done;
Craig Tillera82950e2015-09-22 12:33:20 -0700283 gpr_mu reader_mu; /* protects reader_done and reader.running */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800284 reader_thread_args reader;
Craig Tiller7536af02015-12-22 13:49:30 -0800285 int32_t record_size = 1 + rand() % MAX_RECORD_SIZE;
Craig Tillera82950e2015-09-22 12:33:20 -0700286 printf(" Record size: %d\n", record_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287 /* Create and start writers. */
Craig Tillera82950e2015-09-22 12:33:20 -0700288 gpr_cv_init(&writers_done);
289 gpr_mu_init(&writers_mu);
290 for (ix = 0; ix < NUM_WRITERS; ++ix) {
291 writers[ix].index = ix;
292 writers[ix].record_size = record_size;
293 writers[ix].num_records = NUM_RECORDS_PER_WRITER;
294 writers[ix].done = &writers_done;
295 writers[ix].count = &writers_count;
296 writers[ix].mu = &writers_mu;
297 gpr_thd_new(&id, &writer_thread, &writers[ix], NULL);
298 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800299 /* Start reader. */
300 reader.record_size = record_size;
301 reader.read_iteration_interval_in_msec = READ_ITERATION_INTERVAL_IN_MSEC;
302 reader.total_records = NUM_WRITERS * NUM_RECORDS_PER_WRITER;
303 reader.stop_flag = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700304 gpr_cv_init(&reader.stop);
305 gpr_cv_init(&reader_done);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800306 reader.done = &reader_done;
Craig Tillera82950e2015-09-22 12:33:20 -0700307 gpr_mu_init(&reader_mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800308 reader.mu = &reader_mu;
309 reader.running = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700310 gpr_thd_new(&id, &reader_thread, &reader, NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800311 /* Wait for writers to finish. */
Craig Tillera82950e2015-09-22 12:33:20 -0700312 gpr_mu_lock(&writers_mu);
313 while (writers_count != 0) {
314 gpr_cv_wait(&writers_done, &writers_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
315 }
316 gpr_mu_unlock(&writers_mu);
317 gpr_mu_destroy(&writers_mu);
318 gpr_cv_destroy(&writers_done);
319 gpr_mu_lock(&reader_mu);
320 if (circular_log) {
321 /* Stop reader. */
322 reader.stop_flag = 1;
323 gpr_cv_signal(&reader.stop);
324 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325 /* wait for reader to finish */
Craig Tillera82950e2015-09-22 12:33:20 -0700326 while (reader.running) {
327 gpr_cv_wait(&reader_done, &reader_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
328 }
329 if (circular_log) {
330 /* Assert that there were no out-of-space errors. */
331 GPR_ASSERT(0 == census_log_out_of_space_count());
332 }
333 gpr_mu_unlock(&reader_mu);
334 gpr_mu_destroy(&reader_mu);
335 gpr_cv_destroy(&reader_done);
336 printf(" Reader: finished\n");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800337}
338
339/* Log sizes to use for all tests. */
340#define LOG_SIZE_IN_MB 1
341#define LOG_SIZE_IN_BYTES (LOG_SIZE_IN_MB << 20)
342
Craig Tillera82950e2015-09-22 12:33:20 -0700343static void setup_test(int circular_log) {
344 census_log_initialize(LOG_SIZE_IN_MB, circular_log);
345 GPR_ASSERT(census_log_remaining_space() == LOG_SIZE_IN_BYTES);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800346}
347
348/* Attempts to create a record of invalid size (size >
349 CENSUS_LOG_MAX_RECORD_SIZE). */
Craig Tillera82950e2015-09-22 12:33:20 -0700350void test_invalid_record_size(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800351 static const size_t INVALID_SIZE = CENSUS_LOG_MAX_RECORD_SIZE + 1;
352 static const size_t VALID_SIZE = 1;
Craig Tiller45724b32015-09-22 10:42:19 -0700353 void *record;
Craig Tillera82950e2015-09-22 12:33:20 -0700354 printf("Starting test: invalid record size\n");
355 setup_test(0);
356 record = census_log_start_write(INVALID_SIZE);
357 GPR_ASSERT(record == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800358 /* Now try writing a valid record. */
Craig Tillera82950e2015-09-22 12:33:20 -0700359 record = census_log_start_write(VALID_SIZE);
360 GPR_ASSERT(record != NULL);
361 census_log_end_write(record, VALID_SIZE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800362 /* Verifies that available space went down by one block. In theory, this
363 check can fail if the thread is context switched to a new CPU during the
364 start_write execution (multiple blocks get allocated), but this has not
365 been observed in practice. */
Craig Tillera82950e2015-09-22 12:33:20 -0700366 GPR_ASSERT(LOG_SIZE_IN_BYTES - CENSUS_LOG_MAX_RECORD_SIZE ==
367 census_log_remaining_space());
368 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800369}
370
371/* Tests end_write() with a different size than what was specified in
372 start_write(). */
Craig Tillera82950e2015-09-22 12:33:20 -0700373void test_end_write_with_different_size(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800374 static const size_t START_WRITE_SIZE = 10;
375 static const size_t END_WRITE_SIZE = 7;
Craig Tiller45724b32015-09-22 10:42:19 -0700376 void *record_written;
377 const void *record_read;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800378 size_t bytes_available;
Craig Tillera82950e2015-09-22 12:33:20 -0700379 printf("Starting test: end write with different size\n");
380 setup_test(0);
381 record_written = census_log_start_write(START_WRITE_SIZE);
382 GPR_ASSERT(record_written != NULL);
383 census_log_end_write(record_written, END_WRITE_SIZE);
384 census_log_init_reader();
385 record_read = census_log_read_next(&bytes_available);
386 GPR_ASSERT(record_written == record_read);
387 GPR_ASSERT(END_WRITE_SIZE == bytes_available);
388 assert_log_empty();
389 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800390}
391
392/* Verifies that pending records are not available via read_next(). */
Craig Tillera82950e2015-09-22 12:33:20 -0700393void test_read_pending_record(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800394 static const size_t PR_RECORD_SIZE = 1024;
395 size_t bytes_available;
Craig Tiller45724b32015-09-22 10:42:19 -0700396 const void *record_read;
397 void *record_written;
Craig Tillera82950e2015-09-22 12:33:20 -0700398 printf("Starting test: read pending record\n");
399 setup_test(0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800400 /* Start a write. */
Craig Tillera82950e2015-09-22 12:33:20 -0700401 record_written = census_log_start_write(PR_RECORD_SIZE);
402 GPR_ASSERT(record_written != NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800403 /* As write is pending, read should fail. */
Craig Tillera82950e2015-09-22 12:33:20 -0700404 census_log_init_reader();
405 record_read = census_log_read_next(&bytes_available);
406 GPR_ASSERT(record_read == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800407 /* A read followed by end_write() should succeed. */
Craig Tillera82950e2015-09-22 12:33:20 -0700408 census_log_end_write(record_written, PR_RECORD_SIZE);
409 census_log_init_reader();
410 record_read = census_log_read_next(&bytes_available);
411 GPR_ASSERT(record_written == record_read);
412 GPR_ASSERT(PR_RECORD_SIZE == bytes_available);
413 assert_log_empty();
414 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800415}
416
417/* Tries reading beyond pending write. */
Craig Tillera82950e2015-09-22 12:33:20 -0700418void test_read_beyond_pending_record(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800419 /* Start a write. */
Craig Tiller7536af02015-12-22 13:49:30 -0800420 uint32_t incomplete_record_size = 10;
421 uint32_t complete_record_size = 20;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800422 size_t bytes_available;
Craig Tiller45724b32015-09-22 10:42:19 -0700423 void *complete_record;
424 const void *record_read;
425 void *incomplete_record;
Craig Tillera82950e2015-09-22 12:33:20 -0700426 printf("Starting test: read beyond pending record\n");
427 setup_test(0);
428 incomplete_record = census_log_start_write(incomplete_record_size);
429 GPR_ASSERT(incomplete_record != NULL);
430 complete_record = census_log_start_write(complete_record_size);
431 GPR_ASSERT(complete_record != NULL);
432 GPR_ASSERT(complete_record != incomplete_record);
433 census_log_end_write(complete_record, complete_record_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800434 /* Now iterate over blocks to read completed records. */
Craig Tillera82950e2015-09-22 12:33:20 -0700435 census_log_init_reader();
436 record_read = census_log_read_next(&bytes_available);
437 GPR_ASSERT(complete_record == record_read);
438 GPR_ASSERT(complete_record_size == bytes_available);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800439 /* Complete first record. */
Craig Tillera82950e2015-09-22 12:33:20 -0700440 census_log_end_write(incomplete_record, incomplete_record_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800441 /* Have read past the incomplete record, so read_next() should return NULL. */
442 /* NB: this test also assumes our thread did not get switched to a different
443 CPU between the two start_write calls */
Craig Tillera82950e2015-09-22 12:33:20 -0700444 record_read = census_log_read_next(&bytes_available);
445 GPR_ASSERT(record_read == NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800446 /* Reset reader to get the newly completed record. */
Craig Tillera82950e2015-09-22 12:33:20 -0700447 census_log_init_reader();
448 record_read = census_log_read_next(&bytes_available);
449 GPR_ASSERT(incomplete_record == record_read);
450 GPR_ASSERT(incomplete_record_size == bytes_available);
451 assert_log_empty();
452 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800453}
454
455/* Tests scenario where block being read is detached from a core and put on the
456 dirty list. */
Craig Tillera82950e2015-09-22 12:33:20 -0700457void test_detached_while_reading(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800458 static const size_t DWR_RECORD_SIZE = 10;
459 size_t bytes_available;
Craig Tiller45724b32015-09-22 10:42:19 -0700460 const void *record_read;
461 void *record_written;
Craig Tiller7536af02015-12-22 13:49:30 -0800462 uint32_t block_read = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700463 printf("Starting test: detached while reading\n");
464 setup_test(0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800465 /* Start a write. */
Craig Tillera82950e2015-09-22 12:33:20 -0700466 record_written = census_log_start_write(DWR_RECORD_SIZE);
467 GPR_ASSERT(record_written != NULL);
468 census_log_end_write(record_written, DWR_RECORD_SIZE);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800469 /* Read this record. */
Craig Tillera82950e2015-09-22 12:33:20 -0700470 census_log_init_reader();
471 record_read = census_log_read_next(&bytes_available);
472 GPR_ASSERT(record_read != NULL);
473 GPR_ASSERT(DWR_RECORD_SIZE == bytes_available);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800474 /* Now fill the log. This will move the block being read from core-local
475 array to the dirty list. */
Craig Tillera82950e2015-09-22 12:33:20 -0700476 while ((record_written = census_log_start_write(DWR_RECORD_SIZE))) {
477 census_log_end_write(record_written, DWR_RECORD_SIZE);
478 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800479
480 /* In this iteration, read_next() should only traverse blocks in the
481 core-local array. Therefore, we expect at most gpr_cpu_num_cores() more
482 blocks. As log is full, if read_next() is traversing the dirty list, we
483 will get more than gpr_cpu_num_cores() blocks. */
Craig Tillera82950e2015-09-22 12:33:20 -0700484 while ((record_read = census_log_read_next(&bytes_available))) {
485 ++block_read;
486 GPR_ASSERT(block_read <= gpr_cpu_num_cores());
487 }
488 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800489}
490
491/* Fills non-circular log with records sized such that size is a multiple of
492 CENSUS_LOG_MAX_RECORD_SIZE (no per-block fragmentation). */
Craig Tillera82950e2015-09-22 12:33:20 -0700493void test_fill_log_no_fragmentation(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800494 const int circular = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700495 printf("Starting test: fill log no fragmentation\n");
496 setup_test(circular);
497 fill_log(LOG_SIZE_IN_BYTES, 1 /* no fragmentation */, circular);
498 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800499}
500
501/* Fills circular log with records sized such that size is a multiple of
502 CENSUS_LOG_MAX_RECORD_SIZE (no per-block fragmentation). */
Craig Tillera82950e2015-09-22 12:33:20 -0700503void test_fill_circular_log_no_fragmentation(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800504 const int circular = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700505 printf("Starting test: fill circular log no fragmentation\n");
506 setup_test(circular);
507 fill_log(LOG_SIZE_IN_BYTES, 1 /* no fragmentation */, circular);
508 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800509}
510
511/* Fills non-circular log with records that may straddle end of a block. */
Craig Tillera82950e2015-09-22 12:33:20 -0700512void test_fill_log_with_straddling_records(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800513 const int circular = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700514 printf("Starting test: fill log with straddling records\n");
515 setup_test(circular);
516 fill_log(LOG_SIZE_IN_BYTES, 0 /* block straddling records */, circular);
517 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800518}
519
520/* Fills circular log with records that may straddle end of a block. */
Craig Tillera82950e2015-09-22 12:33:20 -0700521void test_fill_circular_log_with_straddling_records(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800522 const int circular = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700523 printf("Starting test: fill circular log with straddling records\n");
524 setup_test(circular);
525 fill_log(LOG_SIZE_IN_BYTES, 0 /* block straddling records */, circular);
526 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800527}
528
529/* Tests scenario where multiple writers and a single reader are using a log
530 that is configured to discard old records. */
Craig Tillera82950e2015-09-22 12:33:20 -0700531void test_multiple_writers_circular_log(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800532 const int circular = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700533 printf("Starting test: multiple writers circular log\n");
534 setup_test(circular);
535 multiple_writers_single_reader(circular);
536 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800537}
538
539/* Tests scenario where multiple writers and a single reader are using a log
540 that is configured to discard old records. */
Craig Tillera82950e2015-09-22 12:33:20 -0700541void test_multiple_writers(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800542 const int circular = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700543 printf("Starting test: multiple writers\n");
544 setup_test(circular);
545 multiple_writers_single_reader(circular);
546 census_log_shutdown();
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800547}
548
aveitch482a5be2014-12-15 10:25:12 -0800549/* Repeat the straddling records and multiple writers tests with a small log. */
Craig Tillera82950e2015-09-22 12:33:20 -0700550void test_small_log(void) {
aveitch482a5be2014-12-15 10:25:12 -0800551 size_t log_size;
552 const int circular = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700553 printf("Starting test: small log\n");
554 census_log_initialize(0, circular);
555 log_size = census_log_remaining_space();
556 GPR_ASSERT(log_size > 0);
557 fill_log(log_size, 0, circular);
558 census_log_shutdown();
559 census_log_initialize(0, circular);
560 multiple_writers_single_reader(circular);
561 census_log_shutdown();
aveitch482a5be2014-12-15 10:25:12 -0800562}
563
Craig Tillera82950e2015-09-22 12:33:20 -0700564void test_performance(void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800565 int write_size = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700566 for (; write_size < CENSUS_LOG_MAX_RECORD_SIZE; write_size *= 2) {
567 gpr_timespec write_time;
568 gpr_timespec start_time;
569 double write_time_micro = 0.0;
570 int nrecords = 0;
571 setup_test(0);
572 start_time = gpr_now(GPR_CLOCK_REALTIME);
573 while (1) {
574 void *record = census_log_start_write(write_size);
575 if (record == NULL) {
576 break;
577 }
578 census_log_end_write(record, write_size);
579 nrecords++;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800580 }
Craig Tillera82950e2015-09-22 12:33:20 -0700581 write_time = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time);
582 write_time_micro = write_time.tv_sec * 1000000 + write_time.tv_nsec / 1000;
583 census_log_shutdown();
584 printf(
585 "Wrote %d %d byte records in %.3g microseconds: %g records/us "
586 "(%g ns/record), %g gigabytes/s\n",
587 nrecords, write_size, write_time_micro, nrecords / write_time_micro,
588 1000 * write_time_micro / nrecords,
589 (write_size * nrecords) / write_time_micro / 1000);
590 }
Craig Tiller190d3602015-02-18 09:23:38 -0800591}