1 /*
2 * Copyright (c) 2013-2021, The OSKAR Developers.
3 * See the LICENSE file at the top-level directory of this distribution.
4 */
5
6 #include "settings/oskar_option_parser.h"
7 #include "math/oskar_cmath.h"
8 #include "math/oskar_dftw.h"
9 #include "utility/oskar_get_error_string.h"
10 #include "utility/oskar_timer.h"
11 #include "utility/oskar_device.h"
12 #include "oskar_version.h"
13
14 #include <cstdlib>
15 #include <cstdio>
16
17 enum OpType { C2C, M2M, UNDEF };
18
19 int benchmark(int num_elements, int num_directions, int num_element_types,
20 OpType op_type, int loc, int precision, bool evaluate_2d, int niter,
21 double& time_taken);
22
23
main(int argc,char ** argv)24 int main(int argc, char** argv)
25 {
26 oskar::OptionParser opt("oskar_array_pattern_benchmark", OSKAR_VERSION_STR);
27 opt.add_required("No. array elements");
28 opt.add_required("No. directions");
29 opt.add_flag("-sp", "Use single precision (default: double precision)");
30 opt.add_flag("-g", "Run on the GPU");
31 opt.add_flag("-c", "Run on the CPU");
32 opt.add_flag("-cl", "Run using OpenCL");
33 opt.add_flag("-c2c", "Beam pattern using complex inputs (complex to complex DFT)");
34 opt.add_flag("-m2m", "Beam pattern using complex, polarised inputs (complex matrix to matrix DFT)");
35 opt.add_flag("-2d", "Use a 2-dimensional phase term (default: 3D)");
36 opt.add_flag("-n", "Number of iterations", 1, "1");
37 opt.add_flag("-e", "Number of element types", 1, "1");
38 opt.add_flag("-v", "Display verbose output.");
39
40 if (!opt.check_options(argc, argv)) return EXIT_FAILURE;
41
42 int num_elements = atoi(opt.get_arg(0));
43 int num_directions = atoi(opt.get_arg(1));
44 OpType op_type = UNDEF;
45 int op_type_count = 0;
46 if (opt.is_set("-c2c"))
47 {
48 op_type = C2C;
49 op_type_count++;
50 }
51 if (opt.is_set("-m2m"))
52 {
53 op_type = M2M;
54 op_type_count++;
55 }
56
57 int location = -1;
58 if (opt.is_set("-g")) location = OSKAR_GPU;
59 if (opt.is_set("-c")) location = OSKAR_CPU;
60 if (opt.is_set("-cl")) location = OSKAR_CL;
61 if (location < 0)
62 {
63 opt.error("Please select one of -g, -c or -cl");
64 return EXIT_FAILURE;
65 }
66
67 int precision = opt.is_set("-sp") ? OSKAR_SINGLE : OSKAR_DOUBLE;
68 bool evaluate_2d = opt.is_set("-2d") ? true : false;
69 int niter = opt.get_int("-n");
70 int num_element_types = opt.get_int("-e");
71
72 if (op_type == UNDEF || op_type_count != 1)
73 {
74 opt.error("Please select one of the following flags: -o2c, -c2c, -m2m");
75 return EXIT_FAILURE;
76 }
77
78 if (opt.is_set("-v"))
79 {
80 printf("\n");
81 printf("- Number of elements: %i\n", num_elements);
82 printf("- Number of directions: %i\n", num_directions);
83 printf("- Precision: %s\n", (precision == OSKAR_SINGLE) ? "single" : "double");
84 printf("- %s\n", evaluate_2d ? "2D" : "3D");
85 printf("- Operation type: ");
86 if (op_type == C2C)
87 {
88 printf("c2c\n");
89 }
90 else if (op_type == M2M)
91 {
92 printf("m2m\n");
93 }
94 else
95 {
96 printf("Error undefined!\n");
97 }
98 printf("- Number of iterations: %i\n", niter);
99 printf("\n");
100 }
101
102 double time_taken = 0.0;
103 oskar_device_set_require_double_precision(precision == OSKAR_DOUBLE);
104 int status = benchmark(num_elements, num_directions, num_element_types,
105 op_type, location, precision, evaluate_2d, niter, time_taken);
106
107 if (status)
108 {
109 fprintf(stderr, "ERROR: array pattern evaluation failed with code %i: "
110 "%s\n", status, oskar_get_error_string(status));
111 return EXIT_FAILURE;
112 }
113 if (opt.is_set("-v"))
114 {
115 printf("==> Total time taken: %f seconds.\n", time_taken);
116 printf("==> Time taken per iteration: %f seconds.\n", time_taken/niter);
117 printf("\n");
118 }
119 else
120 {
121 printf("%f\n", time_taken/niter);
122 }
123
124 return EXIT_SUCCESS;
125 }
126
127
benchmark(int num_elements,int num_directions,int num_element_types,OpType op_type,int loc,int precision,bool evaluate_2d,int niter,double & time_taken)128 int benchmark(int num_elements, int num_directions, int num_element_types,
129 OpType op_type, int loc, int precision, bool evaluate_2d, int niter,
130 double& time_taken)
131 {
132 int status = 0;
133 int type = precision | OSKAR_COMPLEX;
134 oskar_Mem *beam = 0, *signal = 0, *z = 0, *z_i = 0;
135 oskar_Mem *x = oskar_mem_create(precision, loc, num_directions, &status);
136 oskar_Mem *y = oskar_mem_create(precision, loc, num_directions, &status);
137 oskar_Mem *x_i = oskar_mem_create(precision, loc, num_elements, &status);
138 oskar_Mem *y_i = oskar_mem_create(precision, loc, num_elements, &status);
139 oskar_Mem *weights = oskar_mem_create(type, loc, num_elements, &status);
140 oskar_Mem *element_types_cpu = oskar_mem_create(OSKAR_INT, OSKAR_CPU,
141 num_elements, &status);
142 int* el_type = oskar_mem_int(element_types_cpu, &status);
143 for (int j = 0; j < num_elements; j += num_element_types)
144 {
145 for (int i = 0; i < num_element_types; ++i)
146 {
147 if (i + j >= num_elements) break;
148 el_type[i + j] = i;
149 }
150 }
151 if (!evaluate_2d)
152 {
153 z = oskar_mem_create(precision, loc, num_directions, &status);
154 z_i = oskar_mem_create(precision, loc, num_elements, &status);
155 }
156 int num_signals = num_directions * num_elements;
157 if (op_type == M2M) type |= OSKAR_MATRIX;
158 beam = oskar_mem_create(type, loc, num_directions, &status);
159 signal = oskar_mem_create(type, loc, num_signals, &status);
160 oskar_Mem* element_types = oskar_mem_create_copy(
161 element_types_cpu, loc, &status);
162
163 oskar_Timer *tmr = oskar_timer_create(loc);
164 if (!status)
165 {
166 char* device_name = oskar_device_name(loc, 0);
167 printf("Using device '%s'\n", device_name);
168 free(device_name);
169 oskar_timer_start(tmr);
170 for (int i = 0; i < niter; ++i)
171 {
172 oskar_dftw(0, num_elements, 2.0 * M_PI, weights, x_i, y_i, z_i,
173 0, num_directions, x, y, z,
174 element_types, signal, 1, 1, 0, beam, &status);
175 }
176 time_taken = oskar_timer_elapsed(tmr);
177 }
178
179 // Free memory.
180 oskar_timer_free(tmr);
181 oskar_mem_free(x, &status);
182 oskar_mem_free(y, &status);
183 oskar_mem_free(z, &status);
184 oskar_mem_free(x_i, &status);
185 oskar_mem_free(y_i, &status);
186 oskar_mem_free(z_i, &status);
187 oskar_mem_free(weights, &status);
188 oskar_mem_free(element_types, &status);
189 oskar_mem_free(element_types_cpu, &status);
190 oskar_mem_free(beam, &status);
191 oskar_mem_free(signal, &status);
192
193 return status;
194 }
195