Skip to content

Commit d7b1d0a

Browse files
committed
clean up string handling in unit tests; built tests based on MTX_FMT in config.mk; make MTX_FMT flexible in github test runner
1 parent 7fa4bff commit d7b1d0a

File tree

17 files changed

+636
-304
lines changed

17 files changed

+636
-304
lines changed

.github/workflows/single-platform.yml

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,54 @@ jobs:
7171
esac
7272
7373
# Export TOOLCHAIN for the Makefile
74-
TOOLCHAIN="${{ matrix.compiler }}"
75-
76-
# Update build configuration flags in config.mk
77-
sed -E -i \
78-
-e 's/^(ENABLE_MPI[[:space:]]*\?=[[:space:]]*).*/\1true/' \
79-
-e 's/^(ENABLE_OPENMP[[:space:]]*\?=[[:space:]]*).*/\1false/' \
80-
-e 's/^(MTX_FMT[[:space:]]*\?=[[:space:]]*).*/\1SCS/' \
81-
-e "s/^(TOOLCHAIN[[:space:]]*\?=[[:space:]]*).*/\1${TOOLCHAIN}/" \
82-
config.mk
83-
84-
# Build the main project
85-
make
86-
87-
# Move into the tests directory
88-
cd tests
89-
# Build test suite
90-
make
91-
# Run the tests
92-
./runTests
74+
export TOOLCHAIN="${{ matrix.compiler }}"
75+
76+
# Define reusable logic
77+
run_tests() {
78+
local FMT=$1
79+
echo ">>> Building and testing with $FMT matrix format."
80+
81+
sed -E -i \
82+
-e 's/^(ENABLE_MPI[[:space:]]*\?=).*/\1true/' \
83+
-e 's/^(ENABLE_OPENMP[[:space:]]*\?=).*/\1false/' \
84+
-e "s/^(MTX_FMT[[:space:]]*\?=).*/\1$FMT/" \
85+
-e "s/^(TOOLCHAIN[[:space:]]*\?=).*/\1${{ matrix.compiler }}/" \
86+
config.mk
87+
88+
make -j # Build sparseBench
89+
cd tests
90+
make -j # Build tests
91+
mpirun -n 1 ./runTests # Run (single rank) tests
92+
cd ..
93+
}
94+
95+
# Run both test formats
96+
run_tests CRS
97+
run_tests SCS
98+
99+
# # Set build configuration flags to CRS in config.mk
100+
# sed -E -i \
101+
# -e 's/^(ENABLE_MPI[[:space:]]*\?=[[:space:]]*).*/\1true/' \
102+
# -e 's/^(ENABLE_OPENMP[[:space:]]*\?=[[:space:]]*).*/\1false/' \
103+
# -e 's/^(MTX_FMT[[:space:]]*\?=[[:space:]]*).*/\1CRS/' \
104+
# -e "s/^(TOOLCHAIN[[:space:]]*\?=[[:space:]]*).*/\1${TOOLCHAIN}/" \
105+
# config.mk
106+
107+
# make # Build the main project
108+
# cd tests # Move into the tests directory
109+
# make # Build test suite
110+
# mpirun -n 1 ./runTests # Run the (single rank) tests
111+
112+
# cd ../
113+
# # Set build configuration flags to SCS in config.mk
114+
# sed -E -i \
115+
# -e 's/^(ENABLE_MPI[[:space:]]*\?=[[:space:]]*).*/\1true/' \
116+
# -e 's/^(ENABLE_OPENMP[[:space:]]*\?=[[:space:]]*).*/\1false/' \
117+
# -e 's/^(MTX_FMT[[:space:]]*\?=[[:space:]]*).*/\1SCS/' \
118+
# -e "s/^(TOOLCHAIN[[:space:]]*\?=[[:space:]]*).*/\1${TOOLCHAIN}/" \
119+
# config.mk
120+
121+
# make # Build the main project
122+
# cd tests # Move into the tests directory
123+
# make # Build test suite
124+
# mpirun -n 1 ./runTests # Run the (single rank) tests

src/comm.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ void commPrintConfig(
714714
#endif
715715
}
716716

