Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 0605995 | 2015-02-18 08:34:56 -0800 | [diff] [blame] | 3 | * Copyright 2015, Google Inc. |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 4 | * 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 | |
nnoble | 8a67b5c | 2014-12-12 10:48:34 -0800 | [diff] [blame] | 34 | #include "src/core/statistics/census_log.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 35 | #include <stdio.h> |
| 36 | #include <stdlib.h> |
| 37 | #include <string.h> |
Craig Tiller | 1d2e219 | 2015-02-09 15:25:21 -0800 | [diff] [blame] | 38 | #include <grpc/support/cpu.h> |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 39 | #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> |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 44 | #include <grpc/support/useful.h> |
Craig Tiller | 8ad8a41 | 2015-02-25 08:36:40 -0800 | [diff] [blame] | 45 | #include "test/core/util/test_config.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 46 | |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 49 | static void write_record(char *record, size_t size) { |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 50 | char data = (uintptr_t)record % 255; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 51 | memset(record, data, size); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | /* Reads fixed size records. Returns the number of records read in |
| 55 | 'num_records'. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 56 | static void read_records(size_t record_size, const char *buffer, |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 57 | size_t buffer_size, int32_t *num_records) { |
| 58 | int32_t ix; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 59 | GPR_ASSERT(buffer_size >= record_size); |
| 60 | GPR_ASSERT(buffer_size % record_size == 0); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 61 | *num_records = buffer_size / record_size; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 62 | for (ix = 0; ix < *num_records; ++ix) { |
| 63 | size_t jx; |
| 64 | const char *record = buffer + (record_size * ix); |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 65 | char data = (uintptr_t)record % 255; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 66 | for (jx = 0; jx < record_size; ++jx) { |
| 67 | GPR_ASSERT(data == record[jx]); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 68 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 69 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 70 | } |
| 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 Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 75 | static 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 79 | int counter = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 80 | for (ix = 0; ix < num_records; ++ix) { |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 81 | int32_t jx; |
| 82 | int32_t spin_count = max_spin_count ? rand() % max_spin_count : 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 83 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 88 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 89 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 99 | return num_records; |
| 100 | } |
| 101 | |
| 102 | /* Performs a single read iteration. Returns the number of records read. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 103 | static size_t perform_read_iteration(size_t record_size) { |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 104 | const void *read_buffer = NULL; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 105 | size_t bytes_available; |
| 106 | size_t records_read = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 107 | census_log_init_reader(); |
| 108 | while ((read_buffer = census_log_read_next(&bytes_available))) { |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 109 | int32_t num_records = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 110 | read_records(record_size, (const char *)read_buffer, bytes_available, |
| 111 | &num_records); |
| 112 | records_read += num_records; |
| 113 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 114 | return records_read; |
| 115 | } |
| 116 | |
| 117 | /* Asserts that the log is empty. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 118 | static void assert_log_empty(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 119 | size_t bytes_available; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 120 | census_log_init_reader(); |
| 121 | GPR_ASSERT(census_log_read_next(&bytes_available) == NULL); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | /* Given log size and record size, computes the minimum usable space. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 125 | static int32_t min_usable_space(size_t log_size, size_t record_size) { |
| 126 | int32_t usable_space; |
| 127 | int32_t num_blocks = |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 128 | GPR_MAX(log_size / CENSUS_LOG_MAX_RECORD_SIZE, gpr_cpu_num_cores()); |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 129 | int32_t waste_per_block = CENSUS_LOG_MAX_RECORD_SIZE % record_size; |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 130 | /* In the worst case, all except one core-local block is full. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 131 | int32_t num_full_blocks = num_blocks - 1; |
| 132 | usable_space = (int32_t)log_size - |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 133 | (num_full_blocks * CENSUS_LOG_MAX_RECORD_SIZE) - |
| 134 | ((num_blocks - num_full_blocks) * waste_per_block); |
| 135 | GPR_ASSERT(usable_space > 0); |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 136 | return usable_space; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 137 | } |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 143 | static void fill_log(size_t log_size, int no_fragmentation, int circular_log) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 144 | int size; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 145 | int32_t records_written; |
| 146 | int32_t usable_space; |
| 147 | int32_t records_read; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 148 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 157 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 158 | } |
| 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | /* Structure to pass args to writer_thread */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 172 | typedef struct writer_thread_args { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 173 | /* 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 Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 178 | int32_t num_records; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 179 | /* Used to signal when writer is complete */ |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 180 | gpr_cv *done; |
| 181 | gpr_mu *mu; |
| 182 | int *count; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 183 | } 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 187 | static void writer_thread(void *arg) { |
| 188 | writer_thread_args *args = (writer_thread_args *)arg; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 189 | /* Maximum number of times to spin between writes. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 190 | static const int32_t MAX_SPIN_COUNT = 50; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 191 | int records_written = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 192 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 203 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 204 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 205 | /* Done. Decrement count and signal. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 206 | gpr_mu_lock(args->mu); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 207 | (*args->count)--; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 208 | gpr_cv_broadcast(args->done); |
| 209 | printf(" Writer done: %d\n", args->index); |
| 210 | gpr_mu_unlock(args->mu); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | /* struct to pass args to reader_thread */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 214 | typedef struct reader_thread_args { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 215 | /* Record size. */ |
| 216 | size_t record_size; |
| 217 | /* Interval between read iterations. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 218 | int32_t read_iteration_interval_in_msec; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 219 | /* Total number of records. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 220 | int32_t total_records; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 221 | /* Signalled when reader should stop. */ |
| 222 | gpr_cv stop; |
| 223 | int stop_flag; |
| 224 | /* Used to signal when reader has finished */ |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 225 | gpr_cv *done; |
| 226 | gpr_mu *mu; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 227 | 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 233 | static void reader_thread(void *arg) { |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 234 | int32_t records_read = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 235 | reader_thread_args *args = (reader_thread_args *)arg; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 236 | int32_t num_iterations = 0; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 237 | gpr_timespec interval; |
| 238 | int counter = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 239 | printf(" Reader starting\n"); |
murgatroid99 | 309830f | 2016-02-05 11:30:00 -0800 | [diff] [blame^] | 240 | interval = gpr_time_from_micros((int64_t)args->read_iteration_interval_in_msec * 1000, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 241 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 254 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 255 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 256 | /* Done */ |
| 257 | args->running = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 258 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 262 | } |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 269 | static void multiple_writers_single_reader(int circular_log) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 270 | /* Sleep interval between read iterations. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 271 | static const int32_t READ_ITERATION_INTERVAL_IN_MSEC = 10; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 272 | /* Number of records written by each writer. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 273 | static const int32_t NUM_RECORDS_PER_WRITER = 10 * 1024 * 1024; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 274 | /* 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 280 | gpr_mu writers_mu; /* protects writers_done and writers_count */ |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 281 | writer_thread_args writers[NUM_WRITERS]; |
| 282 | gpr_cv reader_done; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 283 | gpr_mu reader_mu; /* protects reader_done and reader.running */ |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 284 | reader_thread_args reader; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 285 | int32_t record_size = 1 + rand() % MAX_RECORD_SIZE; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 286 | printf(" Record size: %d\n", record_size); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 287 | /* Create and start writers. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 288 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 299 | /* 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 304 | gpr_cv_init(&reader.stop); |
| 305 | gpr_cv_init(&reader_done); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 306 | reader.done = &reader_done; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 307 | gpr_mu_init(&reader_mu); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 308 | reader.mu = &reader_mu; |
| 309 | reader.running = 1; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 310 | gpr_thd_new(&id, &reader_thread, &reader, NULL); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 311 | /* Wait for writers to finish. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 312 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 325 | /* wait for reader to finish */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 326 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 337 | } |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 343 | static 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | /* Attempts to create a record of invalid size (size > |
| 349 | CENSUS_LOG_MAX_RECORD_SIZE). */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 350 | void test_invalid_record_size(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 351 | static const size_t INVALID_SIZE = CENSUS_LOG_MAX_RECORD_SIZE + 1; |
| 352 | static const size_t VALID_SIZE = 1; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 353 | void *record; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 354 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 358 | /* Now try writing a valid record. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 359 | record = census_log_start_write(VALID_SIZE); |
| 360 | GPR_ASSERT(record != NULL); |
| 361 | census_log_end_write(record, VALID_SIZE); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 362 | /* 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 366 | GPR_ASSERT(LOG_SIZE_IN_BYTES - CENSUS_LOG_MAX_RECORD_SIZE == |
| 367 | census_log_remaining_space()); |
| 368 | census_log_shutdown(); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 369 | } |
| 370 | |
| 371 | /* Tests end_write() with a different size than what was specified in |
| 372 | start_write(). */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 373 | void test_end_write_with_different_size(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 374 | static const size_t START_WRITE_SIZE = 10; |
| 375 | static const size_t END_WRITE_SIZE = 7; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 376 | void *record_written; |
| 377 | const void *record_read; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 378 | size_t bytes_available; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 379 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 390 | } |
| 391 | |
| 392 | /* Verifies that pending records are not available via read_next(). */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 393 | void test_read_pending_record(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 394 | static const size_t PR_RECORD_SIZE = 1024; |
| 395 | size_t bytes_available; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 396 | const void *record_read; |
| 397 | void *record_written; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 398 | printf("Starting test: read pending record\n"); |
| 399 | setup_test(0); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 400 | /* Start a write. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 401 | record_written = census_log_start_write(PR_RECORD_SIZE); |
| 402 | GPR_ASSERT(record_written != NULL); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 403 | /* As write is pending, read should fail. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 404 | census_log_init_reader(); |
| 405 | record_read = census_log_read_next(&bytes_available); |
| 406 | GPR_ASSERT(record_read == NULL); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 407 | /* A read followed by end_write() should succeed. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 408 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 415 | } |
| 416 | |
| 417 | /* Tries reading beyond pending write. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 418 | void test_read_beyond_pending_record(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 419 | /* Start a write. */ |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 420 | uint32_t incomplete_record_size = 10; |
| 421 | uint32_t complete_record_size = 20; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 422 | size_t bytes_available; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 423 | void *complete_record; |
| 424 | const void *record_read; |
| 425 | void *incomplete_record; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 426 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 434 | /* Now iterate over blocks to read completed records. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 435 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 439 | /* Complete first record. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 440 | census_log_end_write(incomplete_record, incomplete_record_size); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 441 | /* 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 444 | record_read = census_log_read_next(&bytes_available); |
| 445 | GPR_ASSERT(record_read == NULL); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 446 | /* Reset reader to get the newly completed record. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 447 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 453 | } |
| 454 | |
| 455 | /* Tests scenario where block being read is detached from a core and put on the |
| 456 | dirty list. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 457 | void test_detached_while_reading(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 458 | static const size_t DWR_RECORD_SIZE = 10; |
| 459 | size_t bytes_available; |
Craig Tiller | 45724b3 | 2015-09-22 10:42:19 -0700 | [diff] [blame] | 460 | const void *record_read; |
| 461 | void *record_written; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 462 | uint32_t block_read = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 463 | printf("Starting test: detached while reading\n"); |
| 464 | setup_test(0); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 465 | /* Start a write. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 466 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 469 | /* Read this record. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 470 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 474 | /* Now fill the log. This will move the block being read from core-local |
| 475 | array to the dirty list. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 476 | while ((record_written = census_log_start_write(DWR_RECORD_SIZE))) { |
| 477 | census_log_end_write(record_written, DWR_RECORD_SIZE); |
| 478 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 479 | |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 484 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 489 | } |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 493 | void test_fill_log_no_fragmentation(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 494 | const int circular = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 495 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 499 | } |
| 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 Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 503 | void test_fill_circular_log_no_fragmentation(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 504 | const int circular = 1; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 505 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | /* Fills non-circular log with records that may straddle end of a block. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 512 | void test_fill_log_with_straddling_records(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 513 | const int circular = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 514 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 518 | } |
| 519 | |
| 520 | /* Fills circular log with records that may straddle end of a block. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 521 | void test_fill_circular_log_with_straddling_records(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 522 | const int circular = 1; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 523 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 527 | } |
| 528 | |
| 529 | /* Tests scenario where multiple writers and a single reader are using a log |
| 530 | that is configured to discard old records. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 531 | void test_multiple_writers_circular_log(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 532 | const int circular = 1; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 533 | printf("Starting test: multiple writers circular log\n"); |
| 534 | setup_test(circular); |
| 535 | multiple_writers_single_reader(circular); |
| 536 | census_log_shutdown(); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 537 | } |
| 538 | |
| 539 | /* Tests scenario where multiple writers and a single reader are using a log |
| 540 | that is configured to discard old records. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 541 | void test_multiple_writers(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 542 | const int circular = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 543 | printf("Starting test: multiple writers\n"); |
| 544 | setup_test(circular); |
| 545 | multiple_writers_single_reader(circular); |
| 546 | census_log_shutdown(); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 547 | } |
| 548 | |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 549 | /* Repeat the straddling records and multiple writers tests with a small log. */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 550 | void test_small_log(void) { |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 551 | size_t log_size; |
| 552 | const int circular = 0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 553 | 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(); |
aveitch | 482a5be | 2014-12-15 10:25:12 -0800 | [diff] [blame] | 562 | } |
| 563 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 564 | void test_performance(void) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 565 | int write_size = 1; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 566 | 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 Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 580 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 581 | 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 Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 591 | } |