Functions | Variables
ybwc.c File Reference

Parallel search. More...

#include "ybwc.h"
#include "move.h"
#include "options.h"
#include "util.h"
#include "search.h"
#include "stats.h"
#include "settings.h"
#include <assert.h>
#include <stdlib.h>

Functions

void node_init (Node *node, Search *search, const int alpha, const int beta, const int depth, const int n_moves, Node *parent)
 Initialize a node. More...
 
void node_free (Node *node)
 Free Resources allocated by a node. More...
 
static bool get_helper (Node *master, Node *node, Move *move)
 Seek for & use an helper node. More...
 
bool node_split (Node *node, Move *move)
 Node split. More...
 
void node_wait_slaves (Node *node)
 Wait for slaves termination. More...
 
void node_update (Node *node, Move *move)
 Update a node. More...
 
Movenode_first_move (Node *node, MoveList *movelist)
 Get the first move of the move list. More...
 
static Movenode_next_move_lockless (Node *node)
 Get the next move of the move list. More...
 
Movenode_next_move (Node *node)
 Get the next move of the move list. More...
 
void task_search (Task *task)
 A parallel search within a Task structure. More...
 
void * task_loop (void *param)
 The main loop runned by a task. More...
 
static Searchtask_search_create (Task *task)
 Create a search structure for a task. More...
 
static void task_search_destroy (Search *search)
 Free a search structure of a task. More...
 
void task_init (Task *task)
 Initialize a task. More...
 
void task_free (Task *task)
 Free resources used by a task. More...
 
void task_stack_init (TaskStack *stack, const int n)
 Initialize the stack of tasks. More...
 
void task_stack_free (TaskStack *stack)
 Free resources used by the stack of tasks. More...
 
void task_stack_resize (TaskStack *stack, const int n)
 Resize the stack of tasks. More...
 
Tasktask_stack_get_idle_task (TaskStack *stack)
 Return, if available, an idle task. More...
 
void task_stack_put_idle_task (TaskStack *stack, Task *task)
 Put back an idle task after using it. More...
 

Variables

Log search_log [1]
 

Detailed Description

Parallel search.

The Young Brother Wait Concept [1, 2] is an efficient technique to search a position with several cpu/core working in parallel. At an inner nodes, this technique always evaluates the first move using a sequential approach, but try to evaluate the siblings in parallel, once the first move has been computed. The YBWC has some nice properties: low search overhead, good scalability, easy implementation, etc.

This file holds the function definition to manipulate structures used in our implementation of parallelism:

References:

  1. Feldmann R., Monien B., Mysliwietz P. Vornberger O. (1989) Distributed Game-Tree Search. ICCA Journal, Vol. 12, No. 2, pp. 65-73.
  2. Feldmann R. (1993) Game-Tree Search on Massively Parallel System - PhD Thesis, Paderborn (English version).
Date
1998 - 2017
Author
Richard Delorme
Version
4.4

Function Documentation

◆ get_helper()

static bool get_helper ( Node master,
Node node,
Move move 
)
static

Seek for & use an helper node.

When asking for an idle task, this function look if a parent node is waiting and has a task available to help the current search.

Parameters
masterA parent node with an idle task.
nodeSearched node.
moveSearched move.
Returns
true if an helper task has been launch, false otherwise.

◆ node_first_move()

Move* node_first_move ( Node node,
MoveList movelist 
)

Get the first move of the move list.

This is thread/safe getter of the first move. If the search is stopped, or an alphabeta cut has been found or no move is available the function returns NULL.

Parameters
nodeNode data.
movelistList of moves.
Returns
the first move of the list or NULL if none is available.

◆ node_free()

void node_free ( Node node)

Free Resources allocated by a node.

Parameters
nodeNode.

◆ node_init()

void node_init ( Node node,
Search search,
const int  alpha,
const int  beta,
const int  depth,
const int  n_moves,
Node parent 
)

Initialize a node.

Initialize the various members of the node structure. The important part of the initialization establishes a master-slave relashionship between this node (the slave) and its parent (the master).

Parameters
nodeA potentially shared position.
searchThe position searched
alphalower score bound.
betaupper score bound.
depthdepth.
n_movesMove count.
parentThe parent node.

◆ node_next_move()