717+
// TODO: Unify matrix dumping
717718
void commMatrixDump(Comm* c, Matrix* m)
718719
{
719720
int rank = c->rank;
@@ -726,30 +727,28 @@ void commMatrixDump(Comm* c, Matrix* m)
726727
CG_FLOAT* val = m->val;
727728

728729
if (commIsMaster(c)) {
729-
printf("Matrix: %d total non zeroes, total number of rows %d\n",
730+
fprintf(c->logFile,
731+
"Matrix: %d total non zeroes, total number of rows %d\n",
730732
m->totalNnz,
731733
m->totalNr);
732734
}
733735

734736
for (int i = 0; i < size; i++) {
735737
if (i == rank) {
736-
printf("Rank %d: number of rows %d\n", rank, numRows);
738+
fprintf(c->logFile, "Rank %d: number of rows %d\n", rank, numRows);
737739

738740
for (int rowID = 0; rowID < numRows; rowID++) {
739-
printf("Row [%d]: ", rowID);
741+
fprintf(c->logFile, "Row [%d]: ", rowID);
740742

741743
for (int rowEntry = rowPtr[rowID]; rowEntry < rowPtr[rowID + 1];
742744
rowEntry++) {
743-
printf("[%d]:%.2f ", colInd[rowEntry], val[rowEntry]);
745+
fprintf(c->logFile, "[%d]:%.2f ", colInd[rowEntry], val[rowEntry]);
744746
}
745747

746-
printf("\n");
748+
fprintf(c->logFile, "\n");
747749
}
748-
fflush(stdout);
750+
fflush(c->logFile);
749751
}
750-
#ifdef _MPI
751-
MPI_Barrier(MPI_COMM_WORLD);
752-
#endif
753752
}
754753
#endif /* ifdef CRS */
755754
#ifdef SCS
@@ -802,6 +801,9 @@ void commMatrixDump(Comm* c, Matrix* m)
802801
}
803802
fprintf(c->logFile, "\n");
804803
#endif /* ifdef SCS */
804+
#ifdef _MPI
805+
MPI_Barrier(MPI_COMM_WORLD);
806+
#endif
805807
}
806808

807809
void commVectorDump(Comm* c, CG_FLOAT* v, CG_UINT size, char* name)

tests/Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# # # DL 2025.04.04
1+
# # # DL 2025.06.25
22
# # # Collection of unit tests
33

