1 /*
2 
3    BLIS
4    An object-based framework for developing high-performance BLAS-like
5    libraries.
6 
7    Copyright (C) 2014, The University of Texas at Austin
8    Copyright (C) 2018 - 2019, Advanced Micro Devices, Inc.
9 
10    Redistribution and use in source and binary forms, with or without
11    modification, are permitted provided that the following conditions are
12    met:
13     - Redistributions of source code must retain the above copyright
14       notice, this list of conditions and the following disclaimer.
15     - Redistributions in binary form must reproduce the above copyright
16       notice, this list of conditions and the following disclaimer in the
17       documentation and/or other materials provided with the distribution.
18     - Neither the name(s) of the copyright holder(s) nor the names of its
19       contributors may be used to endorse or promote products derived
20       from this software without specific prior written permission.
21 
22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "blis.h"
37 #include "test_libblis.h"
38 
39 
40 // Static variables.
41 static char*     op_str                    = "dotv";
42 static char*     o_types                   = "vv";  // x y
43 static char*     p_types                   = "cc";  // conjx conjy
44 static thresh_t  thresh[BLIS_NUM_FP_TYPES] = { { 1e-04, 1e-05 },   // warn, pass for s
45                                                { 1e-04, 1e-05 },   // warn, pass for c
46                                                { 1e-13, 1e-14 },   // warn, pass for d
47                                                { 1e-13, 1e-14 } }; // warn, pass for z
48 
49 // Local prototypes.
50 void libblis_test_dotv_deps
51      (
52        thread_data_t* tdata,
53        test_params_t* params,
54        test_op_t*     op
55      );
56 
57 void libblis_test_dotv_experiment
58      (
59        test_params_t* params,
60        test_op_t*     op,
61        iface_t        iface,
62        char*          dc_str,
63        char*          pc_str,
64        char*          sc_str,
65        unsigned int   p_cur,
66        double*        perf,
67        double*        resid
68      );
69 
70 void libblis_test_dotv_impl
71      (
72        iface_t   iface,
73        obj_t*    x,
74        obj_t*    y,
75        obj_t*    rho
76      );
77 
78 void libblis_test_dotv_check
79      (
80        test_params_t* params,
81        obj_t*         x,
82        obj_t*         y,
83        obj_t*         rho,
84        double*        resid
85      );
86 
87 
88 
libblis_test_dotv_deps(thread_data_t * tdata,test_params_t * params,test_op_t * op)89 void libblis_test_dotv_deps
90      (
91        thread_data_t* tdata,
92        test_params_t* params,
93        test_op_t*     op
94      )
95 {
96 	libblis_test_randv( tdata, params, &(op->ops->randv) );
97 	libblis_test_normfv( tdata, params, &(op->ops->normfv) );
98 	libblis_test_copyv( tdata, params, &(op->ops->copyv) );
99 }
100 
101 
102 
libblis_test_dotv(thread_data_t * tdata,test_params_t * params,test_op_t * op)103 void libblis_test_dotv
104      (
105        thread_data_t* tdata,
106        test_params_t* params,
107        test_op_t*     op
108      )
109 {
110 
111 	// Return early if this test has already been done.
112 	if ( libblis_test_op_is_done( op ) ) return;
113 
114 	// Return early if operation is disabled.
115 	if ( libblis_test_op_is_disabled( op ) ||
116 	     libblis_test_l1v_is_disabled( op ) ) return;
117 
118 	// Call dependencies first.
119 	if ( TRUE ) libblis_test_dotv_deps( tdata, params, op );
120 
121 	// Execute the test driver for each implementation requested.
122 	//if ( op->front_seq == ENABLE )
123 	{
124 		libblis_test_op_driver( tdata,
125 		                        params,
126 		                        op,
127 		                        BLIS_TEST_SEQ_FRONT_END,
128 		                        op_str,
129 		                        p_types,
130 		                        o_types,
131 		                        thresh,
132 		                        libblis_test_dotv_experiment );
133 	}
134 }
135 
136 
137 
libblis_test_dotv_experiment(test_params_t * params,test_op_t * op,iface_t iface,char * dc_str,char * pc_str,char * sc_str,unsigned int p_cur,double * perf,double * resid)138 void libblis_test_dotv_experiment
139      (
140        test_params_t* params,
141        test_op_t*     op,
142        iface_t        iface,
143        char*          dc_str,
144        char*          pc_str,
145        char*          sc_str,
146        unsigned int   p_cur,
147        double*        perf,
148        double*        resid
149      )
150 {
151 	unsigned int n_repeats = params->n_repeats;
152 	unsigned int i;
153 
154 	double       time_min  = DBL_MAX;
155 	double       time;
156 
157 	num_t        datatype;
158 
159 	dim_t        m;
160 
161 	conj_t       conjx, conjy, conjconjxy;
162 
163 	obj_t        x, y, rho;
164 
165 
166 	// Use the datatype of the first char in the datatype combination string.
167 	bli_param_map_char_to_blis_dt( dc_str[0], &datatype );
168 
169 	// Map the dimension specifier to an actual dimension.
170 	m = libblis_test_get_dim_from_prob_size( op->dim_spec[0], p_cur );
171 
172 	// Map parameter characters to BLIS constants.
173 	bli_param_map_char_to_blis_conj( pc_str[0], &conjx );
174 	bli_param_map_char_to_blis_conj( pc_str[1], &conjy );
175 
176 	// Create test scalars.
177 	bli_obj_scalar_init_detached( datatype, &rho );
178 
179 	// Create test operands (vectors and/or matrices).
180 	libblis_test_vobj_create( params, datatype, sc_str[0], m, &x );
181 	libblis_test_vobj_create( params, datatype, sc_str[1], m, &y );
182 
183 	// Randomize x.
184 	libblis_test_vobj_randomize( params, TRUE, &x );
185 
186 	// Determine whether to make a copy of x with or without conjugation.
187 	//
188 	//  conjx conjy  ~conjx^conjy   y is initialized as
189 	//  n     n      c              y = conj(x)
190 	//  n     c      n              y = x
191 	//  c     n      n              y = x
192 	//  c     c      c              y = conj(x)
193 	//
194 	conjconjxy = bli_apply_conj( conjx, conjy );
195 	conjconjxy = bli_conj_toggled( conjconjxy );
196 	bli_obj_set_conj( conjconjxy, &x );
197 	bli_copyv( &x, &y );
198 
199 	// Apply the parameters.
200 	bli_obj_set_conj( conjx, &x );
201 	bli_obj_set_conj( conjy, &y );
202 
203 	// Repeat the experiment n_repeats times and record results.
204 	for ( i = 0; i < n_repeats; ++i )
205 	{
206 		bli_copysc( &BLIS_MINUS_ONE, &rho );
207 
208 		time = bli_clock();
209 
210 		libblis_test_dotv_impl( iface, &x, &y, &rho );
211 
212 		time_min = bli_clock_min_diff( time_min, time );
213 	}
214 
215 	// Estimate the performance of the best experiment repeat.
216 	*perf = ( 2.0 * m ) / time_min / FLOPS_PER_UNIT_PERF;
217 	if ( bli_obj_is_complex( &y ) ) *perf *= 4.0;
218 
219 	// Perform checks.
220 	libblis_test_dotv_check( params, &x, &y, &rho, resid );
221 
222 	// Zero out performance and residual if output scalar is empty.
223 	libblis_test_check_empty_problem( &rho, perf, resid );
224 
225 	// Free the test objects.
226 	bli_obj_free( &x );
227 	bli_obj_free( &y );
228 }
229 
230 
231 
libblis_test_dotv_impl(iface_t iface,obj_t * x,obj_t * y,obj_t * rho)232 void libblis_test_dotv_impl
233      (
234        iface_t   iface,
235        obj_t*    x,
236        obj_t*    y,
237        obj_t*    rho
238      )
239 {
240 	switch ( iface )
241 	{
242 		case BLIS_TEST_SEQ_FRONT_END:
243 		bli_dotv( x, y, rho );
244 		break;
245 
246 		default:
247 		libblis_test_printf_error( "Invalid interface type.\n" );
248 	}
249 }
250 
251 
252 
libblis_test_dotv_check(test_params_t * params,obj_t * x,obj_t * y,obj_t * rho,double * resid)253 void libblis_test_dotv_check
254      (
255        test_params_t* params,
256        obj_t*         x,
257        obj_t*         y,
258        obj_t*         rho,
259        double*        resid
260      )
261 {
262 	num_t  dt_real = bli_obj_dt_proj_to_real( y );
263 
264 	obj_t  rho_r, rho_i;
265 	obj_t  norm_x, norm_xy;
266 
267 	double zero;
268 	double junk;
269 
270 	//
271 	// Pre-conditions:
272 	// - x is randomized.
273 	// - y is equal to conj(conjx(conjy(x))).
274 	//
275 	// Under these conditions, we assume that the implementation for
276 	//
277 	//   rho := conjx(x^T) conjy(y)
278 	//
279 	// is functioning correctly if
280 	//
281 	//   sqrtsc( rho.real ) - normfv( x )
282 	//
283 	// and
284 	//
285 	//   rho.imag
286 	//
287 	// are negligible.
288 	//
289 
290 	bli_obj_scalar_init_detached( dt_real, &rho_r );
291 	bli_obj_scalar_init_detached( dt_real, &rho_i );
292 	bli_obj_scalar_init_detached( dt_real, &norm_x );
293 	bli_obj_scalar_init_detached( dt_real, &norm_xy );
294 
295 	bli_normfv( x, &norm_x );
296 
297 	bli_unzipsc( rho, &rho_r, &rho_i );
298 
299 	bli_sqrtsc( &rho_r, &norm_xy );
300 
301 	bli_subsc( &norm_x, &norm_xy );
302 	bli_getsc( &norm_xy, resid, &junk );
303 	bli_getsc( &rho_i,   &zero, &junk );
304 
305 	*resid = bli_fmaxabs( *resid, zero );
306 }
307 
308