packages feed

futhark-0.18.1: rts/c/scheduler_tune.h

/* The self-tuning program to estimate $\kappa$ */

struct futhark_mc_segred_stage_1_struct {
  struct futhark_context *ctx;
  int32_t *free_tuning_res;
  int32_t *array;
};

/* Reduction function over an integer array */
int futhark_mc_tuning_segred_stage_1(void *args, int64_t start, int64_t end,
                                     int flat_tid, int tid) {
  (void)flat_tid;
  (void)tid;

  int err = 0;
  struct futhark_mc_segred_stage_1_struct *futhark_mc_segred_stage_1_struct = (struct futhark_mc_segred_stage_1_struct *) args;
  struct futhark_context *ctx = futhark_mc_segred_stage_1_struct->ctx;
  int32_t *array = futhark_mc_segred_stage_1_struct->array;
  int32_t *tuning_res = futhark_mc_segred_stage_1_struct->free_tuning_res;

  int32_t sum = 0;
  for (int i = start; i < end; i++) {
    int32_t y = array[i];
    sum = add32(sum, y);
  }
  *tuning_res = sum;
  return err;
}

/* The main entry point for the tuning process */
/* Sets the global variable ``kappa`` */
int futhark_segred_tuning_program(struct futhark_context *ctx)
{
  int err = 0;

  int64_t iterations = 100000000;
  int64_t tuning_time = 0;
  int64_t tuning_iter = 0;

  int32_t *array = malloc(sizeof(int32_t) * iterations);
  for (int64_t i = 0; i < iterations; i++) {
    array[i] = fast_rand();
  }

  int64_t start_tuning = get_wall_time_ns();
  /* **************************** */
  /* Run sequential reduce first' */
  /* **************************** */
  int64_t tuning_sequentiual_start = get_wall_time_ns();
  struct futhark_mc_segred_stage_1_struct futhark_mc_segred_stage_1_struct;
  int32_t tuning_res;
  futhark_mc_segred_stage_1_struct.ctx = ctx;
  futhark_mc_segred_stage_1_struct.free_tuning_res = &tuning_res;
  futhark_mc_segred_stage_1_struct.array = array;

  err = futhark_mc_tuning_segred_stage_1(&futhark_mc_segred_stage_1_struct, 0, iterations, 0, 0);
  int64_t tuning_sequentiual_end = get_wall_time_ns();
  int64_t sequential_elapsed = tuning_sequentiual_end - tuning_sequentiual_start;

  double C = (double)sequential_elapsed / (double)iterations;
  fprintf(stderr, " Time for sequential run is %lld - Found C %f\n", (long long)sequential_elapsed, C);

  /* ********************** */
  /* Now run tuning process */
  /* ********************** */
  // Setup a scheduler with a single worker
  int num_threads = ctx->scheduler.num_threads;
  ctx->scheduler.num_threads = 1;
  ctx->scheduler.workers = malloc(sizeof(struct worker));
  worker_local = &ctx->scheduler.workers[0];
  worker_local->tid = 0;
  CHECK_ERR(subtask_queue_init(&ctx->scheduler.workers[0].q, 1024), "failed to init queue for worker %d\n", 0);

  // Start tuning for kappa
  double kappa_tune = 1000; // Initial kappa is 1 us
  double ratio;
  int64_t time_elapsed;
  while(1) {
    int64_t min_iter_pr_subtask = (int64_t) (kappa_tune / C) == 0 ? 1 : (kappa_tune / C);
    int nsubtasks = iterations / min_iter_pr_subtask;
    struct scheduler_info info;
    info.iter_pr_subtask = min_iter_pr_subtask;

    info.nsubtasks = iterations / min_iter_pr_subtask;
    info.remainder = iterations % min_iter_pr_subtask;
    info.task_time = &tuning_time;
    info.task_iter = &tuning_iter;
    info.sched = STATIC;

    struct scheduler_parloop futhark_segred_tuning_scheduler_parloop;
    futhark_segred_tuning_scheduler_parloop.name = "futhark_mc_tuning_segred_stage_1";
    futhark_segred_tuning_scheduler_parloop.fn = futhark_mc_tuning_segred_stage_1;
    futhark_segred_tuning_scheduler_parloop.args = &futhark_mc_segred_stage_1_struct;
    futhark_segred_tuning_scheduler_parloop.iterations = iterations;
    futhark_segred_tuning_scheduler_parloop.info = info;

    int64_t tuning_chunked_start = get_wall_time_ns();
    int futhark_segred_tuning_program_err =
      scheduler_execute_task(&ctx->scheduler,
                             &futhark_segred_tuning_scheduler_parloop);
    assert(futhark_segred_tuning_program_err == 0);
    int64_t tuning_chunked_end = get_wall_time_ns();
    time_elapsed =  tuning_chunked_end - tuning_chunked_start;

    ratio = (double)time_elapsed / (double)sequential_elapsed;
    if (ratio < 1.055) {
      break;
    }
    kappa_tune += 100; // Increase by 100 ns at the time
    fprintf(stderr, "nsubtask %d - kappa %f - ratio %f\n", nsubtasks, kappa_tune, ratio);
  }

  int64_t end_tuning = get_wall_time_ns();
  fprintf(stderr, "tuning took %lld ns and found kappa %f - time %lld - ratio %f\n",
          (long long)end_tuning - start_tuning,
          kappa_tune,
          (long long)time_elapsed,
          ratio);
  kappa = kappa_tune;

  // Clean-up
  CHECK_ERR(subtask_queue_destroy(&ctx->scheduler.workers[0].q), "failed to destroy queue");
  free(array);
  free(ctx->scheduler.workers);
  ctx->scheduler.num_threads = num_threads;
  return err;
}