I am experimenting the row- vs column-major traversal. The general idea is that row-major traversal should be faster due to caching/vectorization/etc. Here is my test code:
// gcc -o main.out main.c -O3
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
  size_t dim[] = {10, 50, 100, 200, 500, 1000, 5000, 10000, 20000};
  struct timespec ts;
  uint32_t* arr_ptr;
  double delta, t0;
  printf(
    "Dim\tArraySize(KB)\tRow-Major Time\tRM Sample\tCol-Major Time\tCM Sample\n"
  );
  for (int i = 0; i < sizeof(dim) / sizeof(dim[0]); ++i) {
    size_t d = dim[i];
    printf("%5lu,\t%11lu,\t", d, d * d * sizeof(uint32_t) / 1024);
    arr_ptr = (uint32_t*)malloc(d * d * sizeof(uint32_t));
    memset(arr_ptr, 0, d * d * sizeof(uint32_t));
    timespec_get(&ts, TIME_UTC);
    t0 = ts.tv_sec + ts.tv_nsec / 1000.0 / 1000.0 / 1000.0;
    for (int j = 0; j < d; ++j) {
      for (int k = 0; k < d; ++k) {
        *(arr_ptr + j * d + k) += (j + k);
      }
    }
    timespec_get(&ts, TIME_UTC);
    delta = ts.tv_sec + ts.tv_nsec / 1000.0 / 1000.0 / 1000.0 - t0;
    printf("%0.9lf,\t%8u,\t", delta, *(arr_ptr + ts.tv_sec % d * d + ts.tv_nsec % d));
    free(arr_ptr);
    arr_ptr = (uint32_t*)malloc(d * d * sizeof(uint32_t));
    memset(arr_ptr, 0, d * d * sizeof(uint32_t));
    timespec_get(&ts, TIME_UTC);
    t0 = ts.tv_sec + ts.tv_nsec / 1000.0 / 1000.0 / 1000.0;
    for (int j = 0; j < d; ++j) {
      for (int k = 0; k < d; ++k) {
        *(arr_ptr + k * d + j) += (j + k);
      }
    }
    timespec_get(&ts, TIME_UTC);
    delta = ts.tv_sec + ts.tv_nsec / 1000.0 / 1000.0 / 1000.0 - t0;
    printf("%0.9lf,\t%8u\n", delta, *(arr_ptr + ts.tv_sec % d * d + ts.tv_nsec % d));
    free(arr_ptr);
  }
  return 0;
}
The result is as follows:
Dim ArraySize(KB)   Row-Major Time  RM Sample   Col-Major Time  CM Sample
   10,            0,    0.000000238,          10,   0.000000238,          18
   20,            1,    0.000000238,          19,   0.000000477,          40
   50,            9,    0.000002384,          31,   0.000001431,         122
  100,           39,    0.000013113,          96,   0.000005245,         272
  200,          156,    0.000077486,         263,   0.000042200,         240
  500,          976,    0.000452757,         558,   0.000420809,         362
 1000,         3906,    0.001549959,        1095,   0.001713991,        1030
 2000,        15625,    0.005422354,        3281,   0.006698370,        3571
 5000,        97656,    0.036512375,        5439,   0.053869963,        4949
10000,       390625,    0.148355007,        7462,   1.049520969,        6046
20000,      1562500,    0.768568516,       22097,   7.388022661,       32356
The general theory holds only after the dimension reaches 500--before that, column-major traversal keeps outperforming row-major traversal. This seems not random--I ran the test multiple times with different gcc parameters, such as -O3 -ffast-math and -O3 -fno-tree-vectorize, the performance gap appears to be stable. But why?