Move* node_next_move ( Node node)

Get the next move of the move list.

This is a thread/safe getter of the next move.

Parameters
nodeNode data.
Returns
the next move of the list.

◆ node_next_move_lockless()

static Move* node_next_move_lockless ( Node node)
static

Get the next move of the move list.

This is a thread/safe getter of the next move. If the search is stopped, or an alphabeta cut has been found or no move is available the function returns NULL.

Parameters
nodeNode data.
Returns
the next move of the list or NULL if none is available.

◆ node_split()

bool node_split ( Node node,
Move move 
)

Node split.

Here is the heart of the YBWC algorithm. It splits a node into two tasks. Splitting occurs if the following conditions are met:

  1. the first move has been already searched. The main principle of the YBWC algorithm. It avoids to split a cut-type node, for which searching a single move is enough, and thus diminish search-overhead.
  2. search to do is deep enough. In order to diminish the overhead of the parallelism. Can be tuned through SPLIT_MIN_DEPTH.
  3. the node has not been splitted yet. For a single position, only two tasks can run in parallel. The idea is to favor splitting elsewhere in the tree.
  4. This is not the last move. The idea is to lose less time in waiting for the parallel task to terminate. Can be tuned through SPLIT_MIN_MOVES_TODO. If these conditions are met, an idle task is requested, first from an idle task of a parent node; then, if none is available, from the idle task stack storage. If no idle task is found, the node splitting fails.
Parameters
nodeMaster node to split.
movemove to search.
Returns
true if the split was a success, false otherwise.

◆ node_update()

void node_update ( Node node,
Move move 
)

Update a node.

Update bestmove, bestscore and alpha value of the node, in case the move is the bestmove found so far. The function is thread-safe although it updates a shared resource. Double check lock is used as an optimization.

Parameters
nodecurrent node.
movelast evaluated move.

◆ node_wait_slaves()

void node_wait_slaves ( Node node)

Wait for slaves termination.

Actually, three steps are performed here:

  1. Stop slaves node in case their scores are unneeded.
  2. Wait for slaves' termination.
  3. Wake-up the master thread that may have been stopped.
Parameters
nodeNode.

◆ task_free()

void task_free ( Task task)

Free resources used by a task.

Parameters
taskThe task.

◆ task_init()

void task_init ( Task task)

Initialize a task.

Initialize task data members and start the task main loop task_loop() within a thread.

Parameters
taskThe task.

◆ task_loop()

void* task_loop ( void *  param)

The main loop runned by a task.

When task->run is set to true, the task starts a parallel search. In order to diminish the parallelism overhead, we do not launch a new thread at each new splitted node. Instead the threads are created at the beginning of the program and run a waiting loop who enters/quits a parallel search when requested.

Parameters
paramThe task.
Returns
NULL.

◆ task_search()

void task_search ( Task task)

A parallel search within a Task structure.

Here we share the search with a main parent task.

Parameters
taskThe task to search with.

◆ task_search_create()

static Search* task_search_create ( Task task)
static

Create a search structure for a task.

Parameters
taskThe task.
Returns
a search structure.

◆ task_search_destroy()

static void task_search_destroy ( Search search)
static

Free a search structure of a task.

Parameters
searchThe search structure.

◆ task_stack_free()

void task_stack_free ( TaskStack stack)

Free resources used by the stack of tasks.

Parameters
stackThe stack of tasks.

◆ task_stack_get_idle_task()

Task* task_stack_get_idle_task ( TaskStack stack)

Return, if available, an idle task.

Parameters
stackThe stack of tasks.
Returns
An idle task.

◆ task_stack_init()

void task_stack_init ( TaskStack stack,
const int  n 
)

Initialize the stack of tasks.

Parameters
stackThe stack of tasks.
nStack size (number of tasks).

◆ task_stack_put_idle_task()

void task_stack_put_idle_task ( TaskStack stack,
Task task 
)

Put back an idle task after using it.

Parameters
stackThe stack of tasks.
taskAn idle task.

◆ task_stack_resize()

void task_stack_resize ( TaskStack stack,
const int  n 
)

Resize the stack of tasks.

Parameters
stackStack to resize.
nNew stack size.

Variable Documentation

◆ search_log

Log search_log[1]