Beispiel #1
0
// Notes:
// -    Each task receives distinct copy of parent
// -    Copy of child is shallow, be careful with `state` member
static long visit(node_t parent)
{
    node_t    child;
    uint64_t *child_descendants = calloc(sizeof(long), parent.num_children);

    CILK_C_REDUCER_OPADD(num_descendants, ulong, 0);
    uint64_t tmp;

    // Spawn children, if any
    for (int i = 0; i < parent.num_children; i++) {
        child.height = parent.height + 1;

        for (int j = 0; j < num_samples; j++) {
            rng_spawn(parent.state.state, child.state.state, i);
        }

        child.num_children = calc_num_children(&child);

        child_descendants[i] = _Cilk_spawn visit(child);
    }

    _Cilk_sync;

    CILK_C_REGISTER_REDUCER(num_descendants);

    _Cilk_for(int i = 0; i < parent.num_children; i++) {
        REDUCER_VIEW(num_descendants) += child_descendants[i];
    }

    tmp = 1 + REDUCER_VIEW(num_descendants);

    CILK_C_UNREGISTER_REDUCER(num_descendants);

    return tmp;
}
Beispiel #2
0
// Gets the local instance of a trace local variable
void* get_trace_local(tlv_id id) {
  int worker_id = 0;
  int steal_count = __cilkrts_get_steal_count(&worker_id);
  if (worker_id == 0) {
    printf("User thread???\n");
    exit(1);
  } else {
    // Shift back from [1, P] to [0, P-1]
    worker_id -= 1;
  }
  worker_table_t* our_table = &worker_tables[worker_id];
  if (our_table->wtrace_info[id].steal_count == steal_count &&
      our_table->wtrace_info[id].view != NULL) {
    return our_table->wtrace_info[id].view;
  }
  trace_initializer initializer = global_table.gtrace_info[id].initializer;
  void* new_view = (*initializer)();
  our_table->wtrace_info[id].view = new_view;
  tc_add(&REDUCER_VIEW(global_table.gtrace_info[id].reducer), new_view);
  our_table->wtrace_info[id].steal_count = steal_count;
  return new_view;
}
Beispiel #3
0
// Collects all the instances of the variable in the execution strand
trace_collection collect_trace_local(tlv_id id) {
  return REDUCER_VIEW(global_table.gtrace_info[id].reducer);
}
Beispiel #4
0
  return;
}

void board_reducer_identity(void *key, void* value) {
  full_board_t* board = (full_board_t*) value;
  memcpy(board, &base_board, sizeof(full_board_t));
  board->is_identity = true;
}

void board_reducer_destroy(void *key, void *value) {
  return;
}

void initialize_reducer() {
  full_board_reducer_t reducer = CILK_C_INIT_REDUCER(full_board_t, board_reducer_reduce, board_reducer_identity,
                                      board_reducer_destroy, (full_board_t) { .board = {0}, .pieces = {{0}, {0}}, .pawn_count = {0, 0}, .rank_major = {0}, .file_major = {0}, .ply = 0, .is_identity = 0});
  CILK_C_REDUCER_OPADD(ncr, ulong, 0);
  node_count_reducer = ncr;
  board_reducer = reducer;
  CILK_C_REGISTER_REDUCER(board_reducer);
  board_reducer_identity(NULL, &REDUCER_VIEW(board_reducer));
  REDUCER_VIEW(board_reducer).is_identity = false;
}

void destroy_reducer() {
  CILK_C_UNREGISTER_REDUCER(board_reducer);
  CILK_C_UNREGISTER_REDUCER(node_count_reducer);
}

