decode.c (9073B)
1 /* See LICENSE for license details. */ 2 #define BASE_EXPORT function 3 #define BASE_IMPORT function 4 #define BEAMFORMER_LIB_EXPORT function 5 #include "base_platform.h" 6 #include "ogl_beamformer_lib.c" 7 8 #include <signal.h> 9 #include <stdarg.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 13 #define AVERAGE_SAMPLES countof(((BeamformerComputeStatsTable *)0)->times) 14 //#define RF_TIME_SAMPLES 2432 15 #define RF_TIME_SAMPLES 4096 16 17 read_only global u32 decode_transmit_counts[] = { 18 2, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96, 128, 160, 192, 256 19 }; 20 21 typedef struct { 22 b32 loop; 23 b32 once; 24 b32 dump; 25 b32 full_aperture; 26 27 u32 warmup_count; 28 29 char *outdir; 30 31 char **remaining; 32 i32 remaining_count; 33 } Options; 34 35 global b32 g_should_exit; 36 37 #define die(...) die_((char *)__func__, __VA_ARGS__) 38 function no_return void 39 die_(char *function_name, char *format, ...) 40 { 41 if (function_name) 42 fprintf(stderr, "%s: ", function_name); 43 44 va_list ap; 45 46 va_start(ap, format); 47 vfprintf(stderr, format, ap); 48 va_end(ap); 49 50 os_exit(1); 51 } 52 53 #if OS_LINUX 54 55 function void 56 os_make_directory(char *name) 57 { 58 mkdir(name, 0770); 59 } 60 61 #elif OS_WINDOWS 62 63 W32(b32) CreateDirectoryA(c8 *, void *); 64 65 function void 66 os_make_directory(char *name) 67 { 68 CreateDirectoryA(name, 0); 69 } 70 71 #else 72 #error Unsupported Platform 73 #endif 74 75 #define shift_n(v, c, n) v += n, c -= n 76 #define shift(v, c) shift_n(v, c, 1) 77 #define unshift(v, c) shift_n(v, c, -1) 78 79 function void 80 usage(char *argv0) 81 { 82 die("%s [--loop] [--once] [--full-aperture] [--warmup n] [--dump dir]\n" 83 " --loop: reupload data forever\n" 84 " --once: only run a single frame\n" 85 " --full-aperture: recieve on full 256 channel aperture\n" 86 " --warmup: warmup with n runs\n" 87 " --dump: dump output stats files to dir\n", 88 argv0); 89 } 90 91 function Options 92 parse_argv(i32 argc, char *argv[]) 93 { 94 Options result = {0}; 95 96 char *argv0 = argv[0]; 97 shift(argv, argc); 98 99 while (argc > 0) { 100 str8 arg = str8_from_c_str(*argv); 101 shift(argv, argc); 102 103 if (str8_equal(arg, str8("--loop"))) { 104 result.loop = 1; 105 } else if (str8_equal(arg, str8("--full-aperture"))) { 106 result.full_aperture = 1; 107 } else if (str8_equal(arg, str8("--dump"))) { 108 if (argc) { 109 result.outdir = *argv; 110 result.dump = 1; 111 shift(argv, argc); 112 } else { 113 die("expected directory to dump to\n"); 114 } 115 } else if (str8_equal(arg, str8("--once"))) { 116 result.once = 1; 117 } else if (str8_equal(arg, str8("--warmup"))) { 118 if (argc) { 119 result.warmup_count = (u32)atoi(*argv); 120 shift(argv, argc); 121 } 122 } else if (arg.length > 0 && arg.data[0] == '-') { 123 usage(argv0); 124 } else { 125 unshift(argv, argc); 126 break; 127 } 128 } 129 130 result.remaining = argv; 131 result.remaining_count = argc; 132 133 return result; 134 } 135 136 function b32 137 send_frame(i16 *restrict i16_data, u32 data_size) 138 { 139 b32 result = beamformer_push_data_with_compute(i16_data, data_size, BeamformerViewPlaneTag_XZ, 0); 140 if (!result && !g_should_exit) printf("lib error: %s\n", beamformer_get_last_error_string()); 141 return result; 142 } 143 144 function uv4 145 decoded_data_dim(u32 transmit_count, b32 full_aperture) 146 { 147 u32 max_transmits = decode_transmit_counts[countof(decode_transmit_counts) - 1]; 148 uv4 result = {{RF_TIME_SAMPLES, full_aperture? max_transmits: transmit_count, transmit_count, 1}}; 149 return result; 150 } 151 152 function uv2 153 raw_data_dim(u32 transmit_count, b32 full_aperture) 154 { 155 uv4 dec = decoded_data_dim(transmit_count, full_aperture); 156 uv2 result = {{dec.x * transmit_count, 256}}; 157 return result; 158 } 159 160 function u32 161 data_size_for_transmit_count(u32 transmit_count, b32 full_aperture) 162 { 163 uv2 rf_dim = raw_data_dim(transmit_count, full_aperture); 164 u32 result = rf_dim.x * rf_dim.y * sizeof(i16); 165 return result; 166 } 167 168 function i16 * 169 generate_test_data_for_transmit_count(u32 transmit_count, b32 full_aperture) 170 { 171 u64 rf_size = data_size_for_transmit_count(transmit_count, full_aperture); 172 i16 *result = malloc(rf_size); 173 if (!result) die("malloc\n"); 174 return result; 175 } 176 177 function void 178 dump_stats(BeamformerComputeStatsTable *stats, Options *options, u32 transmit_count) 179 { 180 char path_buffer[1024]; 181 Stream sb = {.data = (u8 *)path_buffer, .cap = sizeof(path_buffer)}; 182 stream_append_str8s(&sb, str8_from_c_str(options->outdir), str8(OS_PATH_SEPARATOR "decode_")); 183 stream_append_u64(&sb, transmit_count); 184 stream_append_str8(&sb, str8(".bin")); 185 stream_append_byte(&sb, 0); 186 os_write_new_file(path_buffer, str8_struct(stats)); 187 } 188 189 function void 190 send_parameters(Options *options, u32 transmit_count) 191 { 192 BeamformerParameters bp = {0}; 193 bp.decode_mode = BeamformerDecodeMode_Hadamard; 194 b32 full_aperture = options->full_aperture; 195 uv3 dec_data_dim = decoded_data_dim(transmit_count, full_aperture).xyz; 196 bp.sample_count = dec_data_dim.x; 197 bp.channel_count = dec_data_dim.y; 198 bp.acquisition_count = dec_data_dim.z; 199 200 bp.raw_data_dimensions = raw_data_dim(transmit_count, full_aperture); 201 beamformer_push_parameters(&bp); 202 203 /* NOTE(rnp): use real channel mapping so that we still get ~random~ access pattern */ 204 read_only local_persist i16 channel_mapping[] = { 205 217, 129, 212, 188, 255, 131, 237, 190, 241, 130, 248, 187, 219, 128, 218, 181, 206 216, 134, 247, 180, 220, 132, 238, 178, 246, 133, 240, 179, 221, 135, 239, 173, 207 231, 137, 211, 172, 222, 139, 213, 170, 249, 138, 210, 171, 223, 136, 232, 189, 208 233, 142, 209, 164, 224, 140, 214, 186, 254, 141, 208, 163, 225, 143, 215, 185, 209 230, 145, 204, 162, 226, 147, 206, 165, 229, 146, 207, 161, 227, 144, 205, 182, 210 234, 150, 203, 160, 228, 148, 201, 166, 236, 149, 200, 159, 235, 175, 202, 177, 211 242, 151, 196, 191, 243, 155, 198, 167, 245, 154, 199, 158, 244, 176, 197, 174, 212 250, 168, 195, 184, 251, 156, 193, 152, 253, 153, 192, 157, 252, 183, 194, 169, 213 102, 62, 71, 3, 100, 60, 82, 1, 78, 61, 72, 4, 64, 63, 101, 10, 214 103, 57, 107, 11, 99, 59, 81, 13, 73, 58, 79, 12, 98, 56, 80, 18, 215 88, 54, 108, 19, 97, 52, 106, 21, 70, 53, 109, 20, 96, 55, 87, 2, 216 86, 49, 110, 27, 95, 51, 105, 5, 65, 50, 111, 28, 94, 48, 104, 6, 217 89, 46, 115, 29, 93, 44, 113, 26, 90, 45, 112, 30, 92, 47, 114, 9, 218 85, 41, 116, 31, 91, 43, 118, 25, 83, 42, 119, 32, 84, 16, 117, 14, 219 77, 40, 123, 0, 76, 36, 121, 24, 74, 37, 120, 33, 75, 15, 122, 17, 220 69, 23, 124, 7, 68, 35, 126, 39, 66, 38, 127, 34, 67, 8, 125, 22, 221 }; 222 beamformer_push_channel_mapping(channel_mapping, countof(channel_mapping)); 223 224 i32 shader_stages = BeamformerShaderKind_Decode; 225 beamformer_push_pipeline(&shader_stages, 1, BeamformerDataKind_Int16); 226 beamformer_set_global_timeout(1000); 227 } 228 229 function f32 230 execute_study(Options *options, u32 transmit_count, i16 *restrict data) 231 { 232 send_parameters(options, transmit_count); 233 u32 data_size = data_size_for_transmit_count(transmit_count, options->full_aperture); 234 for (u32 i = 0; !g_should_exit && i < options->warmup_count; i++) 235 send_frame(data, data_size); 236 237 u64 start = os_timer_count(); 238 f64 frequency = os_timer_frequency(); 239 for (u32 i = 0; !g_should_exit && i < AVERAGE_SAMPLES; i++) 240 send_frame(data, data_size); 241 f32 result = (os_timer_count() - start) / frequency / (f32)AVERAGE_SAMPLES; 242 243 return result; 244 } 245 246 function void 247 print_result(u32 transmit_count, f32 time) 248 { 249 printf("decode %3u | %uF Average: %8.3f [ms]\n", transmit_count, (u32)AVERAGE_SAMPLES, time * 1e3); 250 } 251 252 function void 253 sigint(i32 _signo) 254 { 255 g_should_exit = 1; 256 } 257 258 BASE_IMPORT void 259 entry_point(i32 argc, char *argv[]) 260 { 261 Options options = parse_argv(argc, argv); 262 263 if (options.remaining_count) 264 usage(argv[0]); 265 266 if (options.dump) os_make_directory(options.outdir); 267 268 signal(SIGINT, sigint); 269 270 BeamformerLiveImagingParameters lip = {.active = 1, .save_enabled = 1}; 271 str8 short_name = str8("Decode Bench"); 272 memory_copy(lip.save_name_tag, short_name.data, (u64)short_name.length); 273 lip.save_name_tag_length = (i32)short_name.length; 274 beamformer_set_live_parameters(&lip); 275 276 u32 max_transmit_count = decode_transmit_counts[countof(decode_transmit_counts) - 1]; 277 i16 *data = generate_test_data_for_transmit_count(max_transmit_count, options.full_aperture); 278 if (options.loop) { 279 for (;!g_should_exit;) { 280 u32 transmit_count = decode_transmit_counts[0]; 281 f32 time = execute_study(&options, transmit_count, data); 282 if (!g_should_exit) print_result(transmit_count, time); 283 } 284 } else if (options.once) { 285 u32 transmit_count = decode_transmit_counts[0]; 286 u32 data_size = data_size_for_transmit_count(transmit_count, options.full_aperture); 287 send_parameters(&options, transmit_count); 288 send_frame(data, data_size); 289 } else { 290 BeamformerComputeStatsTable stats = {0}; 291 for (i64 i = 0; i < countof(decode_transmit_counts); i++) { 292 u32 transmit_count = decode_transmit_counts[i]; 293 f32 time = execute_study(&options, transmit_count, data); 294 if (options.dump) { 295 beamformer_compute_timings(&stats, 1000); 296 dump_stats(&stats, &options, transmit_count); 297 } 298 if (!g_should_exit) print_result(transmit_count, time); 299 } 300 } 301 302 lip.active = 0; 303 beamformer_set_live_parameters(&lip); 304 }