#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <algorithm>
#include "cpucycles.h"
@
@aspas: #include "aspas.h"
@
@djbsort: #include "djbsort.h"
@
@far: #include "avx2sort.h"
@
@herf: #include "herf.h"
@
@radixwrapper: #include "radixwrapper.h"
@
@sid1607: #include "merge_sort.h"
@
@vqsort: #include "hwy/contrib/sort/algo-inl.h"
@vqsort: #include "hwy/contrib/sort/vqsort.h"
@
@vxsort: #include "vxsort_targets_enable_avx2.h"
@vxsort: #include "vxsort.h"
@vxsort: #include "vxsort.avx2.h"
@vxsort: #include "machine_traits.avx2.h"
@vxsort: #include "smallsort/bitonic_sort.avx2.h"
@
@x86simdsort: #include "x86simdsort.h"
@
@32: typedef int32_t sorttype;
@64: typedef int64_t sorttype;
@

#define N 131072
#define TIMINGS 64
typedef long long num;

sorttype r[N] __attribute__((aligned(4096)));
sorttype perm[TIMINGS+1][N] __attribute__((aligned(4096)));
sorttype x[(TIMINGS+1)*(N+1)] __attribute__((aligned(4096)));
sorttype y[N] __attribute__((aligned(4096)));
@radixwrapper: sorttype z[N] __attribute__((aligned(4096)));
@sid1607: sorttype z[N] __attribute__((aligned(4096)));

num t[TIMINGS+1] __attribute__((aligned(4096)));

int main()
{
@
@sid1607:   initialize();
@vqsort:   auto s = hwy::Sorter();
@vqsort:   hwy::SortAscending order;
@vxsort:   auto sorter = vxsort::vxsort<sorttype, vxsort::vector_machine::AVX2, 8>();
@
  printf("cpucycles_version %s\n",cpucycles_version());
  printf("cpucycles_implementation %s\n",cpucycles_implementation());
  srandom(getpid());

  for (num loop = 0;loop < 2;++loop)
    for (num j = 0;j <= TIMINGS;++j)
      t[j] = cpucycles();
  printf("overhead");
  for (num i = 0;i < TIMINGS;++i)
    printf(" %lld",t[i+1]-t[i]);
  printf("\n");

  for (num j = 0;j <= TIMINGS;++j)
    for (num i = 0;i < N;++i)
      perm[j][i] = i;

  num randomized = 0;
  for (num npos = 0;;++npos) {
    num nposlow = npos%24;
    num nposhigh = npos/24;
    num n = round(exp2(nposhigh+round(27.75001*nposlow)/665));
    if (n > N) break;
    num npad = n+!(n&1);
@
@aspas:     if (n < 16) continue;
@herf:     if (n < 64) continue;
@radixwrapper:     if (n <= 8192) continue; // radixwrapper simply calls djbsort in that case
@sid1607:     if (n % SORT_SIZE) continue; // merge_sort crashes without multiple of 64
@sid1607:     npad = n; // merge_sort crashes without alignment
@

    for (;randomized < n;++randomized)
      for (num j = 0;j <= TIMINGS;++j) {
        num pos = random()%(randomized+1);
        sorttype tmp = perm[j][pos];
        perm[j][pos] = perm[j][randomized];
        perm[j][randomized] = tmp;
      }

    for (num i = 0;i < n;++i) {
      r[i] = 0;
      for (num loop = 0;loop < 8;++loop)
        r[i] = (r[i]^(r[i]<<15))+random();
    }
    for (num j = 0;j <= TIMINGS;++j)
      for (num i = 0;i < n;++i)
        x[j*npad+i] = r[perm[j][i]];

    num sum = 0;
    for (num j = 0;j <= TIMINGS;++j)
      for (num i = 0;i < n;++i)
        sum += x[j*npad+i];

    for (num j = 0;j <= TIMINGS;++j)
      t[j] = cpucycles();

    for (num j = 0;j <= TIMINGS;++j) {
      sorttype *y;
      t[j] = cpucycles();
      y = x+j*npad;
@
@aspas:       aspas::sort(y,n);
@32: @djbsort:       djbsort_int32(y,n);
@64: @djbsort:       djbsort_int64(y,n);
@far:       avx2::quicksort(y,n);
@herf:       herf_sort(y,n);
@radixwrapper:       radixwrapper_int32(y,z,n);
@sid1607:       if (merge_sort(y,z,n).first == z) for (long long i = 0;i < n;++i) y[i] = z[i];
@stdsort:       std::sort(y,y+n);
@vqsort:       s(y,n,order);
@vxsort:       sorter.sort(y,y+n-1);
@x86simdsort:       x86simdsort::qsort(y,n,0);
@
    }

    for (num i = 0;i < n;++i)
      y[i] = r[i];
    std::sort(y,y+n);
    for (num j = 0;j <= TIMINGS;++j)
      for (num i = 0;i < n;++i)
        assert(y[i] == x[j*npad+i]);

    for (num j = 0;j <= TIMINGS;++j)
      for (num i = 0;i < n;++i)
        sum -= x[j*npad+i];
    assert(sum == 0);

    printf("%lld",n);
    for (num i = 0;i < TIMINGS;++i)
      printf(" %lld",t[i+1]-t[i]);
    printf("\n");
    fflush(stdout);
  }
  return 0;
}
@
@vxsort: #include "vxsort_targets_disable.h"
@