#include "./end_game.c"
Beispiel #5
0
static score_t scout_search(searchNode *node, int depth,
                            uint64_t *node_count_serial, full_board_t* board) {


  // Initialize the search node.
  initialize_scout_node(node, depth);

  // check whether we should abort
  if (should_abort_check() || parallel_parent_aborted(node)) {
    return 0;
  }

  // Pre-evaluate this position.
  leafEvalResult pre_evaluation_result = evaluate_as_leaf(node, SEARCH_SCOUT, board);

  // If we decide to stop searching, return the pre-evaluation score.
  if (pre_evaluation_result.type == MOVE_EVALUATED) {
    return pre_evaluation_result.score;
  }

  // Populate some of the fields of this search node, using some
  //  of the information provided by the pre-evaluation.
  int hash_table_move = pre_evaluation_result.hash_table_move;
  node->best_score = pre_evaluation_result.score;
  node->quiescence = pre_evaluation_result.should_enter_quiescence;

  // Grab the killer-moves for later use.
  move_t killer_a = killer[KMT(node->ply, 0)];
  move_t killer_b = killer[KMT(node->ply, 1)];

  // Store the sorted move list on the stack.
  //   MAX_NUM_MOVES is all that we need.
  sortable_move_t move_list[MAX_NUM_MOVES];

  // Obtain the sorted move list.
  int num_of_moves = get_sortable_move_list(node, move_list, hash_table_move, board);
  int num_of_special_moves = move_list[num_of_moves];
  int num_of_nonzero_moves = move_list[num_of_moves + 1];
  if (num_of_special_moves == 0) {
    selectionSort(move_list, num_of_moves, 1);
    num_of_special_moves = 1;
  }
  int number_of_moves_evaluated = 0;

  bool generated_early_cutoff = false;

  for (int mv_index = 0; mv_index < num_of_special_moves; mv_index++) {
    int local_index = number_of_moves_evaluated++;
    move_t mv = get_move(move_list[local_index]);

    // increase node count
    REDUCER_VIEW(node_count_reducer)++;

    smallMoveEvaluationResult result = evaluateMove(node, mv, killer_a, killer_b,
                                               SEARCH_SCOUT,
                                               node_count_serial);

    if (result.type == MOVE_ILLEGAL || result.type == MOVE_IGNORE) {
      continue;
    }

    if (abortf || parallel_parent_aborted(node)) {
      return 0;
    }

    // A legal move is a move that's not KO, but when we are in quiescence
    // we only want to count moves that has a capture.
    if (result.type == MOVE_EVALUATED) {
      node->legal_move_count++;
    }

    // process the score. Note that this mutates fields in node.
    bool cutoff = search_process_score(node, mv, local_index, &result, SEARCH_SCOUT);

    if (cutoff) {
      generated_early_cutoff = true;
      break;
    }
  }

//  ABOVE IS YOUNG BROTHER'S WAIT CODE. IT SHOULD RUN IN SERIAL
//
//  BELOW IS PARALLELIZED SCOUT SEARCH. IT SHOULD RUN IN PARALLEL


  // if this happens, we generated an early cutoff in young brother's wait and can just skip to the end
  if (generated_early_cutoff)
    goto finish_scout_search;

  sort_incremental(move_list + num_of_special_moves, num_of_nonzero_moves - num_of_special_moves);

  // A simple mutex. See simple_mutex.h for implementation details.
  simple_mutex_t node_mutex;
  init_simple_mutex(&node_mutex);
  // TODO: see if changing this depth is better
  if (depth >= 2) {
    cilk_for (int mv_index = num_of_special_moves; mv_index < num_of_moves; mv_index++) {
      do {
        if (node->abort) continue;

        int local_index = __sync_fetch_and_add(&number_of_moves_evaluated, 1);

        move_t mv = get_move(move_list[local_index]);

        // increase node count
        REDUCER_VIEW(node_count_reducer)++;

        smallMoveEvaluationResult result = evaluateMove(node, mv, killer_a, killer_b,
                                                   SEARCH_SCOUT,
                                                   node_count_serial);

        // TODO: change this to break if we want to abort
        if (result.type == MOVE_ILLEGAL || result.type == MOVE_IGNORE) {
          continue;
        }

        if (abortf || parallel_parent_aborted(node)) {
          node->abort = true;
          continue;
        }

        // A legal move is a move that's not KO, but when we are in quiescence
        // we only want to count moves that has a capture.
        if (result.type == MOVE_EVALUATED) {
          __sync_fetch_and_add(&node->legal_move_count, 1);
        }

        bool cutoff = false;
        if (result.score > node->best_score) {
          simple_acquire(&node_mutex);
          // process the score. Note that this mutates fields in node.
          cutoff = search_process_score(node, mv, local_index, &result, SEARCH_SCOUT);
          simple_release(&node_mutex);
        }

        if (cutoff) {
          node->abort = true;
          continue;
        }
      } while (false);
    }
  } else {