RCS file: /sources/gnugo/gnugo/engine/cache.c,v
retrieving revision 1.50
diff -u -r1.50 cache.c
|
|
|
|
| 39 | 39 | /* ---------------------------------------------------------------- */ |
| 40 | 40 | |
| 41 | 41 | static void tt_init(Transposition_table *table, int memsize); |
| 42 | | static void tt_clear(Transposition_table *table); |
| | 42 | inline static void tt_clear(Transposition_table *table); |
| 43 | 43 | |
| 44 | 44 | /* The transposition table itself. */ |
| 45 | 45 | Transposition_table ttable; |
| … |
… |
|
| 72 | 72 | calculate_hashval_for_tt(Hash_data *hashdata, int routine, int target1, |
| 73 | 73 | int target2, Hash_data *extra_hash) |
| 74 | 74 | { |
| 75 | | *hashdata = board_hash; /* from globals.c */ |
| | 75 | *hashdata = board_hash; /* from boardlib.c */ |
| 76 | 76 | hashdata_xor(*hashdata, routine_hash[routine]); |
| 77 | 77 | hashdata_xor(*hashdata, target1_hash[target1]); |
| 78 | 78 | if (target2 != NO_MOVE) |
| … |
… |
|
| 97 | 97 | keyhash_init(); |
| 98 | 98 | |
| 99 | 99 | if (memsize > 0) |
| 100 | | num_entries = memsize / sizeof(table->entries[0]); |
| | 100 | num_entries = memsize / sizeof(Hashentry); |
| 101 | 101 | else |
| 102 | 102 | num_entries = DEFAULT_NUMBER_OF_CACHE_ENTRIES; |
| 103 | 103 | |
| 104 | 104 | table->num_entries = num_entries; |
| 105 | | table->entries = malloc(num_entries * sizeof(table->entries[0])); |
| | 105 | table->entries = malloc(num_entries * sizeof(Hashentry)); |
| 106 | 106 | |
| 107 | 107 | if (table->entries == NULL) { |
| 108 | 108 | perror("Couldn't allocate memory for transposition table. \n"); |
| 109 | 109 | exit(1); |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | | table->is_clean = 0; |
| 113 | 112 | tt_clear(table); |
| 114 | 113 | } |
| 115 | 114 | |
| 116 | 115 | |
| 117 | 116 | /* Clear the transposition table. */ |
| 118 | 117 | |
| 119 | | static void |
| | 118 | inline static void |
| 120 | 119 | tt_clear(Transposition_table *table) |
| 121 | 120 | { |
| 122 | | if (!table->is_clean) { |
| 123 | | memset(table->entries, 0, table->num_entries * sizeof(table->entries[0])); |
| 124 | | table->is_clean = 1; |
| 125 | | } |
| | 121 | memset(table->entries, 0, table->num_entries * sizeof(Hashentry)); |
| 126 | 122 | } |
| 127 | | |
| 128 | | |
| | 123 | |
| | 124 | |
| 129 | 125 | /* Free the transposition table. */ |
| 130 | 126 | |
| 131 | | void |
| | 127 | inline void |
| 132 | 128 | tt_free(Transposition_table *table) |
| 133 | 129 | { |
| 134 | 130 | free(table->entries); |
| 135 | 131 | } |
| 136 | 132 | |
| 137 | 133 | |
| 138 | | /* Get result and move. Return value: |
| | 134 | /* Get result and move (the bigger remaining depth the lower depth). |
| | 135 | * Return value: |
| 139 | 136 | * 0 if not found |
| 140 | | * 1 if found, but depth too small to be trusted. In this case the move |
| | 137 | * 1 if found, but depth too big to be trusted. In this case the move |
| 141 | 138 | * can be used for move ordering. |
| 142 | | * 2 if found and depth is enough so that the result can be trusted. |
| | 139 | * 2 if found and depth is small enough so that the result can be trusted. |
| 143 | 140 | */ |
| 144 | 141 | |
| 145 | 142 | int |
| … |
… |
|
| 162 | 159 | |
| 163 | 160 | /* Get the correct entry and node. */ |
| 164 | 161 | entry = &table->entries[hashdata_remainder(hashval, table->num_entries)]; |
| 165 | | if (hashdata_is_equal(hashval, entry->deepest.key)) |
| 166 | | node = &entry->deepest; |
| | 162 | |
| | 163 | if (hashdata_is_equal(hashval, entry->most_reliable.key)) |
| | 164 | node = &entry->most_reliable; |
| 167 | 165 | else if (hashdata_is_equal(hashval, entry->newest.key)) |
| 168 | 166 | node = &entry->newest; |
| 169 | 167 | else |
| 170 | 168 | return 0; |
| 171 | 169 | |
| 172 | | stats.read_result_hits++; |
| | 170 | #ifndef GG_TURN_OFF_STATS |
| | 171 | ++stats.read_result_hits; |
| | 172 | #endif |
| 173 | 173 | |
| 174 | 174 | /* Return data. Only set the result if remaining depth in the table |
| 175 | 175 | * is big enough to be trusted. The move can always be used for move |
| … |
… |
|
| 177 | 177 | */ |
| 178 | 178 | if (move) |
| 179 | 179 | *move = hn_get_move(node->data); |
| | 180 | |
| 180 | 181 | if (remaining_depth <= (int) hn_get_remaining_depth(node->data)) { |
| 181 | 182 | if (value1) |
| 182 | 183 | *value1 = hn_get_value1(node->data); |
| 183 | 184 | if (value2) |
| 184 | 185 | *value2 = hn_get_value2(node->data); |
| 185 | | stats.trusted_read_result_hits++; |
| | 186 | |
| | 187 | #ifndef GG_TURN_OFF_STATS |
| | 188 | ++stats.trusted_read_result_hits; |
| | 189 | #endif |
| | 190 | |
| 186 | 191 | return 2; |
| 187 | 192 | } |
| 188 | 193 | |
| … |
… |
|
| 201 | 206 | { |
| 202 | 207 | Hash_data hashval; |
| 203 | 208 | Hashentry *entry; |
| 204 | | Hashnode *deepest; |
| | 209 | Hashnode *most_reliable; |
| 205 | 210 | Hashnode *newest; |
| 206 | 211 | unsigned int data; |
| 207 | 212 | /* Get routine costs definitions from liberty.h. */ |
| … |
… |
|
| 220 | 225 | |
| 221 | 226 | /* Get the entry and nodes. */ |
| 222 | 227 | entry = &table->entries[hashdata_remainder(hashval, table->num_entries)]; |
| 223 | | deepest = &entry->deepest; |
| | 228 | most_reliable = &entry->most_reliable; |
| 224 | 229 | newest = &entry->newest; |
| 225 | 230 | |
| 226 | 231 | /* See if we found an already existing node. */ |
| 227 | | if (hashdata_is_equal(hashval, deepest->key) |
| 228 | | && remaining_depth >= (int) hn_get_remaining_depth(deepest->data)) { |
| 229 | | |
| 230 | | /* Found deepest */ |
| 231 | | deepest->data = data; |
| 232 | | |
| | 232 | if (hashdata_is_equal(hashval, most_reliable->key)) |
| | 233 | { |
| | 234 | /* Found shallower node (can be trusted more likely) */ |
| | 235 | if (remaining_depth > (int) hn_get_remaining_depth(most_reliable->data)) |
| | 236 | most_reliable->data = data; |
| 233 | 237 | } |
| 234 | | else if (hashdata_is_equal(hashval, newest->key) |
| 235 | | && remaining_depth >= (int) hn_get_remaining_depth(newest->data)) { |
| 236 | | |
| 237 | | /* Found newest */ |
| 238 | | newest->data = data; |
| 239 | | |
| 240 | | /* If newest has become deeper than deepest, then switch them. */ |
| 241 | | if (hn_get_remaining_depth(newest->data) |
| 242 | | > hn_get_remaining_depth(deepest->data)) { |
| 243 | | Hashnode temp; |
| 244 | | |
| 245 | | temp = *deepest; |
| 246 | | *deepest = *newest; |
| 247 | | *newest = temp; |
| 248 | | } |
| 249 | | |
| | 238 | else if (hashdata_is_equal(hashval, newest->key)) |
| | 239 | { |
| | 240 | /* Found newest */ |
| | 241 | if (remaining_depth > (int) hn_get_remaining_depth(newest->data)) |
| | 242 | { |
| | 243 | newest->data = data; |
| | 244 | |
| | 245 | /* If newest reliability is bigger than most_reliable, switch them. */ |
| | 246 | if (hn_get_reliability(newest->data) > |
| | 247 | hn_get_reliability(most_reliable->data)) |
| | 248 | { |
| | 249 | Hashnode temp; |
| | 250 | |
| | 251 | temp = *most_reliable; |
| | 252 | *most_reliable = *newest; |
| | 253 | *newest = temp; |
| | 254 | } |
| | 255 | } |
| | 256 | } |
| | 257 | /* Have new node. */ |
| | 258 | else if (hn_get_reliability(data) > |
| | 259 | hn_get_reliability(most_reliable->data)) |
| | 260 | { |
| | 261 | /* Replace most_reliable. */ |
| | 262 | most_reliable->key = hashval; |
| | 263 | most_reliable->data = data; |
| 250 | 264 | } |
| 251 | | else if (hn_get_total_cost(data) > hn_get_total_cost(deepest->data)) { |
| 252 | | if (hn_get_total_cost(newest->data) < hn_get_total_cost(deepest->data)) |
| 253 | | *newest = *deepest; |
| 254 | | deepest->key = hashval; |
| 255 | | deepest->data = data; |
| 256 | | } |
| 257 | | else { |
| | 265 | else |
| | 266 | { |
| 258 | 267 | /* Replace newest. */ |
| 259 | 268 | newest->key = hashval; |
| 260 | 269 | newest->data = data; |
| 261 | 270 | } |
| 262 | 271 | |
| 263 | | stats.read_result_entered++; |
| 264 | | table->is_clean = 0; |
| | 272 | #ifndef GG_TURN_OFF_STATS |
| | 273 | ++stats.read_result_entered; |
| | 274 | #endif |
| 265 | 275 | } |
| 266 | 276 | |
| 267 | 277 | |
| … |
… |
|
| 270 | 280 | }; |
| 271 | 281 | |
| 272 | 282 | /* Convert a routine as used in the cache table to a string. */ |
| 273 | | const char * |
| | 283 | inline const char * |
| 274 | 284 | routine_id_to_string(enum routine_id routine) |
| 275 | 285 | { |
| 276 | 286 | return routine_names[(int) routine]; |
| … |
… |
|
| 282 | 292 | * allocate a single node or if the allocation fails, the caching is |
| 283 | 293 | * disabled. |
| 284 | 294 | */ |
| 285 | | void |
| | 295 | inline void |
| 286 | 296 | reading_cache_init(int bytes) |
| 287 | 297 | { |
| 288 | 298 | tt_init(&ttable, bytes); |
| … |
… |
|
| 290 | 300 | |
| 291 | 301 | |
| 292 | 302 | /* Clear the cache for read results. */ |
| 293 | | void |
| | 303 | inline void |
| 294 | 304 | reading_cache_clear() |
| 295 | 305 | { |
| 296 | 306 | tt_clear(&ttable); |
| 297 | 307 | } |
| 298 | 308 | |
| 299 | | float |
| | 309 | inline float |
| 300 | 310 | reading_cache_default_size() |
| 301 | 311 | { |
| 302 | 312 | return DEFAULT_NUMBER_OF_CACHE_ENTRIES * sizeof(Hashentry) / 1024.0 / 1024.0; |