mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
templateCublas_test.cpp
Go to the documentation of this file.
1/** \file templateCublas_test.cpp
2 * \brief Tests templated cuBLAS wrappers.
3 */
4#include "../../../catch2/catch.hpp"
5#include "../../../cudaTestUtils.hpp"
6
9
10/// Tests cublasTscal, as well as basic cudaPtr operations.
11/** Exercises cudaPtr upload/download and mx::cuda::cublasTscal. */
12/**
13 * \ingroup templateCublas_unit_tests
14 */
15TEST_CASE( "scaling a vector with cublas", "[math::cuda::templateCublas]" )
16{
17 if( !mxlibTest::cudaDeviceAvailable() )
18 {
19 WARN( "CUDA runtime is available but no CUDA device is present" );
20 return;
21 }
22
23 GIVEN( "a vector" )
24 {
25 WHEN( "type is single precision real" )
26 {
27 std::vector<float> hx;
28 mx::cuda::cudaPtr<float> dx;
29 float alpha = 2;
30
31 hx.resize( 5 );
32 for( size_t n = 0; n < hx.size(); ++n )
33 hx[n] = n;
34
35 dx.upload( hx.data(), hx.size() );
36 REQUIRE( dx.size() == hx.size() );
37
38 cublasHandle_t handle;
39 cublasStatus_t stat;
40 stat = cublasCreate( &handle );
41 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
42
43 stat = mx::cuda::cublasTscal( handle, dx.size(), &alpha, dx(), 1 );
44 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
45
46 dx.download( hx.data() );
47
48 REQUIRE( hx[0] == 0 );
49 REQUIRE( hx[1] == 2 );
50 REQUIRE( hx[2] == 4 );
51 REQUIRE( hx[3] == 6 );
52 REQUIRE( hx[4] == 8 );
53
54 stat = cublasDestroy( handle );
55
56 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
57 }
58
59 WHEN( "type is double precision real" )
60 {
61 std::vector<double> hx;
62 mx::cuda::cudaPtr<double> dx;
63 double alpha = 2;
64
65 hx.resize( 5 );
66 for( size_t n = 0; n < hx.size(); ++n )
67 hx[n] = n;
68
69 dx.upload( hx.data(), hx.size() );
70 REQUIRE( dx.size() == hx.size() );
71
72 cublasHandle_t handle;
73 cublasStatus_t stat;
74 stat = cublasCreate( &handle );
75 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
76
77 stat = mx::cuda::cublasTscal( handle, dx.size(), &alpha, dx(), 1 );
78 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
79
80 dx.download( hx.data() );
81
82 REQUIRE( hx[0] == 0 );
83 REQUIRE( hx[1] == 2 );
84 REQUIRE( hx[2] == 4 );
85 REQUIRE( hx[3] == 6 );
86 REQUIRE( hx[4] == 8 );
87
88 stat = cublasDestroy( handle );
89
90 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
91 }
92
93 WHEN( "type is single precision complex" )
94 {
95 std::vector<std::complex<float>> hx;
96 mx::cuda::cudaPtr<std::complex<float>> dx;
97 std::complex<float> alpha = 2;
98
99 hx.resize( 5 );
100 for( size_t n = 0; n < hx.size(); ++n )
101 hx[n] = std::complex<float>( n, n );
102
103 dx.upload( hx.data(), hx.size() );
104 REQUIRE( dx.size() == hx.size() );
105
106 cublasHandle_t handle;
107 cublasStatus_t stat;
108 stat = cublasCreate( &handle );
109 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
110
111 stat = mx::cuda::cublasTscal( handle, dx.size(), (cuComplex *)&alpha, dx(), 1 );
112 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
113
114 dx.download( hx.data() );
115
116 REQUIRE( hx[0] == std::complex<float>( 0, 0 ) );
117 REQUIRE( hx[1] == std::complex<float>( 2, 2 ) );
118 REQUIRE( hx[2] == std::complex<float>( 4, 4 ) );
119 REQUIRE( hx[3] == std::complex<float>( 6, 6 ) );
120 REQUIRE( hx[4] == std::complex<float>( 8, 8 ) );
121
122 stat = cublasDestroy( handle );
123
124 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
125 }
126
127 WHEN( "type is double precision complex" )
128 {
129 std::vector<std::complex<double>> hx;
130 mx::cuda::cudaPtr<std::complex<double>> dx;
131 std::complex<double> alpha = 2;
132
133 hx.resize( 5 );
134 for( size_t n = 0; n < hx.size(); ++n )
135 hx[n] = std::complex<double>( n, n );
136
137 dx.upload( hx.data(), hx.size() );
138 REQUIRE( dx.size() == hx.size() );
139
140 cublasHandle_t handle;
141 cublasStatus_t stat;
142 stat = cublasCreate( &handle );
143 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
144
145 stat = mx::cuda::cublasTscal( handle, dx.size(), (cuDoubleComplex *)&alpha, dx(), 1 );
146 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
147
148 dx.download( hx.data() );
149
150 REQUIRE( hx[0] == std::complex<double>( 0, 0 ) );
151 REQUIRE( hx[1] == std::complex<double>( 2, 2 ) );
152 REQUIRE( hx[2] == std::complex<double>( 4, 4 ) );
153 REQUIRE( hx[3] == std::complex<double>( 6, 6 ) );
154 REQUIRE( hx[4] == std::complex<double>( 8, 8 ) );
155
156 stat = cublasDestroy( handle );
157
158 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
159 }
160 }
161}
162
163/** scaling and accumulating a vector with cublas
164 * Tests cublasTaxpy, as well as basic cudaPtr operations.
165 *
166 */
167/**
168 * \ingroup templateCublas_unit_tests
169 */
170TEST_CASE( "scaling and accumulating a vector with cublas", "[math::cuda::templateCublas]" )
171{
172 if( !mxlibTest::cudaDeviceAvailable() )
173 {
174 WARN( "CUDA runtime is available but no CUDA device is present" );
175 return;
176 }
177
178 GIVEN( "a vector" )
179 {
180 WHEN( "type is single precision real" )
181 {
182 std::vector<float> hx, hy;
183 mx::cuda::cudaPtr<float> dx, dy;
184 float alpha = 2;
185
186 hx.resize( 5 );
187 for( size_t n = 0; n < hx.size(); ++n )
188 hx[n] = n;
189
190 hy.resize( 5 );
191 for( size_t n = 0; n < hy.size(); ++n )
192 hy[n] = 1;
193
194 dx.upload( hx.data(), hx.size() );
195 REQUIRE( dx.size() == hx.size() );
196
197 dy.upload( hy.data(), hy.size() );
198 REQUIRE( dy.size() == hy.size() );
199
200 cublasHandle_t handle;
201 cublasStatus_t stat;
202 stat = cublasCreate( &handle );
203 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
204
205 stat = mx::cuda::cublasTaxpy( handle, dx.size(), &alpha, dx(), 1, dy(), 1 );
206 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
207
208 dy.download( hy.data() );
209
210 REQUIRE( hy[0] == 1 );
211 REQUIRE( hy[1] == 3 );
212 REQUIRE( hy[2] == 5 );
213 REQUIRE( hy[3] == 7 );
214 REQUIRE( hy[4] == 9 );
215
216 stat = cublasDestroy( handle );
217
218 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
219 }
220
221 WHEN( "type is double precision real" )
222 {
223 std::vector<double> hx, hy;
224 mx::cuda::cudaPtr<double> dx, dy;
225 double alpha = 2;
226
227 hx.resize( 5 );
228 for( size_t n = 0; n < hx.size(); ++n )
229 hx[n] = n;
230
231 hy.resize( 5 );
232 for( size_t n = 0; n < hy.size(); ++n )
233 hy[n] = 1;
234
235 dx.upload( hx.data(), hx.size() );
236 REQUIRE( dx.size() == hx.size() );
237
238 dy.upload( hy.data(), hy.size() );
239 REQUIRE( dy.size() == hy.size() );
240
241 cublasHandle_t handle;
242 cublasStatus_t stat;
243 stat = cublasCreate( &handle );
244 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
245
246 stat = mx::cuda::cublasTaxpy( handle, dx.size(), &alpha, dx(), 1, dy(), 1 );
247 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
248
249 dy.download( hy.data() );
250
251 REQUIRE( hy[0] == 1 );
252 REQUIRE( hy[1] == 3 );
253 REQUIRE( hy[2] == 5 );
254 REQUIRE( hy[3] == 7 );
255 REQUIRE( hy[4] == 9 );
256
257 stat = cublasDestroy( handle );
258
259 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
260 }
261
262 WHEN( "type is single precision complex" )
263 {
264 std::vector<std::complex<float>> hx, hy;
265 mx::cuda::cudaPtr<std::complex<float>> dx, dy;
266 std::complex<float> alpha = 2;
267
268 hx.resize( 5 );
269 for( size_t n = 0; n < hx.size(); ++n )
270 hx[n] = std::complex<float>( n, n );
271
272 hy.resize( 5 );
273 for( size_t n = 0; n < hy.size(); ++n )
274 hy[n] = std::complex<float>( 1, 1 );
275
276 dx.upload( hx.data(), hx.size() );
277 REQUIRE( dx.size() == hx.size() );
278
279 dy.upload( hy.data(), hy.size() );
280 REQUIRE( dy.size() == hy.size() );
281
282 cublasHandle_t handle;
283 cublasStatus_t stat;
284 stat = cublasCreate( &handle );
285 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
286
287 stat = mx::cuda::cublasTaxpy( handle, dx.size(), (cuComplex *)&alpha, dx(), 1, dy(), 1 );
288 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
289
290 dy.download( hy.data() );
291
292 REQUIRE( hy[0] == std::complex<float>( 1, 1 ) );
293 REQUIRE( hy[1] == std::complex<float>( 3, 3 ) );
294 REQUIRE( hy[2] == std::complex<float>( 5, 5 ) );
295 REQUIRE( hy[3] == std::complex<float>( 7, 7 ) );
296 REQUIRE( hy[4] == std::complex<float>( 9, 9 ) );
297
298 stat = cublasDestroy( handle );
299
300 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
301 }
302
303 WHEN( "type is double precision complex" )
304 {
305 std::vector<std::complex<double>> hx, hy;
306 mx::cuda::cudaPtr<std::complex<double>> dx, dy;
307 std::complex<double> alpha = 2;
308
309 hx.resize( 5 );
310 for( size_t n = 0; n < hx.size(); ++n )
311 hx[n] = std::complex<double>( n, n );
312
313 hy.resize( 5 );
314 for( size_t n = 0; n < hy.size(); ++n )
315 hy[n] = std::complex<double>( 1, 1 );
316
317 dx.upload( hx.data(), hx.size() );
318 REQUIRE( dx.size() == hx.size() );
319
320 dy.upload( hy.data(), hy.size() );
321 REQUIRE( dy.size() == hy.size() );
322
323 cublasHandle_t handle;
324 cublasStatus_t stat;
325 stat = cublasCreate( &handle );
326 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
327
328 stat = mx::cuda::cublasTaxpy( handle, dx.size(), (cuDoubleComplex *)&alpha, dx(), 1, dy(), 1 );
329 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
330
331 dy.download( hy.data() );
332
333 REQUIRE( hy[0] == std::complex<double>( 1, 1 ) );
334 REQUIRE( hy[1] == std::complex<double>( 3, 3 ) );
335 REQUIRE( hy[2] == std::complex<double>( 5, 5 ) );
336 REQUIRE( hy[3] == std::complex<double>( 7, 7 ) );
337 REQUIRE( hy[4] == std::complex<double>( 9, 9 ) );
338
339 stat = cublasDestroy( handle );
340
341 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
342 }
343 }
344}
345
346/** multiplying two vectors element by element
347 * Tests mx::cuda::elementwiseXxY, as well as basic cudaPtr operations.
348 *
349 */
350/**
351 * \ingroup templateCublas_unit_tests
352 */
353TEST_CASE( "multiplying two vectors element by element", "[math::cuda::templateCublas]" )
354{
355 if( !mxlibTest::cudaDeviceAvailable() )
356 {
357 WARN( "CUDA runtime is available but no CUDA device is present" );
358 return;
359 }
360
361 GIVEN( "a vector" )
362 {
363 WHEN( "both types are single precision real" )
364 {
365 std::vector<float> hx, hy;
366 mx::cuda::cudaPtr<float> dx, dy;
367
368 hx.resize( 5 );
369 for( size_t n = 0; n < hx.size(); ++n )
370 hx[n] = n;
371
372 hy.resize( 5 );
373 for( size_t n = 0; n < hy.size(); ++n )
374 hy[n] = 2 * n;
375
376 dx.upload( hx.data(), hx.size() );
377 REQUIRE( dx.size() == hx.size() );
378
379 dy.resize( hy.size() );
380 dy.upload( hy.data() );
381 REQUIRE( dy.size() == hy.size() );
382
383 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
384 REQUIRE( rv == cudaSuccess );
385
386 dx.download( hx.data() );
387
388 REQUIRE( hx[0] == 0 );
389 REQUIRE( hx[1] == 2 );
390 REQUIRE( hx[2] == 8 );
391 REQUIRE( hx[3] == 18 );
392 REQUIRE( hx[4] == 32 );
393 }
394
395 WHEN( "type1 is complex-float, and type2 is float" )
396 {
397 std::vector<std::complex<float>> hx;
398 mx::cuda::cudaPtr<std::complex<float>> dx;
399
400 std::vector<float> hy;
401 mx::cuda::cudaPtr<float> dy;
402
403 hx.resize( 5 );
404 for( size_t n = 0; n < hx.size(); ++n )
405 hx[n] = std::complex<float>( n, n );
406
407 hy.resize( 5 );
408 for( size_t n = 0; n < hy.size(); ++n )
409 hy[n] = 2 * n;
410
411 dx.upload( hx.data(), hx.size() );
412 REQUIRE( dx.size() == hx.size() );
413
414 dy.resize( hy.size() );
415 dy.upload( hy.data() );
416 REQUIRE( dy.size() == hy.size() );
417
418 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
419 REQUIRE( rv == cudaSuccess );
420
421 dx.download( hx.data() );
422
423 REQUIRE( hx[0] == std::complex<float>( 0, 0 ) );
424 REQUIRE( hx[1] == std::complex<float>( 2, 2 ) );
425 REQUIRE( hx[2] == std::complex<float>( 8, 8 ) );
426 REQUIRE( hx[3] == std::complex<float>( 18, 18 ) );
427 REQUIRE( hx[4] == std::complex<float>( 32, 32 ) );
428 }
429
430 WHEN( "type1 is complex-float, and type2 is complex-float" )
431 {
432 std::vector<std::complex<float>> hx;
433 mx::cuda::cudaPtr<std::complex<float>> dx;
434
435 std::vector<std::complex<float>> hy;
436 mx::cuda::cudaPtr<std::complex<float>> dy;
437
438 hx.resize( 5 );
439 for( size_t n = 0; n < hx.size(); ++n )
440 hx[n] = std::complex<float>( n, n );
441
442 hy.resize( 5 );
443 for( size_t n = 0; n < hy.size(); ++n )
444 hy[n] = std::complex<float>( 0, 2 * n );
445
446 dx.upload( hx.data(), hx.size() );
447 REQUIRE( dx.size() == hx.size() );
448
449 dy.resize( hy.size() );
450 dy.upload( hy.data() );
451 REQUIRE( dy.size() == hy.size() );
452
453 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
454 REQUIRE( rv == cudaSuccess );
455
456 dx.download( hx.data() );
457
458 REQUIRE( hx[0] == std::complex<float>( 0, 0 ) );
459 REQUIRE( hx[1] == std::complex<float>( -2, 2 ) ); //(1,1) * (0,2) = (0 + 2i + 0i -2) = (-2,2)
460 REQUIRE( hx[2] == std::complex<float>( -8, 8 ) );
461 REQUIRE( hx[3] == std::complex<float>( -18, 18 ) );
462 REQUIRE( hx[4] == std::complex<float>( -32, 32 ) );
463 }
464
465 WHEN( "both types are double precision real" )
466 {
467 std::vector<double> hx, hy;
468 mx::cuda::cudaPtr<double> dx, dy;
469
470 hx.resize( 5 );
471 for( size_t n = 0; n < hx.size(); ++n )
472 hx[n] = n;
473
474 hy.resize( 5 );
475 for( size_t n = 0; n < hy.size(); ++n )
476 hy[n] = 2 * n;
477
478 dx.upload( hx.data(), hx.size() );
479 REQUIRE( dx.size() == hx.size() );
480
481 dy.resize( hy.size() );
482 dy.upload( hy.data() );
483 REQUIRE( dy.size() == hy.size() );
484
485 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
486 REQUIRE( rv == cudaSuccess );
487
488 dx.download( hx.data() );
489
490 REQUIRE( hx[0] == 0 );
491 REQUIRE( hx[1] == 2 );
492 REQUIRE( hx[2] == 8 );
493 REQUIRE( hx[3] == 18 );
494 REQUIRE( hx[4] == 32 );
495 }
496
497 WHEN( "type1 is complex-double, and type2 is double" )
498 {
499 std::vector<std::complex<double>> hx;
500 mx::cuda::cudaPtr<std::complex<double>> dx;
501
502 std::vector<double> hy;
503 mx::cuda::cudaPtr<double> dy;
504
505 hx.resize( 5 );
506 for( size_t n = 0; n < hx.size(); ++n )
507 hx[n] = std::complex<double>( n, n );
508
509 hy.resize( 5 );
510 for( size_t n = 0; n < hy.size(); ++n )
511 hy[n] = 2 * n;
512
513 dx.upload( hx.data(), hx.size() );
514 REQUIRE( dx.size() == hx.size() );
515
516 dy.resize( hy.size() );
517 dy.upload( hy.data() );
518 REQUIRE( dy.size() == hy.size() );
519
520 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
521 REQUIRE( rv == cudaSuccess );
522
523 dx.download( hx.data() );
524
525 REQUIRE( hx[0] == std::complex<double>( 0, 0 ) );
526 REQUIRE( hx[1] == std::complex<double>( 2, 2 ) );
527 REQUIRE( hx[2] == std::complex<double>( 8, 8 ) );
528 REQUIRE( hx[3] == std::complex<double>( 18, 18 ) );
529 REQUIRE( hx[4] == std::complex<double>( 32, 32 ) );
530 }
531
532 WHEN( "type1 is complex-double, and type2 is complex-double" )
533 {
534 std::vector<std::complex<double>> hx;
535 mx::cuda::cudaPtr<std::complex<double>> dx;
536
537 std::vector<std::complex<double>> hy;
538 mx::cuda::cudaPtr<std::complex<double>> dy;
539
540 hx.resize( 5 );
541 for( size_t n = 0; n < hx.size(); ++n )
542 hx[n] = std::complex<double>( n, n );
543
544 hy.resize( 5 );
545 for( size_t n = 0; n < hy.size(); ++n )
546 hy[n] = std::complex<double>( 1, 2 * n );
547
548 dx.upload( hx.data(), hx.size() );
549 REQUIRE( dx.size() == hx.size() );
550
551 dy.resize( hy.size() );
552 dy.upload( hy.data() );
553 REQUIRE( dy.size() == hy.size() );
554
555 cudaError_t rv = mx::cuda::elementwiseXxY( dx(), dy(), dx.size() );
556 REQUIRE( rv == cudaSuccess );
557
558 dx.download( hx.data() );
559
560 REQUIRE( hx[0] == std::complex<double>( 0, 0 ) ); //(0,0) * (0,0) = (0,0)
561 REQUIRE( hx[1] == std::complex<double>( -1, 3 ) ); //(1,1) * (1,2) = (1 + 2i + i -2) = (-1,3)
562 REQUIRE( hx[2] == std::complex<double>( -6, 10 ) );
563 REQUIRE( hx[3] == std::complex<double>( -15, 21 ) );
564 REQUIRE( hx[4] == std::complex<double>( -28, 36 ) );
565 }
566 }
567}
568
569/** multiplying a vector by a matrix
570 * Tests mx::cuda::cublasTgemv, as well as basic cudaPtr operations.
571 *
572 */
573/**
574 * \ingroup templateCublas_unit_tests
575 */
576TEST_CASE( "multiplying a vector by a matrix giving increments", "[math::cuda::templateCublas]" )
577{
578 if( !mxlibTest::cudaDeviceAvailable() )
579 {
580 WARN( "CUDA runtime is available but no CUDA device is present" );
581 return;
582 }
583
584 GIVEN( "a 2x2 matrix, float" )
585 {
586 WHEN( "float precision, beta is 0" )
587 {
588 std::vector<float> hA; // This will actually be a vector
589 mx::cuda::cudaPtr<float> dA;
590
591 std::vector<float> hx; // This will actually be a vector
592 mx::cuda::cudaPtr<float> dx;
593
594 std::vector<float> hy;
595 mx::cuda::cudaPtr<float> dy;
596
597 /* Column major order:
598 1 3
599 2 4
600 */
601 hA.resize( 4 );
602 hA[0] = 1;
603 hA[1] = 2;
604 hA[2] = 3;
605 hA[3] = 4;
606
607 dA.resize( 2, 2 );
608 dA.upload( hA.data() );
609
610 hx.resize( 2 );
611 hx[0] = 1;
612 hx[1] = 2;
613
614 dx.upload( hx.data(), hx.size() );
615
616 hy.resize( 2 );
617
618 dy.resize( 2 );
619 dy.initialize();
620
621 float alpha = 1;
622 float beta = 0;
623
624 cublasHandle_t handle;
625 cublasStatus_t stat;
626 stat = cublasCreate( &handle );
627 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
628
629 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
630 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
631
632 dy.download( hy.data() );
633
634 REQUIRE( hy[0] == 7 );
635 REQUIRE( hy[1] == 10 );
636
637 stat = cublasDestroy( handle );
638 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
639 }
640
641 WHEN( "float precision, beta is 1, but y is all 0" )
642 {
643 std::vector<float> hA; // This will actually be a vector
644 mx::cuda::cudaPtr<float> dA;
645
646 std::vector<float> hx; // This will actually be a vector
647 mx::cuda::cudaPtr<float> dx;
648
649 std::vector<float> hy;
650 mx::cuda::cudaPtr<float> dy;
651
652 /* Column major order:
653 1 3
654 2 4
655 */
656 hA.resize( 4 );
657 hA[0] = 1;
658 hA[1] = 2;
659 hA[2] = 3;
660 hA[3] = 4;
661
662 dA.resize( 2, 2 );
663 dA.upload( hA.data() );
664
665 hx.resize( 2 );
666 hx[0] = 1;
667 hx[1] = 2;
668
669 dx.upload( hx.data(), hx.size() );
670
671 hy.resize( 2 );
672
673 dy.resize( 2 );
674 dy.initialize();
675
676 float alpha = 1;
677 float beta = 1;
678
679 cublasHandle_t handle;
680 cublasStatus_t stat;
681 stat = cublasCreate( &handle );
682 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
683
684 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
685 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
686
687 dy.download( hy.data() );
688
689 REQUIRE( hy[0] == 7 );
690 REQUIRE( hy[1] == 10 );
691
692 stat = cublasDestroy( handle );
693 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
694 }
695 WHEN( "float precision, beta is 1, y is [1,2]" )
696 {
697 std::vector<float> hA; // This will actually be a vector
698 mx::cuda::cudaPtr<float> dA;
699
700 std::vector<float> hx; // This will actually be a vector
701 mx::cuda::cudaPtr<float> dx;
702
703 std::vector<float> hy;
704 mx::cuda::cudaPtr<float> dy;
705
706 /* Column major order:
707 1 3
708 2 4
709 */
710 hA.resize( 4 );
711 hA[0] = 1;
712 hA[1] = 2;
713 hA[2] = 3;
714 hA[3] = 4;
715
716 dA.resize( 2, 2 );
717 dA.upload( hA.data() );
718
719 hx.resize( 2 );
720 hx[0] = 1;
721 hx[1] = 2;
722
723 dx.upload( hx.data(), hx.size() );
724
725 hy.resize( 2 );
726 hy[0] = 1;
727 hy[1] = 2;
728
729 dy.resize( 2 );
730 dy.upload( hx.data() );
731
732 float alpha = 1;
733 float beta = 1;
734
735 cublasHandle_t handle;
736 cublasStatus_t stat;
737 stat = cublasCreate( &handle );
738 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
739
740 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
741 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
742
743 dy.download( hy.data() );
744
745 REQUIRE( hy[0] == 8 );
746 REQUIRE( hy[1] == 12 );
747
748 stat = cublasDestroy( handle );
749 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
750 }
751 }
752
753 GIVEN( "a 2x2 matrix, double" )
754 {
755 WHEN( "double precision, beta is 0" )
756 {
757 std::vector<double> hA; // This will actually be a vector
758 mx::cuda::cudaPtr<double> dA;
759
760 std::vector<double> hx; // This will actually be a vector
761 mx::cuda::cudaPtr<double> dx;
762
763 std::vector<double> hy;
764 mx::cuda::cudaPtr<double> dy;
765
766 /* Column major order:
767 1 3
768 2 4
769 */
770 hA.resize( 4 );
771 hA[0] = 1;
772 hA[1] = 2;
773 hA[2] = 3;
774 hA[3] = 4;
775
776 dA.resize( 2, 2 );
777 dA.upload( hA.data() );
778
779 hx.resize( 2 );
780 hx[0] = 1;
781 hx[1] = 2;
782
783 dx.upload( hx.data(), hx.size() );
784
785 hy.resize( 2 );
786
787 dy.resize( 2 );
788 dy.initialize();
789
790 double alpha = 1;
791 double beta = 0;
792
793 cublasHandle_t handle;
794 cublasStatus_t stat;
795 stat = cublasCreate( &handle );
796 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
797
798 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
799 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
800
801 dy.download( hy.data() );
802
803 REQUIRE( hy[0] == 7 );
804 REQUIRE( hy[1] == 10 );
805
806 stat = cublasDestroy( handle );
807 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
808 }
809
810 WHEN( "double precision, beta is 1, but y is all 0" )
811 {
812 std::vector<double> hA; // This will actually be a vector
813 mx::cuda::cudaPtr<double> dA;
814
815 std::vector<double> hx; // This will actually be a vector
816 mx::cuda::cudaPtr<double> dx;
817
818 std::vector<double> hy;
819 mx::cuda::cudaPtr<double> dy;
820
821 /* Column major order:
822 1 3
823 2 4
824 */
825 hA.resize( 4 );
826 hA[0] = 1;
827 hA[1] = 2;
828 hA[2] = 3;
829 hA[3] = 4;
830
831 dA.resize( 2, 2 );
832 dA.upload( hA.data() );
833
834 hx.resize( 2 );
835 hx[0] = 1;
836 hx[1] = 2;
837
838 dx.upload( hx.data(), hx.size() );
839
840 hy.resize( 2 );
841
842 dy.resize( 2 );
843 dy.initialize();
844
845 double alpha = 1;
846 double beta = 1;
847
848 cublasHandle_t handle;
849 cublasStatus_t stat;
850 stat = cublasCreate( &handle );
851 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
852
853 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
854 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
855
856 dy.download( hy.data() );
857
858 REQUIRE( hy[0] == 7 );
859 REQUIRE( hy[1] == 10 );
860
861 stat = cublasDestroy( handle );
862 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
863 }
864 WHEN( "double precision, beta is 1, y is [1,2]" )
865 {
866 std::vector<double> hA; // This will actually be a vector
867 mx::cuda::cudaPtr<double> dA;
868
869 std::vector<double> hx; // This will actually be a vector
870 mx::cuda::cudaPtr<double> dx;
871
872 std::vector<double> hy;
873 mx::cuda::cudaPtr<double> dy;
874
875 /* Column major order:
876 1 3
877 2 4
878 */
879 hA.resize( 4 );
880 hA[0] = 1;
881 hA[1] = 2;
882 hA[2] = 3;
883 hA[3] = 4;
884
885 dA.resize( 2, 2 );
886 dA.upload( hA.data() );
887
888 hx.resize( 2 );
889 hx[0] = 1;
890 hx[1] = 2;
891
892 dx.upload( hx.data(), hx.size() );
893
894 hy.resize( 2 );
895 hy[0] = 1;
896 hy[1] = 2;
897
898 dy.resize( 2 );
899 dy.upload( hx.data() );
900
901 double alpha = 1;
902 double beta = 1;
903
904 cublasHandle_t handle;
905 cublasStatus_t stat;
906 stat = cublasCreate( &handle );
907 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
908
909 stat = mx::cuda::cublasTgemv( handle, CUBLAS_OP_N, 2, 2, &alpha, dA(), 2, dx(), 1, &beta, dy(), 1 );
910 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
911
912 dy.download( hy.data() );
913
914 REQUIRE( hy[0] == 8 );
915 REQUIRE( hy[1] == 12 );
916
917 stat = cublasDestroy( handle );
918 REQUIRE( stat == CUBLAS_STATUS_SUCCESS );
919 }
920 }
921}
A wrapper for cuda device pointers.
TEST_CASE("scaling a vector with cublas", "[math::cuda::templateCublas]")
Tests cublasTscal, as well as basic cudaPtr operations.
A template interface to cuBlas.