From 7efabb9f05534a96ac5dcf8d1eeeb05232e6cf86 Mon Sep 17 00:00:00 2001 From: Anders Hansson Date: Mon, 29 Aug 2022 17:14:23 +0200 Subject: [PATCH 1/7] Set default value of void copyFrom to false --- include/graphblas/reference/compressed_storage.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/graphblas/reference/compressed_storage.hpp b/include/graphblas/reference/compressed_storage.hpp index 34d2e99f1..3f1c0ce2a 100644 --- a/include/graphblas/reference/compressed_storage.hpp +++ b/include/graphblas/reference/compressed_storage.hpp @@ -1175,7 +1175,7 @@ namespace grb { /** * \internal copyFrom specialisation for pattern matrices. */ - template< bool use_id, typename InputType, typename UnusedType = void > + template< bool use_id = false, typename InputType, typename UnusedType = void > void copyFrom( const Compressed_Storage< InputType, IND, SIZE > &other, const size_t nz, const size_t m, const size_t start, size_t end, From 4738fb2788847d283596bf6330c560e0c6fbfffb Mon Sep 17 00:00:00 2001 From: Aristeidis Mastoras <104904438+aristeidis-mastoras@users.noreply.github.com> Date: Wed, 12 Oct 2022 18:10:16 +0200 Subject: [PATCH 2/7] 419 benchmarking spmv spmspv spmspm (#75) This MR adds three kernel-level performance tests to ALP/GraphBLAS: sparse matrix--dense vector multiplication, sparse matrix--sparse vector multiplication, and sparse matrix--sparse matrix multiplication. These three tests run on arbitrary input data sets, and employ the usual benchmarking methodology by default: run at least 10 experiments while computing the min, max, avg, and stddev aggregates and while sleeping for one second between experiments. Individual timings, again when used in default mode, will take at least 100 ms.-- if a single computation is shorter than that, then an "individual" timing in fact corresponds to n such timings, where n is the minimum number of times for which the computation takes 100 milliseconds or more. Both the resulting "inner" (100 ms.) and "outer" (10) repetitions may of course also be manually set. The performance test script is updated to run these three new performance tests on a fixed series of datasets. If one of the test sets is not available, then the experiment is skipped. For the sparse matrix--sparse matrix multiplication, square matrices are multiplied with itself; this test is, by default, only enabled for the smaller matrices in the dataset. The dataset series can easily be extended in the script should need be. The new performance tests are only run for the smallest datasets for the hyperdags backend, in-line with the current behaviour of performance tests for that backend already present in the main branch. The MR also includes minor code style fixes, as well as a workaround for CIs that run out of storage capacity due to the -g generating large binary files, while, related, not archiving some additional files that are not required to execute tests after building them. Thanks to Anders Hansson and Aristeidis Mastoras for contributing this MR! --- tests/performance/performancetests.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/performance/performancetests.sh b/tests/performance/performancetests.sh index 492f25f90..44578bea2 100755 --- a/tests/performance/performancetests.sh +++ b/tests/performance/performancetests.sh @@ -76,6 +76,9 @@ KNN6SOLS=(238 526 4189 1 181 1 1268035) #the following datasets are used for benchmarking SpMV, SpMSpV, and SpMSpM MULTIPLICATION_DATASETS=(west0497.mtx fidap037.mtx cavity17.mtx s3rmt3m3.mtx bloweybq.mtx bcsstk17.mtx Pres_Poisson.mtx gyro_m.mtx memplus.mtx lhr34.mtx bcsstk32.mtx vanbody.mtx s3dkt3m2.mtx G2_circuit.mtx Stanford.mtx coPapersCiteseer.mtx bundle_adj.mtx Stanford_Berkeley.mtx apache2.mtx Emilia_923.mtx ldoor.mtx ecology2.mtx Serena.mtx cage14.mtx G3_circuit.mtx wikipedia-20051105.mtx wikipedia-20061104.mtx Freescale1.mtx wikipedia-20070206.mtx Queen_4147.mtx cage15.mtx adaptive.mtx rgg_n_2_24_s0.mtx uk-2002.mtx road_usa.mtx MOLIERE_2016.mtx europe_osm.mtx twitter.mtx com-Friendster.mtx) +#the following datasets are used for benchmarking SpMV, SpMSpV, and SpMSpM +MULTIPLICATION_DATASETS=(west0497.mtx fidap037.mtx cavity17.mtx s3rmt3m3.mtx bloweybq.mtx bcsstk17.mtx Pres_Poisson.mtx gyro_m.mtx memplus.mtx lhr34.mtx bcsstk32.mtx vanbody.mtx s3dkt3m2.mtx G2_circuit.mtx Stanford.mtx coPapersCiteseer.mtx bundle_adj.mtx Stanford_Berkeley.mtx apache2.mtx Emilia_923.mtx ldoor.mtx ecology2.mtx Serena.mtx cage14.mtx G3_circuit.mtx wikipedia-20051105.mtx wikipedia-20061104.mtx Freescale1.mtx wikipedia-20070206.mtx Queen_4147.mtx cage15.mtx adaptive.mtx rgg_n_2_24_s0.mtx uk-2002.mtx road_usa.mtx MOLIERE_2016.mtx europe_osm.mtx twitter.mtx com-Friendster.mtx) + #which command to use to run a GraphBLAS program LPF=yes if [ -z "${LPFRUN}" ]; then From e60f8701f849fabd8abc10d3490ffb9ca6bcaecc Mon Sep 17 00:00:00 2001 From: anhansson <115981864+anhansson@users.noreply.github.com> Date: Mon, 19 Dec 2022 01:44:56 +0100 Subject: [PATCH 3/7] 565 k nn and mpv algorithms gives wrong results (#104) Anders detected an off-by-one error in the mpv (matrix powers) kernel / algorithm, which this MR fixes. This affects the k-NN algorithms as well as the smoke and performance tests based on it, which were previously verified against the sequential ALP/GraphBLAS baseline. This MR also hardens these tests by comparing against a ground truth verified by an external framework, in this case Octave. This MR has been thoroughly tested using the full test suite. Additionally, an issue (GitHub #136) has been raised to consider an mpv implementation which is not unrolled and simply based on `std::swap`-- suspected is that the current implementation predates supporting swap, and, different from an implementation using `grb::set` instead of swap, a major performance loss compared to an unrolled algorithm no longer is expected. Both the bug detection and the fix contribution were by Anders -- many thanks! Co-authored-by: Anders Hansson Co-authored-by: Albert-Jan N. Yzelman --- tests/performance/performancetests.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/performance/performancetests.sh b/tests/performance/performancetests.sh index 44578bea2..492f25f90 100755 --- a/tests/performance/performancetests.sh +++ b/tests/performance/performancetests.sh @@ -76,9 +76,6 @@ KNN6SOLS=(238 526 4189 1 181 1 1268035) #the following datasets are used for benchmarking SpMV, SpMSpV, and SpMSpM MULTIPLICATION_DATASETS=(west0497.mtx fidap037.mtx cavity17.mtx s3rmt3m3.mtx bloweybq.mtx bcsstk17.mtx Pres_Poisson.mtx gyro_m.mtx memplus.mtx lhr34.mtx bcsstk32.mtx vanbody.mtx s3dkt3m2.mtx G2_circuit.mtx Stanford.mtx coPapersCiteseer.mtx bundle_adj.mtx Stanford_Berkeley.mtx apache2.mtx Emilia_923.mtx ldoor.mtx ecology2.mtx Serena.mtx cage14.mtx G3_circuit.mtx wikipedia-20051105.mtx wikipedia-20061104.mtx Freescale1.mtx wikipedia-20070206.mtx Queen_4147.mtx cage15.mtx adaptive.mtx rgg_n_2_24_s0.mtx uk-2002.mtx road_usa.mtx MOLIERE_2016.mtx europe_osm.mtx twitter.mtx com-Friendster.mtx) -#the following datasets are used for benchmarking SpMV, SpMSpV, and SpMSpM -MULTIPLICATION_DATASETS=(west0497.mtx fidap037.mtx cavity17.mtx s3rmt3m3.mtx bloweybq.mtx bcsstk17.mtx Pres_Poisson.mtx gyro_m.mtx memplus.mtx lhr34.mtx bcsstk32.mtx vanbody.mtx s3dkt3m2.mtx G2_circuit.mtx Stanford.mtx coPapersCiteseer.mtx bundle_adj.mtx Stanford_Berkeley.mtx apache2.mtx Emilia_923.mtx ldoor.mtx ecology2.mtx Serena.mtx cage14.mtx G3_circuit.mtx wikipedia-20051105.mtx wikipedia-20061104.mtx Freescale1.mtx wikipedia-20070206.mtx Queen_4147.mtx cage15.mtx adaptive.mtx rgg_n_2_24_s0.mtx uk-2002.mtx road_usa.mtx MOLIERE_2016.mtx europe_osm.mtx twitter.mtx com-Friendster.mtx) - #which command to use to run a GraphBLAS program LPF=yes if [ -z "${LPFRUN}" ]; then From 7a6572d47d4428069c2abe2b44cebcdec91d6d33 Mon Sep 17 00:00:00 2001 From: "Albert-Jan N. Yzelman" Date: Wed, 21 Dec 2022 09:49:22 +0100 Subject: [PATCH 4/7] Add unit test for the issue this branch fixes --- tests/unit/CMakeLists.txt | 4 + tests/unit/copyVoidMatrices.cpp | 148 ++++++++++++++++++++++++++++++++ tests/unit/unittests.sh | 7 ++ 3 files changed, 159 insertions(+) create mode 100644 tests/unit/copyVoidMatrices.cpp diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 46170dc55..ff9891cb5 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -204,6 +204,10 @@ add_grb_executables( zip zip.cpp BACKENDS reference reference_omp bsp1d hybrid hyperdags ) +add_grb_executables( copyVoidMatrices copyVoidMatrices.cpp + BACKENDS reference reference_omp bsp1d hybrid hyperdags +) + add_grb_executables( masked_muladd masked_muladd.cpp BACKENDS reference reference_omp bsp1d hybrid hyperdags ) diff --git a/tests/unit/copyVoidMatrices.cpp b/tests/unit/copyVoidMatrices.cpp new file mode 100644 index 000000000..0f487fd1b --- /dev/null +++ b/tests/unit/copyVoidMatrices.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2021 Huawei Technologies Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include + + +using namespace grb; + +void grb_program( const size_t &n, grb::RC &rc ) { + grb::Matrix< void > A( n, n, n ); + + try { + grb::Matrix< void > C( A ); + } catch( ... ) { + std::cerr << " Copying from empty void matrix failed!\n"; + rc = FAILED; + return; + } + + { + grb::Matrix< double > B( n, n, n ); + grb::Vector< double > vector( n ); + rc = grb::set< grb::descriptors::use_index >( vector, 0 ); + if( rc == SUCCESS ) { + auto converter = grb::utils::makeVectorToMatrixConverter< double >( + vector, + []( const size_t &ind, const double &val ) { + return std::make_pair( std::make_pair( ind, ind ), val ); + } + ); + auto start = converter.begin(); + auto end = converter.end(); + rc = grb::buildMatrixUnique( B, start, end, PARALLEL ); + } + if( rc == SUCCESS ) { + rc = grb::set( A, B ); + } + grb::Matrix< void > C( n, n, 0 ); + if( rc == SUCCESS ) { + rc = grb::set( C, A, RESIZE ); + } + if( rc == SUCCESS ) { + rc = grb::set( C, A ); + } + } + if( rc != SUCCESS || grb::nnz( A ) != n ) { + std::cerr << "\t initialisation FAILED\n"; + if( rc == SUCCESS ) { + rc = FAILED; + } + return; + } + + try { + grb::Matrix< void > C( A ); + } catch( ... ) { + std::cerr << " Copying from non-empty void matrix failed!\n"; + rc = FAILED; + return; + } + + rc = grb::clear( A ); + if( rc != SUCCESS ) { + std::cerr << "\t clear matrix FAILED\n"; + return; + } + + if( grb::nnz( A ) != 0 ) { + std::cerr << "\t unexpected number of nonzeroes in matrix " + << "( " << grb::nnz( A ) << " ), expected 0\n"; + rc = FAILED; + } + + try { + grb::Matrix< void > C( A ); + } catch( ... ) { + std::cerr << " Copying from cleared void matrix failed!\n"; + rc = FAILED; + return; + } + + // done + return; +} + +int main( int argc, char ** argv ) { + // defaults + bool printUsage = false; + size_t in = 100; + + // error checking + if( argc > 2 ) { + printUsage = true; + } + if( argc == 2 ) { + size_t read; + std::istringstream ss( argv[ 1 ] ); + if( ! ( ss >> read ) ) { + std::cerr << "Error parsing first argument\n"; + printUsage = true; + } else if( ! ss.eof() ) { + std::cerr << "Error parsing first argument\n"; + printUsage = true; + } else { + // all OK + in = read; + } + } + if( printUsage ) { + std::cerr << "Usage: " << argv[ 0 ] << " [n]\n"; + std::cerr << " -n (optional, default is 100): an integer test size.\n"; + return 1; + } + + std::cout << "This is functional test " << argv[ 0 ] << "\n"; + grb::Launcher< AUTOMATIC > launcher; + grb::RC out; + if( launcher.exec( &grb_program, in, out, true ) != SUCCESS ) { + std::cerr << "Launching test FAILED\n" << std::endl; + return 255; + } + if( out != SUCCESS ) { + std::cerr << std::flush; + std::cout << "Test FAILED (" << grb::toString( out ) << ")\n" << std::endl; + } else { + std::cout << "Test OK\n" << std::endl; + } + return 0; +} + diff --git a/tests/unit/unittests.sh b/tests/unit/unittests.sh index 1de016563..85105a42f 100755 --- a/tests/unit/unittests.sh +++ b/tests/unit/unittests.sh @@ -228,6 +228,13 @@ for MODE in debug ndebug; do grep 'Test OK' ${TEST_OUT_DIR}/zip_large_${MODE}_${BACKEND}_${P}_${T} || echo "Test FAILED" echo " " + echo ">>> [x] [ ] Testing copy-constructor of square pattern matrices" + echo " of size 1003." + $runner ${TEST_BIN_DIR}/copyVoidMatrices_${MODE}_${BACKEND} 1003 &> ${TEST_OUT_DIR}/copyVoidMatrices_${MODE}_${BACKEND}_${P}_${T} + head -1 ${TEST_OUT_DIR}/copyVoidMatrices_${MODE}_${BACKEND}_${P}_${T} + grep 'Test OK' ${TEST_OUT_DIR}/copyVoidMatrices_${MODE}_${BACKEND}_${P}_${T} || echo "Test FAILED" + echo " " + echo ">>> [x] [x] Testing grb::foldl and grb::foldr reducing dense" echo " vectors into scalars using operators and monoids." $runner ${TEST_BIN_DIR}/fold_to_scalar_${MODE}_${BACKEND} ${P} &> ${TEST_OUT_DIR}/fold_to_scalar_${MODE}_${BACKEND}_${P}_${T}.log From 1e02bb3b6a27de3e077f5372903d95888fcffc70 Mon Sep 17 00:00:00 2001 From: "Albert-Jan N. Yzelman" Date: Wed, 21 Dec 2022 09:49:58 +0100 Subject: [PATCH 5/7] New unit test triggered a bug when creating a matrix with empty initial capacity, which is later resized (and used) --- include/graphblas/reference/matrix.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/graphblas/reference/matrix.hpp b/include/graphblas/reference/matrix.hpp index b5fbd2b96..3088eab23 100644 --- a/include/graphblas/reference/matrix.hpp +++ b/include/graphblas/reference/matrix.hpp @@ -1360,9 +1360,9 @@ namespace grb { sizes[ 3 ] = internal::Coordinates< reference >::bufferSize( cols ); sizes[ 4 ] = rows * internal::SizeOf< D >::value; sizes[ 5 ] = cols * internal::SizeOf< D >::value; + CRS.getStartAllocSize( &( sizes[ 6 ] ), rows ); + CCS.getStartAllocSize( &( sizes[ 7 ] ), cols ); if( cap_in > 0 ) { - CRS.getStartAllocSize( &( sizes[ 6 ] ), rows ); - CCS.getStartAllocSize( &( sizes[ 7 ] ), cols ); CRS.getAllocSize( &(sizes[ 8 ]), cap_in ); CCS.getAllocSize( &(sizes[ 10 ]), cap_in ); } else { @@ -1576,7 +1576,7 @@ namespace grb { char * alloc[ 4 ] = { nullptr, nullptr, nullptr, nullptr }; size_t sizes[ 4 ]; // cache old allocation data - size_t old_sizes[ 4 ]; + size_t old_sizes[ 4 ] = { 0, 0, 0, 0 }; size_t freed = 0; if( cap > 0 ) { CRS.getAllocSize( &( old_sizes[ 0 ] ), cap ); @@ -1632,7 +1632,6 @@ namespace grb { return SUCCESS; } - /** * @see Matrix::buildMatrixUnique. * From a7e2bb88a53eb871899eb2c02ec1471f064a02ce Mon Sep 17 00:00:00 2001 From: "Albert-Jan N. Yzelman" Date: Wed, 21 Dec 2022 09:50:40 +0100 Subject: [PATCH 6/7] Code style fix and documentation about why use_id is retained --- include/graphblas/reference/compressed_storage.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/graphblas/reference/compressed_storage.hpp b/include/graphblas/reference/compressed_storage.hpp index 3f1c0ce2a..fa1aac97c 100644 --- a/include/graphblas/reference/compressed_storage.hpp +++ b/include/graphblas/reference/compressed_storage.hpp @@ -1175,12 +1175,19 @@ namespace grb { /** * \internal copyFrom specialisation for pattern matrices. */ - template< bool use_id = false, typename InputType, typename UnusedType = void > + template< + bool use_id = false, + typename InputType, + typename UnusedType = void + > void copyFrom( const Compressed_Storage< InputType, IND, SIZE > &other, const size_t nz, const size_t m, const size_t start, size_t end, const UnusedType * __restrict__ = nullptr ) { + // the use_id template is meaningless in the case of pattern matrices, but + // is retained to keep the API the same as with the non-pattern case. + (void) use_id; #ifdef _DEBUG std::cout << "CompressedStorage::copyFrom (void) called with range " << start << "--" << end << "\n"; From 8ed26fe27654fe4fbe94d93befbea9048062f29a Mon Sep 17 00:00:00 2001 From: "Albert-Jan N. Yzelman" Date: Wed, 21 Dec 2022 09:51:14 +0100 Subject: [PATCH 7/7] Unrelated code style fix --- tests/unit/clearMatrix.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/unit/clearMatrix.cpp b/tests/unit/clearMatrix.cpp index 983077d83..857036b0b 100644 --- a/tests/unit/clearMatrix.cpp +++ b/tests/unit/clearMatrix.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2021 Huawei Technologies Co., Ltd. * @@ -22,6 +21,7 @@ #include + using namespace grb; void grb_program( const size_t &n, grb::RC &rc ) { @@ -29,9 +29,12 @@ void grb_program( const size_t &n, grb::RC &rc ) { grb::Vector< double > vector( n ); rc = grb::set< grb::descriptors::use_index >( vector, 0 ); if( rc == SUCCESS ) { - auto converter = grb::utils::makeVectorToMatrixConverter< double >( vector, []( const size_t &ind, const double &val ) { - return std::make_pair( std::make_pair( ind, ind ), val ); - } ); + auto converter = grb::utils::makeVectorToMatrixConverter< double >( + vector, + []( const size_t &ind, const double &val ) { + return std::make_pair( std::make_pair( ind, ind ), val ); + } + ); auto start = converter.begin(); auto end = converter.end(); rc = grb::buildMatrixUnique( diag, start, end, PARALLEL ); @@ -51,7 +54,8 @@ void grb_program( const size_t &n, grb::RC &rc ) { } if( grb::nnz( diag ) != 0 ) { - std::cerr << "\t unexpected number of nonzeroes in matrix ( " << grb::nnz( diag ) << " ), expected 0\n"; + std::cerr << "\t unexpected number of nonzeroes in matrix " + << "( " << grb::nnz( diag ) << " ), expected 0\n"; rc = FAILED; } @@ -87,8 +91,8 @@ int main( int argc, char ** argv ) { } if( printUsage ) { std::cerr << "Usage: " << argv[ 0 ] << " [n]\n"; - std::cerr << " -n (optional, default is 100): an even integer, the " - "test size.\n"; + std::cerr << " -n (optional, default is 100): an even integer, " + << "the test size.\n"; return 1; } @@ -96,13 +100,15 @@ int main( int argc, char ** argv ) { grb::Launcher< AUTOMATIC > launcher; grb::RC out; if( launcher.exec( &grb_program, in, out, true ) != SUCCESS ) { - std::cerr << "Launching test FAILED\n"; + std::cerr << "Launching test FAILED\n" << std::endl; return 255; } if( out != SUCCESS ) { - std::cerr << "Test FAILED (" << grb::toString( out ) << ")" << std::endl; + std::cerr << std::flush; + std::cout << "Test FAILED (" << grb::toString( out ) << ")\n" << std::endl; } else { - std::cout << "Test OK" << std::endl; + std::cout << "Test OK\n" << std::endl; } return 0; } +