/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see * * http://www.gnu.org/software/gnugo/ for more information. * * * * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * * 2008 and 2009 by the Free Software Foundation. * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation - version 3 or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License in file COPYING for more details. * * * * You should have received a copy of the GNU General Public * * License along with this program; if not, write to the Free * * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02111, USA. * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef _CACHE_H_ #define _CACHE_H_ #include #include "hash.h" /* * This file, together with engine/hash.c implements hashing of go positions * using a method known as Zobrist hashing. See the Texinfo documentation * (Reading/Hashing) for more information. */ /* Hashnode: a node stored in the transposition table. * * In addition to the position, the hash lock encodes the following data, * all hashed: * komaster * kom_pos * routine * str1 * str2 * extra hashvalue, optional (e.g. encoding a goal array) * * The data field packs into 32 bits the following * fields: * * RESERVED : 5 bits * value1 : 4 bits * value2 : 4 bits * move : 10 bits * cost : 4 bits * remaining_depth: 5 bits (depth - stackp) NOTE: HN_MAX_REMAINING_DEPTH * * The last 9 bits together give an index for the total costs. */ typedef struct { Hash_data key; unsigned int data; /* Should be 32 bits, but only wastes 25% if 64 bits. */ } Hashnode; #define HN_MAX_REMAINING_DEPTH 31 /* Hashentry: an entry, with two nodes of the hash_table */ typedef struct { Hashnode deepest; Hashnode newest; } Hashentry; /* Hn is for hash node. */ #define hn_get_value1(hn) ((hn >> 23) & 0x0f) #define hn_get_value2(hn) ((hn >> 19) & 0x0f) #define hn_get_move(hn) ((hn >> 9) & 0x3ff) #define hn_get_cost(hn) ((hn >> 5) & 0x0f) #define hn_get_remaining_depth(hn) ((hn >> 0) & 0x1f) #define hn_get_total_cost(hn) ((hn >> 0) & 0x1ff) #define hn_create_data(remaining_depth, value1, value2, move, cost) \ ((((value1) & 0x0f) << 23) \ | (((value2) & 0x0f) << 19) \ | (((move) & 0x3ff) << 9) \ | (((cost) & 0x0f) << 5) \ | (((remaining_depth & 0x1f) << 0))) /* Transposition_table: transposition table used for caching. */ typedef struct { unsigned int num_entries; Hashentry *entries; int is_clean; } Transposition_table; extern Transposition_table ttable; /* Number of cache entries to use by default if no cache memory usage * has been set explicitly. */ #define DEFAULT_NUMBER_OF_CACHE_ENTRIES 350000 void tt_free(Transposition_table *table); int tt_get(Transposition_table *table, enum routine_id routine, int target1, int target2, int remaining_depth, Hash_data *extra_hash, int *value1, int *value2, int *move); void tt_update(Transposition_table *table, enum routine_id routine, int target, int target2, int remaining_depth, Hash_data *extra_hash, int value1, int value2, int move); /* ================================================================ */ /* Macros used from reading.c, readconnect.c, and owl.c to store and * retrieve read results. */ #if TRACE_READ_RESULTS #define TRACE_CACHED_RESULT(result, move) \ gprintf("%o%s %1m %d %d %1m (cached) ", read_function_name, \ q, stackp, result, move); \ dump_stack(); #define TRACE_CACHED_RESULT2(result1, result2, move) \ gprintf("%o%s %1m %1m %d %d %d %1m (cached) ", read_function_name, \ q1, q2, stackp, result1, result2, move); \ dump_stack(); #define SETUP_TRACE_INFO(name, str) \ const char *read_function_name = name; \ int q = find_origin(str); #define SETUP_TRACE_INFO2(name, str1, str2) \ const char *read_function_name = name; \ int q1 = board[str1] == EMPTY ? str1 : find_origin(str1); \ int q2 = board[str2] == EMPTY ? str2 : find_origin(str2); #else #define TRACE_CACHED_RESULT(result, move) #define TRACE_CACHED_RESULT2(result1, result2, move) #define SETUP_TRACE_INFO(name, str) \ const char *read_function_name = name; \ int q = str; #define SETUP_TRACE_INFO2(name, str1, str2) \ const char *read_function_name = name; \ int q1 = str1; \ int q2 = str2; #endif /* Trace messages in decidestring/decidedragon sgf file. */ void sgf_trace(const char *func, int str, int move, int result, const char *message); /* Trace messages in decideconnection sgf file. */ void sgf_trace2(const char *func, int str1, int str2, int move, const char *result, const char *message); /* Trace messages in decidesemeai sgf file. */ void sgf_trace_semeai(const char *func, int str1, int str2, int move, int result1, int result2, const char *message); /* Macro to hide the call to sgf_trace(). Notice that a little black * magic is going on here. Before using this macro, SETUP_TRACE_INFO * must have been called to provide the variables read_function_name * and q. These must of course not be used for anything else in * the function. */ #define SGFTRACE(move, result, message) \ if (sgf_dumptree) \ sgf_trace(read_function_name, q, move, result, message) /* Corresponding macro for use in connection or semeai reading, where * two groups are involved. */ #define SGFTRACE2(move, result, message) \ if (sgf_dumptree) \ sgf_trace2(read_function_name, q1, q2, move, \ result_to_string(result), message) #define SGFTRACE_SEMEAI(move, result1, result2, message) \ if (sgf_dumptree) \ sgf_trace_semeai(read_function_name, q1, q2, move, \ result1, result2, message) /* ================================================================ */ /* * These macros should be used in all the places where we want to * return a result from a reading function and where we want to * store the result in the hash table at the same time. */ #if !TRACE_READ_RESULTS #define READ_RETURN0(routine, str, remaining_depth) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ 0, 0, NO_MOVE);\ return 0; \ } while (0) #define READ_RETURN(routine, str, remaining_depth, point, move, value) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ return (value); \ } while (0) #define READ_RETURN_SEMEAI(routine, str1, str2, remaining_depth, point, move, value1, value2) \ do { \ tt_update(&ttable, routine, str1, str2, remaining_depth, NULL, \ value1, value2, move); \ if ((value1) != 0 && (point) != 0) *(point) = (move); \ return; \ } while (0) #define READ_RETURN_CONN(routine, str1, str2, remaining_depth, point, move, value) \ do { \ tt_update(&ttable, routine, str1, str2, remaining_depth, NULL,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ return (value); \ } while (0) #define READ_RETURN_HASH(routine, str, remaining_depth, hash, point, move, value) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, hash,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ return (value); \ } while (0) #define READ_RETURN2(routine, str, remaining_depth, point, move, value1, value2) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ value1, value2, move);\ if ((value1) != 0 && (point) != 0) *(point) = (move); \ return (value1); \ } while (0) #else /* !TRACE_READ_RESULTS */ #define READ_RETURN0(routine, str, remaining_depth) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ 0, 0, NO_MOVE);\ gprintf("%o%s %1m %d 0 0 ", read_function_name, q, stackp); \ dump_stack(); \ return 0; \ } while (0) #define READ_RETURN(routine, str, remaining_depth, point, move, value) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ gprintf("%o%s %1m %d %d %1m ", read_function_name, q, stackp, \ (value), (move)); \ dump_stack(); \ return (value); \ } while (0) #define READ_RETURN_SEMEAI(routine, str1, str2, remaining_depth, point, move, value1, value2) \ do { \ tt_update(&ttable, routine, str1, str2, remaining_depth, NULL, \ value1, value2, move); \ if ((value1) != 0 && (point) != 0) *(point) = (move); \ gprintf("%o%s %1m %1m %d %d %d %1m ", read_function_name, q1, q2, stackp, \ (value1), (value2), (move)); \ dump_stack(); \ return; \ } while (0) #define READ_RETURN_CONN(routine, str1, str2, remaining_depth, point, move, value) \ do { \ tt_update(&ttable, routine, str1, str2, remaining_depth, NULL,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ gprintf("%o%s %1m %1m %d %d %1m ", read_function_name, q1, q2, stackp, \ (value), (move)); \ dump_stack(); \ return (value); \ } while (0) #define READ_RETURN_HASH(routine, str, remaining_depth, hash, point, move, value) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, hash,\ value, 0, move);\ if ((value) != 0 && (point) != 0) *(point) = (move); \ gprintf("%o%s %1m %d %d %1m ", read_function_name, q, stackp, \ (value), (move)); \ dump_stack(); \ return (value); \ } while (0) #define READ_RETURN2(routine, str, remaining_depth, point, move, value1, value2) \ do { \ tt_update(&ttable, routine, str, NO_MOVE, remaining_depth, NULL,\ value1, value2, move);\ if ((value1) != 0 && (point) != 0) *(point) = (move); \ gprintf("%o%s %1m %d %d %1m ", read_function_name, q, stackp, \ (value1), (move)); \ dump_stack(); \ return (value1); \ } while (0) #endif /* ================================================================ */ /* This has actually nothing to do with caching, but is useful in * the same places where the caching is. */ /* Macro to use when saving ko results while continuing to look for an * unconditional result. It's assumed that we have tried the move at * (move) and then called an attack or defense function giving the * result passed in the code parameter. * * In general we prefer not to have to do the first ko threat. Thus a * savecode KO_A is always better than a savecode KO_B. Also we always * prefer to keep the old move if we get the same savecode once more, * on the assumption that the moves have been ordered with the * presumably best one first. * * Notice that the savecode may be either 0 (nothing found so far), KO_B * or KO_A. Occasionally savecode WIN is also used, indicating an effective * but not preferred move, typically because it's either a sacrifice * or a backfilling move. If possible, we prefer making non-sacrifice * and direct moves. Of course savecode WIN is better than KO_A or KO_B. */ #define UPDATE_SAVED_KO_RESULT(savecode, save, code, move) \ if (code != 0 && REVERSE_RESULT(code) > savecode) { \ save = move; \ savecode = REVERSE_RESULT(code); \ } \ /* Same as above, except this should be used when there's no * intervening trymove(). Thus we shouldn't reverse the save code. */ #define UPDATE_SAVED_KO_RESULT_UNREVERSED(savecode, save, code, move) \ if (code != WIN && code > savecode) { \ save = move; \ savecode = code; \ } /* This too isn't really related to caching but is convenient to have here. * (Needs to be available in reading.c and persistent.c.) * * Minimum number of nodes for which DEBUG_READING_PERFORMANCE reports * anything. */ #define MIN_READING_NODES_TO_REPORT 1000 #endif /* _CACHE_H_ */ /* * Local Variables: * tab-width: 8 * c-basic-offset: 2 * End: */