44
include ../config.mk
@@ -18,8 +18,8 @@ LINKS := $(filter-out ${TC_DIR}/main.o, $(wildcard ${TC_DIR}/*.o))
1818
TARGET=runTests
1919

2020
# Collect objects from all test modules
21-
MOD1_OBJECTS=${MOD1}/convertSCS.o ${MOD1}/matrixTests.o
22-
MOD2_OBJECTS=${MOD2}/spmvSCS.o ${MOD2}/solverTests.o
21+
MOD1_OBJECTS=${MOD1}/convert$(MTX_FMT).o ${MOD1}/matrixTests.o
22+
MOD2_OBJECTS=${MOD2}/spmv$(MTX_FMT).o ${MOD2}/solverTests.o
2323
OBJECTS := $(shell echo $(MOD1_OBJECTS) $(MOD2_OBJECTS) | tr ' ' '\n' | sort -u | tr '\n' ' ')
2424

2525
# Always leave debugging flag on
@@ -33,7 +33,7 @@ endif
3333

3434
.PHONY: all clean
3535

36-
all: $(TARGET)
36+
all: clean $(TARGET)
3737

3838
clean:
3939
rm -f $(TARGET) $(OBJECTS) runTests.o
@@ -50,12 +50,12 @@ runTests.o: runTests.c
5050
$(MOD1)/matrixTests.o: $(MOD1)/matrixTests.c
5151
$(CC) $(CFLAGS) -c -o $@ $<
5252

53-
$(MOD1)/convertSCS.o: $(MOD1)/convertSCS.c
53+
$(MOD1)/convert$(MTX_FMT).o: $(MOD1)/convert$(MTX_FMT).c
5454
$(CC) $(CFLAGS) -c -o $@ $<
5555

5656
# Module 2 tests: solver
5757
$(MOD2)/solverTests.o: $(MOD2)/solverTests.c
5858
$(CC) $(CFLAGS) -c -o $@ $<
5959

60-
$(MOD2)/spmvSCS.o: $(MOD2)/spmvSCS.c
60+
$(MOD2)/spmv$(MTX_FMT).o: $(MOD2)/spmv$(MTX_FMT).c
6161
$(CC) $(CFLAGS) -c -o $@ $<

tests/common.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
#include <stdio.h>
55
#include <string.h>
66

7-
#define SET_ARGS(i, C_val, sigma_val) \
7+
#define SET_SCS_ARGS(i, C_val, sigma_val) \
88
{ \
9-
args[i]->C = (C_val); \
10-
args[i]->sigma = (sigma_val); \
9+
args[i].C = (C_val); \
10+
args[i].sigma = (sigma_val); \
1111
}
1212

1313
typedef int (*TestFunc)(void* config, const char* dataDir);
@@ -36,11 +36,9 @@ typedef struct {
3636
}
3737
#endif
3838

39-
#ifndef FORMAT_AND_STRIP_MATRIX_FILE
40-
#define FORMAT_AND_STRIP_MATRIX_FILE(A, entry, C_str, sigma_str, arguments) \
39+
#ifndef STRIP_MATRIX_FILE
40+
#define STRIP_MATRIX_FILE(entry) \
4141
{ \
42-
sprintf((C_str), "%d", arguments->C); \
43-
sprintf((sigma_str), "%d", arguments->sigma); \
4442
char* dot = strrchr((entry)->d_name, '.'); \
4543
if (dot != NULL) { \
4644
*dot = '\0'; \
@@ -77,7 +75,8 @@ typedef struct {
7775
#define ARRAY_ALIGNMENT 64
7876
#endif
7977

80-
static int diff_files(const char* expectedData, const char* reportedData)
78+
static int diff_files(
79+
const char* expectedData, const char* reportedData, int offset)
8180
{
8281
FILE* f1 = fopen(expectedData, "r");
8382
FILE* f2 = fopen(reportedData, "r");
@@ -90,6 +89,19 @@ static int diff_files(const char* expectedData, const char* reportedData)
9089
char line1[2048], line2[2048];
9190
int line_number = 1; // Line number counter
9291

92+
// Skip offset lines in reported file (f2)
93+
for (int i = 0; i < offset; i++) {
94+
if (fgets(line1, sizeof(line1), f2) == NULL) {
95+
printf("Reported file %s has fewer than %d lines to skip.\n",
96+
reportedData,
97+
offset);
98+
fclose(f1);
99+
fclose(f2);
100+
return 1;
101+
}
102+
line_number++;
103+
}
104+
93105
// Compare lines until one of the files ends
94106
while (fgets(line1, sizeof(line1), f1) != NULL &&
95107
fgets(line2, sizeof(line2), f2) != NULL) {

tests/data/expected/test0_CRS.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Matrix: 18 total non zeroes, total number of rows 10
2+
Rank 0: number of rows 10
3+
Row [0]: [0]:11.00 [3]:14.00 [4]:15.00
4+
Row [1]: [1]:22.00
5+
Row [2]: [0]:31.00 [1]:32.00 [2]:33.00
6+
Row [3]: [3]:44.00
7+
Row [4]: [4]:55.00
8+
Row [5]: [5]:66.00 [8]:69.00 [9]:610.00
9+
Row [6]: [6]:77.00
10+
Row [7]: [5]:86.00 [6]:87.00 [7]:88.00
11+
Row [8]: [8]:99.00
12+
Row [9]: [9]:1010.00
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
vec = 40.000000, 22.000000, 96.000000, 44.000000, 55.000000, 745.000000, 77.000000, 261.000000, 99.000000, 1010.000000,
1+
element[0] 40.000000
2+
element[1] 22.000000
3+
element[2] 96.000000
4+
element[3] 44.000000
5+
element[4] 55.000000
6+
element[5] 745.000000
7+
element[6] 77.000000
8+
element[7] 261.000000
9+
element[8] 99.000000
10+
element[9] 1010.000000

tests/data/expected/test8_CRS.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Matrix: 27 total non zeroes, total number of rows 10
2+
Rank 0: number of rows 10
3+
Row [0]: [0]:11.00 [3]:14.00 [4]:15.00 [9]:110.00
4+
Row [1]: [0]:21.00 [1]:22.00
5+
Row [2]: [0]:31.00 [1]:32.00 [2]:33.00
6+
Row [3]: [0]:41.00 [3]:44.00
7+
Row [4]: [0]:51.00 [4]:55.00
8+
Row [5]: [0]:61.00 [5]:66.00 [8]:69.00 [9]:610.00
9+
Row [6]: [0]:71.00 [6]:77.00
10+
Row [7]: [0]:81.00 [5]:86.00 [6]:87.00 [7]:88.00
11+
Row [8]: [0]:91.00 [8]:99.00
12+
Row [9]: [0]:101.00 [9]:1010.00
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
element[0] 150.000000
2+
element[1] 43.000000
3+
element[2] 96.000000
4+
element[3] 85.000000
5+
element[4] 106.000000
6+
element[5] 806.000000
7+
element[6] 148.000000
8+
element[7] 342.000000
9+
element[8] 190.000000
10+
element[9] 1111.000000

tests/matrix/convertCRS.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// DL 2025.06.25
2+
// Unit test: Converts a Matrix Market (MM) matrix to internal CRS format
3+
// and compares against expected output from disk.
4+
// Assumes a single MPI rank (no parallel communication).
5+
6+
#include "../../src/comm.h"
7+
#include "../../src/matrix.h"
8+
#include "../common.h"
9+
#include <dirent.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <string.h>
13+
14+
/**
15+
* Runs conversion tests for all `.mtx` files in `dataDir/testMatrices/`.
16+
*
17+
* For each matrix:
18+
* 1. Builds full path to the file
19+
* 2. Loads MM matrix and converts it to GMatrix, and then CRS
20+
* 3. Dumps the converted result to a file
21+
* 4. Compares the dump against expected result (if present)
22+
*
23+
* Returns 0 on success, 1 if any test fails.
24+
*/
25+
int test_convertCRS(void* args, const char* dataDir)
26+
{
27+
// Compose path to directory containing test matrices
28+
char matricesPath[STR_LEN];
29+
snprintf(matricesPath, STR_LEN, "%s%s", dataDir, "testMatrices/");
30+
31+
// Open the directory and check for errors
32+
DIR* dir = opendir(matricesPath);
33+
if (dir == NULL) {
34+
perror("Error opening directory");
35+
return 1;
36+
}
37+
38+
// Read the directory entries
39+
struct dirent* entry;
40+
41+
// Iterate through files in the directory
42+
while ((entry = readdir(dir)) != NULL) {
43+
// Only process files with ".mtx" extension
44+
if (strstr(entry->d_name, ".mtx") != NULL) {
45+
46+
// Build full path to matrix file
47+
char matrixPath[STR_LEN];
48+
snprintf(matrixPath, STR_LEN, "%s%s", matricesPath, entry->d_name);
49+
50+
MMMatrix M;
51+
Args* arguments = (Args*)args;
52+
53+
STRIP_MATRIX_FILE(entry) // Removes .mtx from file name
54+
55+
// Path to expected output (".in" file) for this matrix
56+
char pathToExpectedData[STR_LEN];
57+
snprintf(pathToExpectedData,
58+
STR_LEN,
59+
"data/expected/%s_CRS.in",
60+
entry->d_name);
61+
62+
// Only test if expected file exists
63+
if (fopen(pathToExpectedData, "r")) {
64+
65+
// Path to write reported output (".out" file)
66+
char pathToReportedData[STR_LEN];
67+
snprintf(pathToReportedData,
68+
STR_LEN,
69+
"data/reported/%s_CRS.out",
70+
entry->d_name);
71+
72+
// Open output file for writing results
73+
FILE* reportedData = fopen(pathToReportedData, "w");
74+
if (reportedData == NULL) {
75+
perror("fopen failed for reportedData");
76+
exit(EXIT_FAILURE); // Crash fast on I/O error
77+
}
78+
79+
// Load matrix from Matrix Market file
80+
MMMatrixRead(&M, matrixPath);
81+
82+
// Declare graph and algebraic matrices
83+
GMatrix m;
84+
Matrix A;
85+
Comm c;
86+
87+
// Set single-rank defaults (no parallel distribution)
88+
M.startRow = 0;
89+
M.stopRow = M.nr;
90+
M.totalNr = M.nr;
91+
M.totalNnz = M.nnz;
92+
c.rank = 0;
93+
c.size = 1;
94+
c.logFile = reportedData;
95+
96+
// Convert to internal formats
97+
matrixConvertfromMM(&M, &m); // MM → GMatrix
98+
convertMatrix(&A, &m); // GMatrix → Matrix
99+
commMatrixDump(&c, &A); // Output formatted result
100+
fclose(reportedData);
101+
102+
// Diff against expected file — if mismatch, fail the test
103+
if (diff_files(pathToExpectedData, pathToReportedData, 0)) {
104+
closedir(dir);
105+
return 1;
106+
}
107+
}
108+
}
109+
}
110+
111+
// Clean up and return success
112+
closedir(dir);
113+
return 0;
114+
}

0 commit comments

Comments
 (0)