1 /* ************************************************************************
2  * Copyright 2013 Advanced Micro Devices, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  * ************************************************************************/
16 
17 
18 #include <stdlib.h>             // srand()
19 #include <string.h>             // memcpy()
20 #include <gtest/gtest.h>
21 #include <clBLAS.h>
22 #include <common.h>
23 #include <blas-internal.h>
24 #include <blas-wrapper.h>
25 #include <clBLAS-wrapper.h>
26 #include <BlasBase.h>
27 #include <blas-random.h>
28 #include <iamax.h>
29 
30 static void
releaseMemObjects(cl_mem objX,cl_mem objiAmax,cl_mem objScratch)31 releaseMemObjects(cl_mem objX, cl_mem objiAmax, cl_mem objScratch)
32 {
33     if(objX != NULL)
34  	{
35         clReleaseMemObject(objX);
36 	}
37 	if(objiAmax != NULL)
38     {
39         clReleaseMemObject(objiAmax);
40     }
41 	if(objScratch != NULL)
42     {
43         clReleaseMemObject(objScratch);
44     }
45 }
46 
47 template <typename T> static void
deleteBuffers(T * blasX,int * blasiAmax=NULL,int * clblasiAmax=NULL)48 deleteBuffers(T *blasX, int *blasiAmax=NULL, int *clblasiAmax=NULL)
49 {
50 	if(blasX != NULL)
51 	{
52         delete[] blasX;
53     }
54 	if(clblasiAmax != NULL)
55     {
56         delete[] clblasiAmax;
57     }
58 	if(blasiAmax != NULL)
59     {
60         delete(blasiAmax);
61     }
62 }
63 
64 template <typename T>
65 void
iamaxCorrectnessTest(TestParams * params)66 iamaxCorrectnessTest(TestParams *params)
67 {
68     cl_int err;
69     T *blasX;
70     int *clblasiAmax, *blasiAmax;
71     cl_mem bufX, bufiAmax, scratchBuff;
72     clMath::BlasBase *base;
73     cl_event *events;
74 
75     base = clMath::BlasBase::getInstance();
76 
77     if ((typeid(T) == typeid(cl_double) ||
78          typeid(T) == typeid(DoubleComplex)) &&
79         !base->isDevSupportDoublePrecision()) {
80 
81         std::cerr << ">> WARNING: The target device doesn't support native "
82                      "double precision floating point arithmetic" <<
83                      std::endl << ">> Test skipped" << std::endl;
84         SUCCEED();
85         return;
86     }
87 
88 	printf("number of command queues : %d\n\n", params->numCommandQueues);
89 
90     events = new cl_event[params->numCommandQueues];
91     memset(events, 0, params->numCommandQueues * sizeof(cl_event));
92 
93     size_t lengthX = (1 + ((params->N -1) * abs(params->incx)));
94 
95     blasX 	= new T[lengthX + params->offBX ];
96 	blasiAmax = new int[1];
97     clblasiAmax = new int[1 + params->offa];
98 
99 	if((blasX == NULL) || (clblasiAmax == NULL) || (blasiAmax == NULL))
100 	{
101 		::std::cerr << "Cannot allocate memory on host side\n" << "!!!!!!!!!!!!Test skipped.!!!!!!!!!!!!" << ::std::endl;
102         deleteBuffers<T>(blasX, blasiAmax, clblasiAmax);
103 		delete[] events;
104 		SUCCEED();
105         return;
106 	}
107 
108     srand(params->seed);
109     ::std::cerr << "Generating input data... ";
110 
111 	randomVectors<T>(params->N, (blasX + params->offBX), params->incx, NULL, 0);
112     ::std::cerr << "Done" << ::std::endl;
113 
114 	// Allocate buffers
115     bufX = base->createEnqueueBuffer(blasX, (lengthX + params->offBX)* sizeof(T), 0, CL_MEM_READ_ONLY);
116     bufiAmax = base->createEnqueueBuffer(NULL, (1 + params->offa) * sizeof(int), 0, CL_MEM_READ_WRITE);
117 	scratchBuff = base->createEnqueueBuffer(NULL, (2 * lengthX * sizeof(T)), 0, CL_MEM_READ_WRITE);
118 
119     ::std::cerr << "Calling reference xiAMAX routine... ";
120 
121 	*blasiAmax = ::clMath::blas::iamax( params->N, blasX, params->offBX, params->incx);
122     ::std::cerr << "Done" << ::std::endl;
123 
124     if ((bufX == NULL) || (bufiAmax == NULL) || (scratchBuff == NULL)) {
125         releaseMemObjects(bufX, bufiAmax, scratchBuff);
126         deleteBuffers<T>(blasX, blasiAmax, clblasiAmax);
127         delete[] events;
128         ::std::cerr << ">> Failed to create/enqueue buffer for a matrix."
129             << ::std::endl
130             << ">> Can't execute the test, because data is not transfered to GPU."
131             << ::std::endl
132             << ">> Test skipped." << ::std::endl;
133         SUCCEED();
134         return;
135     }
136 
137     ::std::cerr << "Calling clblas xiAMAX routine... ";
138 
139     DataType type;
140     type = ( typeid(T) == typeid(cl_float))? TYPE_FLOAT : ( typeid(T) == typeid(cl_double))? TYPE_DOUBLE: ( typeid(T) == typeid(cl_float2))? TYPE_COMPLEX_FLOAT:TYPE_COMPLEX_DOUBLE;
141 
142     // Should use bufXTemp as well
143     err = (cl_int)::clMath::clblas::iamax( type, params->N, bufiAmax, params->offa,
144                                            bufX, params->offBX, params->incx, scratchBuff,
145                                             params->numCommandQueues, base->commandQueues(), 0, NULL, events);
146 
147     if (err != CL_SUCCESS) {
148         releaseMemObjects(bufX, bufiAmax, scratchBuff);
149         deleteBuffers<T>(blasX, blasiAmax, clblasiAmax);
150         delete[] events;
151         ASSERT_EQ(CL_SUCCESS, err) << "::clMath::clblas::iAMAX() failed";
152     }
153 
154     err = waitForSuccessfulFinish(params->numCommandQueues,
155         base->commandQueues(), events);
156     if (err != CL_SUCCESS) {
157         releaseMemObjects(bufX, bufiAmax, scratchBuff);
158         deleteBuffers<T>(blasX, blasiAmax, clblasiAmax);
159         delete[] events;
160         ASSERT_EQ(CL_SUCCESS, err) << "waitForSuccessfulFinish()";
161     }
162     ::std::cerr << "Done" << ::std::endl;
163 
164 
165     err = clEnqueueReadBuffer(base->commandQueues()[0], bufiAmax, CL_TRUE, 0,
166         (1 + params->offa) * sizeof(*clblasiAmax), clblasiAmax, 0, NULL, NULL);
167 	if (err != CL_SUCCESS)
168 	{
169 		::std::cerr << "iAMAX: Reading results failed...." << std::endl;
170 	}
171 
172     compareValues<int>((blasiAmax), (clblasiAmax+params->offa), 0);
173     releaseMemObjects(bufX, bufiAmax, scratchBuff);
174     deleteBuffers<T>(blasX, blasiAmax, clblasiAmax);
175     delete[] events;
176 }
177 
178 // Instantiate the test
179 
TEST_P(iAMAX,isamax)180 TEST_P(iAMAX, isamax) {
181     TestParams params;
182 
183     getParams(&params);
184     iamaxCorrectnessTest<cl_float>(&params);
185 }
186 
TEST_P(iAMAX,idamax)187 TEST_P(iAMAX, idamax) {
188     TestParams params;
189 
190     getParams(&params);
191     iamaxCorrectnessTest<cl_double>(&params);
192 }
193 
TEST_P(iAMAX,icamax)194 TEST_P(iAMAX, icamax) {
195     TestParams params;
196 
197     getParams(&params);
198     iamaxCorrectnessTest<FloatComplex>(&params);
199 }
200 
TEST_P(iAMAX,izamax)201 TEST_P(iAMAX, izamax) {
202     TestParams params;
203 
204     getParams(&params);
205     iamaxCorrectnessTest<DoubleComplex>(&params);
206 }
207