throughput.c (6401B)
1 /* See LICENSE for license details. */ 2 /* TODO(rnp): 3 * [ ]: for finer grained evaluation of throughput latency just queue a data upload 4 * without replacing the data. 5 * [ ]: bug: we aren't inserting rf data between each frame 6 */ 7 8 #include "test_common.c" 9 10 global iv3 g_output_points = {{512, 1, 1024}}; 11 global v2 g_axial_extent = {{ 10e-3f, 165e-3f}}; 12 global v2 g_lateral_extent = {{-60e-3f, 60e-3f}}; 13 global f32 g_f_number = 0.5f; 14 15 typedef struct { 16 b32 loop; 17 u32 frame_number; 18 19 char **remaining; 20 i32 remaining_count; 21 } Options; 22 23 global b32 g_should_exit; 24 25 function void 26 usage(char *argv0) 27 { 28 die("%s [--loop] [--frame n] parameters_file\n" 29 " --loop: reupload data forever\n" 30 " --frame n: use frame n of the data for display\n", 31 argv0); 32 } 33 34 function Options 35 parse_argv(i32 argc, char *argv[]) 36 { 37 Options result = {0}; 38 39 char *argv0 = argv[0]; 40 shift(argv, argc); 41 42 while (argc > 0) { 43 str8 arg = str8_from_c_str(*argv); 44 45 if (str8_equal(arg, str8("--loop"))) { 46 shift(argv, argc); 47 result.loop = 1; 48 } else if (str8_equal(arg, str8("--frame"))) { 49 shift(argv, argc); 50 if (argc) { 51 result.frame_number = (u32)atoi(*argv); 52 shift(argv, argc); 53 } 54 } else if (arg.length > 0 && arg.data[0] == '-') { 55 usage(argv0); 56 } else { 57 break; 58 } 59 } 60 61 result.remaining = argv; 62 result.remaining_count = argc; 63 64 return result; 65 } 66 67 function b32 68 send_frame(void *restrict data, BeamformerSimpleParameters *restrict bp, BeamformerViewPlaneTag tag, u32 slot) 69 { 70 u32 data_size = bp->raw_data_dimensions.E[0] * bp->raw_data_dimensions.E[1] 71 * beamformer_data_kind_byte_size[bp->data_kind]; 72 b32 result = beamformer_push_data_with_compute(data, data_size, tag, slot); 73 if (!result && !g_should_exit) printf("lib error: %s\n", beamformer_get_last_error_string()); 74 75 return result; 76 } 77 78 function void 79 execute_study(Arena *arena, Stream path, Options *options) 80 { 81 i32 path_work_index = path.widx; 82 stream_ensure_termination(&path, 0); 83 84 ZBP_Data raw_data = {0}; 85 BeamformerSimpleParameters bp = {0}; 86 if (!beamformer_simple_parameters_from_zbp_file(arena, &bp, (char *)path.data, &raw_data, 0)) 87 die("failed to load parameters file: %s\n", (char *)path.data); 88 stream_reset(&path, path_work_index); 89 90 v2 min_coordinate = (v2){{g_lateral_extent.x, g_axial_extent.x}}; 91 v2 max_coordinate = (v2){{g_lateral_extent.y, g_axial_extent.y}}; 92 if (RXOrientation(bp.transmit_receive_orientation) == ZBP_RCAOrientation_Rows) 93 bp.das_voxel_transform = das_transform_2d_yz(min_coordinate, max_coordinate, 0); 94 else 95 bp.das_voxel_transform = das_transform_2d_xz(min_coordinate, max_coordinate, 0); 96 97 bp.output_points.x = g_output_points.x; 98 bp.output_points.y = g_output_points.z; 99 bp.output_points.z = 1; 100 bp.output_points.w = 1; 101 102 bp.f_number = g_f_number; 103 bp.interpolation_mode = BeamformerInterpolationMode_Cubic; 104 105 bp.decimation_rate = 1; 106 107 if (bp.data_kind != BeamformerDataKind_Float32Complex && 108 bp.data_kind != BeamformerDataKind_Int16Complex) 109 { 110 bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_Demodulate; 111 } 112 bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_Decode; 113 bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_DAS; 114 115 BeamformerFilterParameters filter = {.sampling_frequency = bp.sampling_frequency / 2}; 116 { 117 BeamformerEmissionParameters *ep = &bp.emission_parameters; 118 switch (bp.emission_parameters.kind) { 119 120 case BeamformerEmissionKind_Sine:{ 121 filter.kind = BeamformerFilterKind_Kaiser; 122 filter.kaiser.beta = 5.65f; 123 filter.kaiser.cutoff_frequency = 0.5f * ep->sine.frequency; 124 filter.kaiser.length = 36; 125 }break; 126 127 case BeamformerEmissionKind_Chirp:{ 128 filter.kind = BeamformerFilterKind_MatchedChirp; 129 filter.matched_chirp.duration = ep->chirp.duration; 130 filter.matched_chirp.min_frequency = ep->chirp.min_frequency - bp.demodulation_frequency; 131 filter.matched_chirp.max_frequency = ep->chirp.max_frequency - bp.demodulation_frequency; 132 filter.complex = 1; 133 134 //bp.time_offset += ep->chirp.duration / 2; 135 }break; 136 137 InvalidDefaultCase; 138 } 139 140 beamformer_create_filter(&filter, 0, 0); 141 142 bp.compute_stage_parameters[0] = 0; 143 } 144 145 beamformer_push_simple_parameters(&bp); 146 147 beamformer_set_global_timeout(1000); 148 149 void *data = zbp_data_pointer(arena, &raw_data, path, options->frame_number); 150 151 if (options->loop) { 152 BeamformerLiveImagingParameters lip = { 153 .active = 1, 154 .acquisition_kind = bp.acquisition_kind, 155 .save_enabled = 1, 156 .acquisition_kind_enabled_flags = 1 << bp.acquisition_kind, 157 }; 158 159 str8 short_name = str8("Throughput"); 160 memory_copy(lip.save_name_tag, short_name.data, (u64)short_name.length); 161 lip.save_name_tag_length = (i32)short_name.length; 162 beamformer_set_live_parameters(&lip); 163 164 u32 frame = 0; 165 f32 times[32] = {0}; 166 f32 data_size = (f32)(bp.raw_data_dimensions.E[0] * bp.raw_data_dimensions.E[1] 167 * beamformer_data_kind_byte_size[bp.data_kind]); 168 u64 start = os_timer_count(); 169 f64 frequency = os_timer_frequency(); 170 for (;!g_should_exit;) { 171 if (send_frame(data, &bp, BeamformerViewPlaneTag_XZ, 0)) { 172 u64 now = os_timer_count(); 173 f64 delta = (now - start) / frequency; 174 start = now; 175 176 if ((frame % 16) == 0) { 177 f32 sum = 0; 178 for (u32 i = 0; i < countof(times); i++) 179 sum += times[i] / countof(times); 180 printf("Frame Time: %8.3f [ms] | 32-Frame Average: %8.3f [ms] | %8.3f GB/s\n", 181 delta * 1e3, sum * 1e3, data_size / (sum * (GB(1)))); 182 } 183 184 times[frame % countof(times)] = delta; 185 frame++; 186 } 187 i32 flag = beamformer_live_parameters_get_dirty_flag(); 188 if (flag != -1 && (1 << flag) == BeamformerLiveImagingDirtyFlags_StopImaging) 189 break; 190 } 191 192 lip.active = 0; 193 beamformer_set_live_parameters(&lip); 194 } else { 195 send_frame(data, &bp, BeamformerViewPlaneTag_XZ, 0); 196 } 197 } 198 199 function void 200 sigint(i32 _signo) 201 { 202 g_should_exit = 1; 203 } 204 205 BASE_IMPORT void 206 entry_point(i32 argc, char *argv[]) 207 { 208 Options options = parse_argv(argc, argv); 209 210 if (options.remaining_count != 1) 211 usage(argv[0]); 212 213 signal(SIGINT, sigint); 214 215 Arena *arena = arena_create(); 216 Stream path = stream_alloc(arena, KB(4)); 217 stream_append_str8(&path, str8_from_c_str(options.remaining[0])); 218 219 execute_study(arena, path, &options); 220 }