|  | 
|  | 1 | +/** | 
|  | 2 | +* @license Apache-2.0 | 
|  | 3 | +* | 
|  | 4 | +* Copyright (c) 2025 The Stdlib Authors. | 
|  | 5 | +* | 
|  | 6 | +* Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 7 | +* you may not use this file except in compliance with the License. | 
|  | 8 | +* You may obtain a copy of the License at | 
|  | 9 | +* | 
|  | 10 | +*    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 11 | +* | 
|  | 12 | +* Unless required by applicable law or agreed to in writing, software | 
|  | 13 | +* distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 14 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 15 | +* See the License for the specific language governing permissions and | 
|  | 16 | +* limitations under the License. | 
|  | 17 | +*/ | 
|  | 18 | + | 
|  | 19 | +#include "stdlib/blas/base/dger.h" | 
|  | 20 | +#include "stdlib/blas/base/shared.h" | 
|  | 21 | +#include <stdlib.h> | 
|  | 22 | +#include <stdio.h> | 
|  | 23 | +#include <math.h> | 
|  | 24 | +#include <time.h> | 
|  | 25 | +#include <sys/time.h> | 
|  | 26 | + | 
|  | 27 | +#define NAME "dger" | 
|  | 28 | +#define ITERATIONS 10000000 | 
|  | 29 | +#define REPEATS 3 | 
|  | 30 | +#define MIN 1 | 
|  | 31 | +#define MAX 6 | 
|  | 32 | + | 
|  | 33 | +/** | 
|  | 34 | +* Prints the TAP version. | 
|  | 35 | +*/ | 
|  | 36 | +static void print_version( void ) { | 
|  | 37 | +	printf( "TAP version 13\n" ); | 
|  | 38 | +} | 
|  | 39 | + | 
|  | 40 | +/** | 
|  | 41 | +* Prints the TAP summary. | 
|  | 42 | +* | 
|  | 43 | +* @param total     total number of tests | 
|  | 44 | +* @param passing   total number of passing tests | 
|  | 45 | +*/ | 
|  | 46 | +static void print_summary( int total, int passing ) { | 
|  | 47 | +	printf( "#\n" ); | 
|  | 48 | +	printf( "1..%d\n", total ); // TAP plan | 
|  | 49 | +	printf( "# total %d\n", total ); | 
|  | 50 | +	printf( "# pass  %d\n", passing ); | 
|  | 51 | +	printf( "#\n" ); | 
|  | 52 | +	printf( "# ok\n" ); | 
|  | 53 | +} | 
|  | 54 | + | 
|  | 55 | +/** | 
|  | 56 | +* Prints benchmarks results. | 
|  | 57 | +* | 
|  | 58 | +* @param iterations   number of iterations | 
|  | 59 | +* @param elapsed      elapsed time in seconds | 
|  | 60 | +*/ | 
|  | 61 | +static void print_results( int iterations, double elapsed ) { | 
|  | 62 | +	double rate = (double)iterations / elapsed; | 
|  | 63 | +	printf( "  ---\n" ); | 
|  | 64 | +	printf( "  iterations: %d\n", iterations ); | 
|  | 65 | +	printf( "  elapsed: %0.9f\n", elapsed ); | 
|  | 66 | +	printf( "  rate: %0.9f\n", rate ); | 
|  | 67 | +	printf( "  ...\n" ); | 
|  | 68 | +} | 
|  | 69 | + | 
|  | 70 | +/** | 
|  | 71 | +* Returns a clock time. | 
|  | 72 | +* | 
|  | 73 | +* @return clock time | 
|  | 74 | +*/ | 
|  | 75 | +static double tic( void ) { | 
|  | 76 | +	struct timeval now; | 
|  | 77 | +	gettimeofday( &now, NULL ); | 
|  | 78 | +	return (double)now.tv_sec + (double)now.tv_usec/1.0e6; | 
|  | 79 | +} | 
|  | 80 | + | 
|  | 81 | +/** | 
|  | 82 | +* Generates a random number on the interval [0,1). | 
|  | 83 | +* | 
|  | 84 | +* @return random number | 
|  | 85 | +*/ | 
|  | 86 | +static double rand_double( void ) { | 
|  | 87 | +	int r = rand(); | 
|  | 88 | +	return (double)r / ( (double)RAND_MAX + 1.0 ); | 
|  | 89 | +} | 
|  | 90 | + | 
|  | 91 | +/** | 
|  | 92 | +* Runs a benchmark. | 
|  | 93 | +* | 
|  | 94 | +* @param iterations   number of iterations | 
|  | 95 | +* @param N            array dimension size | 
|  | 96 | +* @return             elapsed time in seconds | 
|  | 97 | +*/ | 
|  | 98 | +static double benchmark1( int iterations, int N ) { | 
|  | 99 | +	double elapsed; | 
|  | 100 | +	double A[ N*N ]; | 
|  | 101 | +	double x[ N ]; | 
|  | 102 | +	double y[ N ]; | 
|  | 103 | +	double t; | 
|  | 104 | +	int i; | 
|  | 105 | +	int j; | 
|  | 106 | + | 
|  | 107 | +	for ( i = 0, j = 0; i < N; i++, j += 2 ) { | 
|  | 108 | +		x[ i ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 109 | +		y[ i ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 110 | +		A[ j ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 111 | +		A[ j+1 ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 112 | +	} | 
|  | 113 | +	t = tic(); | 
|  | 114 | +	for ( i = 0; i < iterations; i++ ) { | 
|  | 115 | +		// cppcheck-suppress uninitvar | 
|  | 116 | +		c_dger( CblasRowMajor, N, N, 1.0, x, 1, y, 1, A, N ); | 
|  | 117 | +		if ( A[ i%(N*2) ] != A[ i%(N*2) ] ) { | 
|  | 118 | +			printf( "should not return NaN\n" ); | 
|  | 119 | +			break; | 
|  | 120 | +		} | 
|  | 121 | +	} | 
|  | 122 | +	elapsed = tic() - t; | 
|  | 123 | +	if ( A[ i%(N*2) ] != A[ i%(N*2) ] ) { | 
|  | 124 | +		printf( "should not return NaN\n" ); | 
|  | 125 | +	} | 
|  | 126 | +	return elapsed; | 
|  | 127 | +} | 
|  | 128 | + | 
|  | 129 | +/** | 
|  | 130 | +* Runs a benchmark. | 
|  | 131 | +* | 
|  | 132 | +* @param iterations   number of iterations | 
|  | 133 | +* @param N            array dimension size | 
|  | 134 | +* @return             elapsed time in seconds | 
|  | 135 | +*/ | 
|  | 136 | +static double benchmark2( int iterations, int N ) { | 
|  | 137 | +	double elapsed; | 
|  | 138 | +	double A[ N*N ]; | 
|  | 139 | +	double x[ N ]; | 
|  | 140 | +	double y[ N ]; | 
|  | 141 | +	double t; | 
|  | 142 | +	int i; | 
|  | 143 | +	int j; | 
|  | 144 | + | 
|  | 145 | +	for ( i = 0, j = 0; i < N; i++, j += 2 ) { | 
|  | 146 | +		x[ i ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 147 | +		y[ i ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 148 | +		A[ j ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 149 | +		A[ j+1 ] = ( rand_double()*20.0 ) - 10.0; | 
|  | 150 | +	} | 
|  | 151 | +	t = tic(); | 
|  | 152 | +	for ( i = 0; i < iterations; i++ ) { | 
|  | 153 | +		// cppcheck-suppress uninitvar | 
|  | 154 | +		c_dger_ndarray( N, N, 1.0, x, 1, 0, y, 1, 0, A, N, 1, 0 ); | 
|  | 155 | +		if ( A[ i%(N*2) ] != A[ i%(N*2) ] ) { | 
|  | 156 | +			printf( "should not return NaN\n" ); | 
|  | 157 | +			break; | 
|  | 158 | +		} | 
|  | 159 | +	} | 
|  | 160 | +	elapsed = tic() - t; | 
|  | 161 | +	if ( A[ i%(N*2) ] != A[ i%(N*2) ] ) { | 
|  | 162 | +		printf( "should not return NaN\n" ); | 
|  | 163 | +	} | 
|  | 164 | +	return elapsed; | 
|  | 165 | +} | 
|  | 166 | + | 
|  | 167 | +/** | 
|  | 168 | +* Main execution sequence. | 
|  | 169 | +*/ | 
|  | 170 | +int main( void ) { | 
|  | 171 | +	double elapsed; | 
|  | 172 | +	int count; | 
|  | 173 | +	int iter; | 
|  | 174 | +	int N; | 
|  | 175 | +	int i; | 
|  | 176 | +	int j; | 
|  | 177 | + | 
|  | 178 | +	// Use the current time to seed the random number generator: | 
|  | 179 | +	srand( time( NULL ) ); | 
|  | 180 | + | 
|  | 181 | +	print_version(); | 
|  | 182 | +	count = 0; | 
|  | 183 | +	for ( i = MIN; i <= MAX; i++ ) { | 
|  | 184 | +		N = floor( pow( pow( 10, i ), 1.0/2.0 ) ); | 
|  | 185 | +		iter = ITERATIONS / pow( 10, i-1 ); | 
|  | 186 | +		for ( j = 0; j < REPEATS; j++ ) { | 
|  | 187 | +			count += 1; | 
|  | 188 | +			printf( "# c::%s:size=%d\n", NAME, N*N ); | 
|  | 189 | +			elapsed = benchmark1( iter, N ); | 
|  | 190 | +			print_results( iter, elapsed ); | 
|  | 191 | +			printf( "ok %d benchmark finished\n", count ); | 
|  | 192 | +		} | 
|  | 193 | +	} | 
|  | 194 | +	for ( i = MIN; i <= MAX; i++ ) { | 
|  | 195 | +		N = floor( pow( pow( 10, i ), 1.0/2.0 ) ); | 
|  | 196 | +		iter = ITERATIONS / pow( 10, i-1 ); | 
|  | 197 | +		for ( j = 0; j < REPEATS; j++ ) { | 
|  | 198 | +			count += 1; | 
|  | 199 | +			printf( "# c::%s:ndarray:size=%d\n", NAME, N*N ); | 
|  | 200 | +			elapsed = benchmark2( iter, N ); | 
|  | 201 | +			print_results( iter, elapsed ); | 
|  | 202 | +			printf( "ok %d benchmark finished\n", count ); | 
|  | 203 | +		} | 
|  | 204 | +	} | 
|  | 205 | +	print_summary( count, count ); | 
|  | 206 | +} | 
0 commit comments