/* * This program is meant to benchmark two ways of operating * on a two-dimensional array, once by rows and once per * columns, to find out whether order of access makes a * difference and how much difference. * * Users specify via the command line whether to try access * rows or access by columns, array dimensions, and how many * time to repeat the calculation (which for small arrays may * be the only way to get a nontrivial runtime). Run without * arguments it prints a usage message about what arguments it * wants. * * See the write-up for more comments. */ #include #include #include #include #include #include "timer.h" void error_exit(const char * msg); void set_values_rows(long ** a, long rows, long columns); void set_values_cols(long ** a, long rows, long columns); long count_evens_rows(long ** a, long rows, long columns); long count_evens_cols(long ** a, long rows, long columns); int main(int argc, char *argv[]) { /* command-line arguments */ if (argc < 5) { fprintf(stderr, "usage: %s [ -r | -c ] rows columns repeats\n", argv[0]); return EXIT_FAILURE; } bool by_rows; if (strcmp(argv[1], "-r") == 0) { by_rows = true; } else if (strcmp(argv[1], "-c") == 0) { by_rows = false; } else { error_exit("first argument not -r or -c"); } char * endptr; long rows = strtol(argv[2], &endptr, 10); if (*endptr != '\0') { error_exit("rows not integer"); } long columns = strtol(argv[3], &endptr, 10); if (*endptr != '\0') { error_exit("columns not integer"); } long repeats = strtol(argv[4], &endptr, 10); if (*endptr != '\0') { error_exit("repeats not integer"); } printf("%ld by %ld, %ld repeats, %s\n", rows, columns, repeats, by_rows ? "by rows" : "by columns"); /* array setup */ long * data = malloc(sizeof(data[0]) * rows * columns); long ** data2D = malloc(sizeof(data2D[0]) * rows); if ((data == NULL) || (data2D == NULL)) { error_exit("could not get space for array\n"); } for (long r = 0; r < rows; ++r) data2D[r] = &data[r*columns]; /* main loop (see writeup for more) */ double start_time = get_time(); long meaningless_min = LONG_MAX; long meaningless_max = LONG_MIN; for (long i = 0; i < repeats; ++i) { if (by_rows) set_values_rows(data2D, rows, columns); else set_values_cols(data2D, rows, columns); long meaningless; if (by_rows) meaningless = count_evens_rows(data2D, rows, columns); else meaningless = count_evens_cols(data2D, rows, columns); if (meaningless < meaningless_min) meaningless_min = meaningless; if (meaningless > meaningless_max) meaningless_max = meaningless; } printf("meaningless results %g, %g\n", ((double)meaningless_min) / (rows*columns), ((double)meaningless_max) / (rows*columns)); double end_time = get_time(); printf("execution time for main loop %g seconds\n", end_time - start_time); printf("(%ld elements, %g seconds per repeat)\n\n", (rows * columns), (end_time - start_time)/repeats); free(data2D); free(data); return EXIT_SUCCESS; } void error_exit(const char * msg) { fprintf(stderr, "%s\n", msg); exit(EXIT_FAILURE); } void set_values_rows(long ** a, long rows, long columns) { for (long r = 0; r < rows; ++r) for (long c = 0; c < columns; ++c) a[r][c] = rand(); } void set_values_cols(long ** a, long rows, long columns) { for (long c = 0; c < columns; ++c) for (long r = 0; r < rows; ++r) a[r][c] = rand(); } long count_evens_rows(long ** a, long rows, long columns) { long n = 0; for (long r = 0; r < rows; ++r) for (long c = 0; c < columns; ++c) if ((a[r][c] % 2) == 0) n += 1; return n; } long count_evens_cols(long ** a, long rows, long columns) { long n = 0; for (long c = 0; c < columns; ++c) for (long r = 0; r < rows; ++r) if ((a[r][c] % 2) == 0) n += 1; return n; }