diff --git a/clients/testing/CMakeLists.txt b/clients/testing/CMakeLists.txt index 8e8632e..c2f3dd7 100644 --- a/clients/testing/CMakeLists.txt +++ b/clients/testing/CMakeLists.txt @@ -90,6 +90,9 @@ target_sources(test_main test_functions_incomplete_LU_factorization_dense.cpp test_functions_sptrsv.cpp test_functions_spgeam.cpp + test_functions_axpy.cpp + test_functions_axpby.cpp + test_functions_axpbypgz.cpp test_functions_transpose.cpp test_functions_transpose_dense.cpp test_functions_ruiz_scaling.cpp diff --git a/clients/testing/test_enums.h b/clients/testing/test_enums.h index 3f8d663..e001e57 100644 --- a/clients/testing/test_enums.h +++ b/clients/testing/test_enums.h @@ -69,6 +69,9 @@ namespace testing CSRILU0, tridiagonal_solver, exclusive_scan, + axpy, + axpby, + axpbypgz, ruiz_scaling, symmetric_ruiz_scaling, unknown @@ -218,6 +221,12 @@ namespace testing return "tridiagonal_solver"; case fixture::exclusive_scan: return "exclusive_scan"; + case fixture::axpy: + return "axpy"; + case fixture::axpby: + return "axpby"; + case fixture::axpbypgz: + return "axpbypgz"; case fixture::ruiz_scaling: return "ruiz_scaling"; case fixture::symmetric_ruiz_scaling: diff --git a/clients/testing/test_functions.h b/clients/testing/test_functions.h index 7fe365a..604fbc1 100644 --- a/clients/testing/test_functions.h +++ b/clients/testing/test_functions.h @@ -42,6 +42,9 @@ namespace testing bool test_tridiagonal_solver(Arguments arg); // math testing + bool test_axpy(Arguments arg); + bool test_axpby(Arguments arg); + bool test_axpbypgz(Arguments arg); bool test_sptrsv(Arguments arg); bool test_spgeam(Arguments arg); bool test_csric0(Arguments arg); diff --git a/clients/testing/test_functions_axpby.cpp b/clients/testing/test_functions_axpby.cpp new file mode 100644 index 0000000..70e4b21 --- /dev/null +++ b/clients/testing/test_functions_axpby.cpp @@ -0,0 +1,110 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "test_functions.h" +#include "utility.h" + +#include +#include +#include + +#include "linalg.h" + +bool testing::test_axpby(Arguments arg) +{ + const size_t size = arg.m; + + linalg::vector x(size); + linalg::vector y(size); + x.fill(2.0); + y.fill(3.0); + + linalg::vector y_copy(size); + y_copy.copy_from(y); + + if(arg.backend == backend::GPU) + { + x.move_to_device(); + y.move_to_device(); + y_copy.move_to_device(); + } + + const double alpha = 1.5; + const double beta = -0.5; + + // Warmup + for(int i = 0; i < 4; i++) + { + linalg::axpby(alpha, x, beta, y); + } + y.copy_from(y_copy); + linalg::synchronize(); + + // Timed solve + auto t1 = std::chrono::high_resolution_clock::now(); + for(int i = 0; i < 10; i++) + { + linalg::axpby(alpha, x, beta, y); + } + linalg::synchronize(); + auto t2 = std::chrono::high_resolution_clock::now(); + + std::chrono::duration ms_float = t2 - t1; + std::cout << "Solve time: " << ms_float.count() << "ms" << std::endl; + + y.copy_from(y_copy); + linalg::axpby(alpha, x, beta, y); + + if(arg.backend == backend::GPU) + { + x.move_to_host(); + y.move_to_host(); + y_copy.move_to_host(); + } + + bool success = true; + for(size_t i = 0; i < size; ++i) + { + const double expected = alpha * 2.0 + beta * 3.0; + if(std::abs(y[i] - expected) > 1e-12) + { + std::cout << "axpby mismatch at index " << i << ": got " << y[i] << ", expected " + << expected << std::endl; + success = false; + } + } + + size_t total_bytes_read = sizeof(double) * ((alpha != 0.0) ? size : 0) + + sizeof(double) * ((beta != 0.0) ? size : 0); + size_t total_bytes_written = sizeof(double) * size; + size_t total_bytes_read_write = total_bytes_read + total_bytes_written; + double total_gbytes = (double)10 * total_bytes_read_write / 1e9; + double bandwidth = total_gbytes / (ms_float.count() / 1e3); + + std::cout << "Effective Bandwidth: " << bandwidth << " GB/s" << std::endl; + + return success; +} diff --git a/clients/testing/test_functions_axpbypgz.cpp b/clients/testing/test_functions_axpbypgz.cpp new file mode 100644 index 0000000..880413c --- /dev/null +++ b/clients/testing/test_functions_axpbypgz.cpp @@ -0,0 +1,116 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "test_functions.h" +#include "utility.h" + +#include +#include +#include + +#include "linalg.h" + +bool testing::test_axpbypgz(Arguments arg) +{ + const size_t size = arg.m; + + linalg::vector x(size); + linalg::vector y(size); + linalg::vector z(size); + x.fill(2.0); + y.fill(3.0); + z.fill(4.0); + + linalg::vector z_copy(size); + z_copy.copy_from(z); + + if(arg.backend == backend::GPU) + { + x.move_to_device(); + y.move_to_device(); + z.move_to_device(); + z_copy.move_to_device(); + } + + const double alpha = 1.5; + const double beta = -0.5; + const double gamma = 2.0; + + // Warmup + for(int i = 0; i < 4; i++) + { + linalg::axpbypgz(alpha, x, beta, y, gamma, z); + } + z.copy_from(z_copy); + linalg::synchronize(); + + // Timed solve + auto t1 = std::chrono::high_resolution_clock::now(); + for(int i = 0; i < 10; i++) + { + linalg::axpbypgz(alpha, x, beta, y, gamma, z); + } + linalg::synchronize(); + auto t2 = std::chrono::high_resolution_clock::now(); + + std::chrono::duration ms_float = t2 - t1; + std::cout << "Solve time: " << ms_float.count() << "ms" << std::endl; + + z.copy_from(z_copy); + linalg::axpbypgz(alpha, x, beta, y, gamma, z); + + if(arg.backend == backend::GPU) + { + x.move_to_host(); + y.move_to_host(); + z.move_to_host(); + z_copy.move_to_host(); + } + + bool success = true; + for(size_t i = 0; i < size; ++i) + { + const double expected = alpha * 2.0 + beta * 3.0 + gamma * 4.0; + if(std::abs(z[i] - expected) > 1e-12) + { + std::cout << "axpbypgz mismatch at index " << i << ": got " << z[i] << ", expected " + << expected << std::endl; + success = false; + } + } + + size_t total_bytes_read = sizeof(double) * ((alpha != 0.0) ? size : 0) + + sizeof(double) * ((beta != 0.0) ? size : 0) + + sizeof(double) * ((gamma != 0.0) ? size : 0); + size_t total_bytes_written = sizeof(double) * size; + size_t total_bytes_read_write = total_bytes_read + total_bytes_written; + double total_gbytes = (double)10 * total_bytes_read_write / 1e9; + double bandwidth = total_gbytes / (ms_float.count() / 1e3); + + std::cout << "Effective Bandwidth: " << bandwidth << " GB/s" << std::endl; + + return success; +} diff --git a/clients/testing/test_functions_axpy.cpp b/clients/testing/test_functions_axpy.cpp new file mode 100644 index 0000000..a024031 --- /dev/null +++ b/clients/testing/test_functions_axpy.cpp @@ -0,0 +1,109 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "test_functions.h" +#include "utility.h" + +#include +#include +#include +#include + +#include "linalg.h" + +bool testing::test_axpy(Arguments arg) +{ + const size_t size = arg.m; + + linalg::vector x(size); + linalg::vector y(size); + x.fill(2.0); + y.fill(3.0); + + linalg::vector y_copy(size); + y_copy.copy_from(y); + + if(arg.backend == backend::GPU) + { + x.move_to_device(); + y.move_to_device(); + y_copy.move_to_device(); + } + + const double alpha = 1.5; + + // Warmup + for(int i = 0; i < 4; i++) + { + linalg::axpy(alpha, x, y); + } + y.copy_from(y_copy); + linalg::synchronize(); + + // Timed solve + auto t1 = std::chrono::high_resolution_clock::now(); + for(int i = 0; i < 10; i++) + { + linalg::axpy(alpha, x, y); + } + linalg::synchronize(); + auto t2 = std::chrono::high_resolution_clock::now(); + + std::chrono::duration ms_float = t2 - t1; + std::cout << "Solve time: " << ms_float.count() << "ms" << std::endl; + + y.copy_from(y_copy); + linalg::axpy(alpha, x, y); + + if(arg.backend == backend::GPU) + { + x.move_to_host(); + y.move_to_host(); + y_copy.move_to_host(); + } + + bool success = true; + for(size_t i = 0; i < size; ++i) + { + const double expected = alpha * 2.0 + 3.0; + if(std::abs(y[i] - expected) > 1e-12) + { + std::cout << "axpy mismatch at index " << i << ": got " << y[i] << ", expected " + << expected << std::endl; + success = false; + } + } + + size_t total_bytes_read = sizeof(double) * ((alpha != 0.0) ? size : 0) + sizeof(double) * size; + size_t total_bytes_written = sizeof(double) * size; + size_t total_bytes_read_write = total_bytes_read + total_bytes_written; + double total_gbytes = (double)10 * total_bytes_read_write / 1e9; + double bandwidth = total_gbytes / (ms_float.count() / 1e3); + + std::cout << "Effective Bandwidth: " << bandwidth << " GB/s" << std::endl; + + return success; +} diff --git a/clients/testing/test_functions_dispatch.cpp b/clients/testing/test_functions_dispatch.cpp index 8c4ef16..e9f4a12 100644 --- a/clients/testing/test_functions_dispatch.cpp +++ b/clients/testing/test_functions_dispatch.cpp @@ -83,6 +83,12 @@ namespace testing { switch(arg.fixture) { + case fixture::axpy: + return test_axpy(arg); + case fixture::axpby: + return test_axpby(arg); + case fixture::axpbypgz: + return test_axpbypgz(arg); case fixture::SpTRSV: return test_sptrsv(arg); case fixture::SpGEAM: diff --git a/clients/testing/test_yaml_loader.h b/clients/testing/test_yaml_loader.h index 880b6e8..5981793 100644 --- a/clients/testing/test_yaml_loader.h +++ b/clients/testing/test_yaml_loader.h @@ -407,7 +407,10 @@ inline testing::fixture string_to_fixture(const std::string& str) {"tridiagonal_solver", testing::fixture::tridiagonal_solver}, {"ruiz_scaling", testing::fixture::ruiz_scaling}, {"symmetric_ruiz_scaling", testing::fixture::symmetric_ruiz_scaling}, - {"exclusive_scan", testing::fixture::exclusive_scan}}; + {"exclusive_scan", testing::fixture::exclusive_scan}, + {"axpy", testing::fixture::axpy}, + {"axpby", testing::fixture::axpby}, + {"axpbypgz", testing::fixture::axpbypgz}}; // Find the string in the map auto it = fixture_map.find(str); diff --git a/clients/testing/tests/CMakeLists.txt b/clients/testing/tests/CMakeLists.txt index 58cd732..3a0275d 100644 --- a/clients/testing/tests/CMakeLists.txt +++ b/clients/testing/tests/CMakeLists.txt @@ -49,6 +49,9 @@ target_sources(test_main test_transpose_dense.cpp test_tridiagonal_solver.cpp test_exclusive_scan.cpp + test_axpy.cpp + test_axpby.cpp + test_axpbypgz.cpp test_ruiz_scaling.cpp test_symmetric_ruiz_scaling.cpp ) diff --git a/clients/testing/tests/test_axpby.cpp b/clients/testing/tests/test_axpby.cpp new file mode 100644 index 0000000..a52856c --- /dev/null +++ b/clients/testing/tests/test_axpby.cpp @@ -0,0 +1,29 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2025-2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "../test.h" + +INSTANTIATE_TEST(math, axpby, axpby, "tests/test_axpby.yaml"); diff --git a/clients/testing/tests/test_axpby.yaml b/clients/testing/tests/test_axpby.yaml new file mode 100644 index 0000000..8bcc567 --- /dev/null +++ b/clients/testing/tests/test_axpby.yaml @@ -0,0 +1,16 @@ +Tests: + quick_ci: + m: [10, 33, 67, 123, 200, 310, 465, 576, 662, 789, 890, 1001] + backend: [CPU] + + small: + m: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] + backend: [CPU, GPU] + + medium: + m: [565, 651, 768, 808, 950, 1012, 1435, 1867, 2048, 2345, 2567, 3001, 3456] + backend: [CPU, GPU] + + large: + m: [6598, 10234, 20480, 40960, 81920, 163840, 768193] + backend: [CPU, GPU] diff --git a/clients/testing/tests/test_axpbypgz.cpp b/clients/testing/tests/test_axpbypgz.cpp new file mode 100644 index 0000000..8f2610c --- /dev/null +++ b/clients/testing/tests/test_axpbypgz.cpp @@ -0,0 +1,29 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2025-2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "../test.h" + +INSTANTIATE_TEST(math, axpbypgz, axpbypgz, "tests/test_axpbypgz.yaml"); diff --git a/clients/testing/tests/test_axpbypgz.yaml b/clients/testing/tests/test_axpbypgz.yaml new file mode 100644 index 0000000..53ddfee --- /dev/null +++ b/clients/testing/tests/test_axpbypgz.yaml @@ -0,0 +1,16 @@ +Tests: + quick_ci: + m: [9, 55, 78, 134, 212, 320, 456, 539, 682, 713, 857, 1023] + backend: [CPU] + + small: + m: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] + backend: [CPU, GPU] + + medium: + m: [581, 612, 739, 825, 1132, 1867, 2048, 2345, 2984, 3198, 3847] + backend: [CPU, GPU] + + large: + m: [2367, 3810, 4762, 6593, 7615, 8028, 10234, 20480, 40960, 81920, 163840, 987231] + backend: [CPU, GPU] diff --git a/clients/testing/tests/test_axpy.cpp b/clients/testing/tests/test_axpy.cpp new file mode 100644 index 0000000..51ac989 --- /dev/null +++ b/clients/testing/tests/test_axpy.cpp @@ -0,0 +1,29 @@ +//******************************************************************************** +// +// MIT License +// +// Copyright(c) 2025-2026 James Sandham +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this softwareand associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//******************************************************************************** + +#include "../test.h" + +INSTANTIATE_TEST(math, axpy, axpy, "tests/test_axpy.yaml"); diff --git a/clients/testing/tests/test_axpy.yaml b/clients/testing/tests/test_axpy.yaml new file mode 100644 index 0000000..0487b9c --- /dev/null +++ b/clients/testing/tests/test_axpy.yaml @@ -0,0 +1,16 @@ +Tests: + quick_ci: + m: [8, 22, 56, 101, 269, 303, 456, 567, 610, 718, 834, 1092] + backend: [CPU] + + small: + m: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] + backend: [CPU, GPU] + + medium: + m: [555, 678, 801, 978, 1024, 1436, 1867, 2048, 2345, 2567, 3001, 3456] + backend: [CPU, GPU] + + large: + m: [2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576] + backend: [CPU, GPU]