Use raw pointers for search parameters to avoid false sharing, make global tunable dictionary constant (bench 5736541)
This commit is contained in:
3
Makefile
3
Makefile
@@ -44,6 +44,7 @@ PATCH_VERSION := 2
|
||||
THP_PAGE_ALIGNMENT := 2097152
|
||||
|
||||
|
||||
CFLAGS := -flto -static
|
||||
CUSTOM_FLAGS := -d:outputBuckets=$(OUTPUT_BUCKETS) \
|
||||
-d:inputBuckets=$(INPUT_BUCKETS) \
|
||||
-d:hlSize=$(HL_SIZE) \
|
||||
@@ -95,8 +96,6 @@ else
|
||||
CUSTOM_FLAGS += -d:danger
|
||||
endif
|
||||
|
||||
CFLAGS := -flto -static
|
||||
|
||||
ifeq ($(DBG_SYMBOLS),1)
|
||||
CUSTOM_FLAGS += --debugger:native
|
||||
CFLAGS += -fno-omit-frame-pointer -ggdb
|
||||
|
||||
@@ -190,7 +190,7 @@ when isMainModule:
|
||||
if bench:
|
||||
runBench(benchDepth)
|
||||
if getParams:
|
||||
echo getSPSAInput(getDefaultParameters())
|
||||
echo getSPSAInput(getDefaultParameters()[])
|
||||
elif magicGen:
|
||||
magicWizard()
|
||||
elif augment:
|
||||
|
||||
@@ -124,7 +124,7 @@ type
|
||||
state* : SearchState
|
||||
statistics* : SearchStatistics
|
||||
limiter* : SearchLimiter
|
||||
parameters* : SearchParameters
|
||||
parameters* : ptr SearchParameters
|
||||
logger* : SearchLogger
|
||||
histories* : HistoryTables
|
||||
ttable : ptr TTable
|
||||
@@ -551,14 +551,14 @@ proc scoreMove(self: SearchManager, hashMove: Move, move: Move, ply: int): Score
|
||||
|
||||
# Good/bad tacticals
|
||||
if move.isTactical():
|
||||
let winning = self.parameters.see(self.board.position, move, 0)
|
||||
let winning = self.parameters[].see(self.board.position, move, 0)
|
||||
if move.isCapture():
|
||||
result.data += self.historyScore(sideToMove, move)
|
||||
# Prioritize attacking our opponent's
|
||||
# most valuable pieces
|
||||
result.data += MVV_MULTIPLIER * self.parameters.staticPieceScore(self.board.on(move.targetSquare)).int32
|
||||
result.data += MVV_MULTIPLIER * self.parameters[].staticPieceScore(self.board.on(move.targetSquare)).int32
|
||||
elif move.isEnPassant():
|
||||
result.data += MVV_MULTIPLIER * self.parameters.staticPieceScore(Pawn).int32
|
||||
result.data += MVV_MULTIPLIER * self.parameters[].staticPieceScore(Pawn).int32
|
||||
if not winning:
|
||||
# Prioritize good exchanges (see > 0)
|
||||
result.data += BAD_CAPTURE_OFFSET
|
||||
@@ -723,11 +723,11 @@ proc rawEval(self: SearchManager): Score =
|
||||
rooks = self.board.pieces(Rook)
|
||||
queens = self.board.pieces(Queen)
|
||||
|
||||
let material = Score(self.parameters.materialPieceScore(Knight) * knights.count() +
|
||||
self.parameters.materialPieceScore(Bishop) * bishops.count() +
|
||||
self.parameters.materialPieceScore(Pawn) * pawns.count() +
|
||||
self.parameters.materialPieceScore(Rook) * rooks.count() +
|
||||
self.parameters.materialPieceScore(Queen) * queens.count())
|
||||
let material = Score(self.parameters[].materialPieceScore(Knight) * knights.count() +
|
||||
self.parameters[].materialPieceScore(Bishop) * bishops.count() +
|
||||
self.parameters[].materialPieceScore(Pawn) * pawns.count() +
|
||||
self.parameters[].materialPieceScore(Rook) * rooks.count() +
|
||||
self.parameters[].materialPieceScore(Queen) * queens.count())
|
||||
|
||||
# This scales the eval linearly between base / divisor and (base + max material) / divisor
|
||||
result = result * (material + Score(self.parameters.materialScalingOffset)) div Score(self.parameters.materialScalingDivisor)
|
||||
@@ -863,7 +863,7 @@ proc qsearch(self: var SearchManager, root: static bool, ply: int, alpha, beta:
|
||||
elif scoredMove.stage() == BadNoisy:
|
||||
false
|
||||
else:
|
||||
self.parameters.see(self.board.position, move, 0)
|
||||
self.parameters[].see(self.board.position, move, 0)
|
||||
# Skip known bad captures
|
||||
if not winning:
|
||||
continue
|
||||
@@ -873,7 +873,7 @@ proc qsearch(self: var SearchManager, root: static bool, ply: int, alpha, beta:
|
||||
|
||||
# Qsearch futility pruning: similar to FP in regular search, but we skip moves
|
||||
# that gain no material on top of not improving alpha (given a margin)
|
||||
if not recapture and not self.stack[ply].inCheck and staticEval + self.parameters.qsearchFpEvalMargin <= alpha and not self.parameters.see(self.board.position, move, 1):
|
||||
if not recapture and not self.stack[ply].inCheck and staticEval + self.parameters.qsearchFpEvalMargin <= alpha and not self.parameters[].see(self.board.position, move, 1):
|
||||
continue
|
||||
let kingSq = self.board.position.kingSquare(self.board.sideToMove)
|
||||
self.stack[ply].move = move
|
||||
@@ -1201,7 +1201,7 @@ proc search(self: var SearchManager, depth, ply: int, alpha, beta: Score, isPV,
|
||||
if lmrDepth <= SEE_PRUNING_MAX_DEPTH and (move.isQuiet() or move.isCapture() or move.isEnPassant()):
|
||||
# SEE pruning: prune moves with a bad enough SEE score
|
||||
let margin = -depth * (if move.isQuiet(): self.parameters.seePruningMargin.quiet else: self.parameters.seePruningMargin.capture)
|
||||
if not self.parameters.see(self.board.position, move, margin):
|
||||
if not self.parameters[].see(self.board.position, move, margin):
|
||||
inc(seenMoves)
|
||||
continue
|
||||
var singular = 0
|
||||
@@ -1523,7 +1523,7 @@ proc search*(self: var SearchManager, searchMoves: seq[Move] = @[], silent=false
|
||||
for depth in 1..MAX_DEPTH:
|
||||
if self.limiter.expiredSoft():
|
||||
break iterativeDeepening
|
||||
self.limiter.scale(self.parameters)
|
||||
self.limiter.scale(self.parameters[])
|
||||
|
||||
for i in 1..variations:
|
||||
self.statistics.selectiveDepth.store(0, moRelaxed)
|
||||
|
||||
@@ -1326,7 +1326,10 @@ proc startUCISession* =
|
||||
# Search already running. Let's teach the user a lesson
|
||||
session.searcher.cancel()
|
||||
searchWorker.waitFor(SearchComplete)
|
||||
echo "info string premium membership is required to send go during search. Please check out https://n9x.co/heimdall-premium for details"
|
||||
if not session.isMixedMode:
|
||||
echo "info string premium membership is required to send go during search. Please check out https://n9x.co/heimdall-premium for details"
|
||||
else:
|
||||
stdout.styledWrite(useColor, fgYellow, "Warning: premium membership is required to send go during search. Please check out https://n9x.co/heimdall-premium for details\n")
|
||||
continue
|
||||
if session.board.isGameOver():
|
||||
if not session.isMixedMode:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import std/[math, tables, strutils, strformat]
|
||||
|
||||
import heimdall/pieces
|
||||
import heimdall/util/memory/aligned
|
||||
|
||||
|
||||
const isTuningEnabled* {.booldefine:"enableTuning".} = false
|
||||
@@ -28,7 +29,7 @@ type
|
||||
max*: int
|
||||
default*: int
|
||||
|
||||
SearchParameters* = ref object
|
||||
SearchParameters* = object
|
||||
## A set of search parameters
|
||||
|
||||
# Null move pruning
|
||||
@@ -110,8 +111,6 @@ type
|
||||
corrHistScale*: tuple[weight, eval: tuple[pawn, nonpawn, major, minor: int]]
|
||||
|
||||
|
||||
var params = newTable[string, TunableParameter]()
|
||||
|
||||
proc newTunableParameter*(name: string, min, max, default: int): TunableParameter =
|
||||
## Initializes a new tunable parameter
|
||||
result.name = name
|
||||
@@ -179,10 +178,10 @@ MinorCorrHistEvalScale, 261
|
||||
|
||||
|
||||
template addTunableParameter(name: string, min, max, default: int) =
|
||||
params[name] = newTunableParameter(name, min, max, default)
|
||||
result[name] = newTunableParameter(name, min, max, default)
|
||||
|
||||
|
||||
proc addTunableParameters =
|
||||
proc initTunableParameters: Table[string, TunableParameter] =
|
||||
## Adds all our tunable parameters to the global
|
||||
## parameter list
|
||||
addTunableParameter("RFPBaseMargin", 1, 200, 100)
|
||||
@@ -250,7 +249,10 @@ proc addTunableParameters =
|
||||
if line.len() == 0:
|
||||
continue
|
||||
let splosh = line.split(",", maxsplit=2)
|
||||
params[splosh[0]].default = splosh[1].parseInt()
|
||||
result[splosh[0]].default = splosh[1].parseInt()
|
||||
|
||||
|
||||
const params = initTunableParameters()
|
||||
|
||||
|
||||
proc isParamName*(name: string): bool =
|
||||
@@ -259,7 +261,7 @@ proc isParamName*(name: string): bool =
|
||||
return name in params
|
||||
|
||||
|
||||
proc setParameter*(self: SearchParameters, name: string, value: int) =
|
||||
proc setParameter*(self: ptr SearchParameters, name: string, value: int) =
|
||||
## Sets the tunable parameter with the given name
|
||||
## to the given integer value
|
||||
|
||||
@@ -497,14 +499,13 @@ iterator getParameters*: TunableParameter =
|
||||
proc getParamCount*: int = len(params)
|
||||
|
||||
|
||||
proc getDefaultParameters*: SearchParameters {.gcsafe.} =
|
||||
proc getDefaultParameters*: ptr SearchParameters {.gcsafe.} =
|
||||
## Returns the set of parameters to be
|
||||
## used during search
|
||||
new(result)
|
||||
# TODO: This is ugly, find a way around it
|
||||
{.cast(gcsafe).}:
|
||||
for key in params.keys():
|
||||
result.setParameter(key, params[key].default)
|
||||
result = allocHeapAligned(SearchParameters, 64)
|
||||
result[] = default(SearchParameters)
|
||||
for key in params.keys():
|
||||
result.setParameter(key, params[key].default)
|
||||
|
||||
|
||||
proc getSPSAInput*(parameters: SearchParameters): string =
|
||||
@@ -519,6 +520,7 @@ proc getSPSAInput*(parameters: SearchParameters): string =
|
||||
result &= "\n"
|
||||
inc(i)
|
||||
|
||||
|
||||
func staticPieceScore*(parameters: SearchParameters, kind: PieceKind): int {.inline.} =
|
||||
## Returns a static score for the given piece
|
||||
## type to be used inside SEE. This makes testing
|
||||
@@ -546,7 +548,4 @@ func materialPieceScore*(parameters: SearchParameters, kind: PieceKind): int {.i
|
||||
func materialPieceScore*(parameters: SearchParameters, piece: Piece): int {.inline.} =
|
||||
## Returns a static score for the given piece
|
||||
## type to be used for material scaling
|
||||
return parameters.staticPieceScore(piece.kind)
|
||||
|
||||
|
||||
addTunableParameters()
|
||||
return parameters.staticPieceScore(piece.kind)
|
||||
Reference in New Issue
Block a user