perf(game-engine): 대규모 NPC 천통 시간을 계측
시나리오 2601의 880명·94도시를 DB와 Redis 없이 자동 실행하고 커맨드, 수뇌 여부, 연월별 시간을 JSON으로 기록한다.
This commit is contained in:
@@ -753,6 +753,21 @@ export const createReservedTurnHandler = async (options: {
|
||||
blockedReason?: string;
|
||||
aiState?: ReturnType<GeneralAI['getDebugState']>;
|
||||
}) => void;
|
||||
onActionProfiled?: (payload: {
|
||||
kind: 'nation' | 'general';
|
||||
generalId: number;
|
||||
nationId: number | null;
|
||||
officerLevel: number;
|
||||
npcState: number;
|
||||
year: number;
|
||||
month: number;
|
||||
requestedAction: string;
|
||||
actionKey: string;
|
||||
usedFallback: boolean;
|
||||
usedAi: boolean;
|
||||
aiDecisionDurationNs: bigint;
|
||||
actionDurationNs: bigint;
|
||||
}) => void;
|
||||
}): Promise<GeneralTurnHandler> => {
|
||||
const env = options.commandEnv ?? buildCommandEnv(options.scenarioConfig, options.unitSet);
|
||||
const itemRegistry = createItemModuleRegistry(await loadItemModules([...ITEM_KEYS]));
|
||||
@@ -1627,7 +1642,11 @@ export const createReservedTurnHandler = async (options: {
|
||||
hasReservedTurn = true;
|
||||
}
|
||||
let nationAiState: ReturnType<GeneralAI['getDebugState']> | undefined;
|
||||
let nationAiDecisionDurationNs = 0n;
|
||||
let nationUsedAi = false;
|
||||
if (worldView && shouldUseAi(currentGeneral, context.world)) {
|
||||
nationUsedAi = true;
|
||||
const aiStartedAt = options.onActionProfiled ? process.hrtime.bigint() : 0n;
|
||||
sharedAi = new GeneralAI({
|
||||
general: currentGeneral,
|
||||
city: currentCity,
|
||||
@@ -1647,6 +1666,9 @@ export const createReservedTurnHandler = async (options: {
|
||||
});
|
||||
const ai = sharedAi;
|
||||
const candidate = ai.chooseNationTurn(nationCommand);
|
||||
if (options.onActionProfiled) {
|
||||
nationAiDecisionDurationNs = process.hrtime.bigint() - aiStartedAt;
|
||||
}
|
||||
if (candidate) {
|
||||
if (
|
||||
(process.env.CORE_AI_TRACE_GENERAL_IDS?.split(',') ?? []).includes(
|
||||
@@ -1690,7 +1712,11 @@ export const createReservedTurnHandler = async (options: {
|
||||
}
|
||||
nationAiState = ai.getDebugState();
|
||||
}
|
||||
const nationActionStartedAt = options.onActionProfiled ? process.hrtime.bigint() : 0n;
|
||||
const nationResult = runAction('nation', nationDefinitions, nationFallback, nationCommand, false);
|
||||
const nationActionDurationNs = options.onActionProfiled
|
||||
? process.hrtime.bigint() - nationActionStartedAt
|
||||
: 0n;
|
||||
// Ref persists the nation command here, but LazyVarUpdater only
|
||||
// clears its dirty flags: it does not replace the same PHP
|
||||
// General object's fractional values with the MariaDB INT row.
|
||||
@@ -1722,6 +1748,21 @@ export const createReservedTurnHandler = async (options: {
|
||||
...(nationResult.blockedReason ? { blockedReason: nationResult.blockedReason } : {}),
|
||||
...(nationAiState ? { aiState: nationAiState } : {}),
|
||||
});
|
||||
options.onActionProfiled?.({
|
||||
kind: 'nation',
|
||||
generalId: currentGeneral.id,
|
||||
nationId: currentNation?.id ?? null,
|
||||
officerLevel: currentGeneral.officerLevel,
|
||||
npcState: currentGeneral.npcState,
|
||||
year: context.world.currentYear,
|
||||
month: context.world.currentMonth,
|
||||
requestedAction: nationCommand.action,
|
||||
actionKey: nationResult.actionKey,
|
||||
usedFallback: nationResult.usedFallback,
|
||||
usedAi: nationUsedAi,
|
||||
aiDecisionDurationNs: nationAiDecisionDurationNs,
|
||||
actionDurationNs: nationActionDurationNs,
|
||||
});
|
||||
options.reservedTurns.shiftNationTurns(currentNation.id, currentGeneral.officerLevel, -1);
|
||||
}
|
||||
if (isBlocked && currentNation && currentGeneral.officerLevel >= 5) {
|
||||
@@ -1745,7 +1786,11 @@ export const createReservedTurnHandler = async (options: {
|
||||
}
|
||||
let generalAiState: ReturnType<GeneralAI['getDebugState']> | undefined;
|
||||
let generalAutorunMode = false;
|
||||
let generalAiDecisionDurationNs = 0n;
|
||||
let generalUsedAi = false;
|
||||
if (!isBlocked && worldView && shouldUseAi(currentGeneral, context.world)) {
|
||||
generalUsedAi = true;
|
||||
const aiStartedAt = options.onActionProfiled ? process.hrtime.bigint() : 0n;
|
||||
const ai =
|
||||
sharedAi ??
|
||||
new GeneralAI({
|
||||
@@ -1766,6 +1811,9 @@ export const createReservedTurnHandler = async (options: {
|
||||
nationFallback,
|
||||
});
|
||||
const candidate = ai.chooseGeneralTurn(generalCommand);
|
||||
if (options.onActionProfiled) {
|
||||
generalAiDecisionDurationNs = process.hrtime.bigint() - aiStartedAt;
|
||||
}
|
||||
// Ref GeneralAI::calcDiplomacyState writes
|
||||
// nation_env.last_attackable for ordinary generals too. The
|
||||
// nation-turn path consumes this patch above, but most NPCs
|
||||
@@ -1818,6 +1866,7 @@ export const createReservedTurnHandler = async (options: {
|
||||
}
|
||||
generalAiState = ai.getDebugState();
|
||||
}
|
||||
const generalActionStartedAt = options.onActionProfiled ? process.hrtime.bigint() : 0n;
|
||||
const generalResult = isBlocked
|
||||
? {
|
||||
actionKey: DEFAULT_ACTION,
|
||||
@@ -1826,6 +1875,9 @@ export const createReservedTurnHandler = async (options: {
|
||||
blockedReason: '블럭 대상자입니다.',
|
||||
}
|
||||
: runAction('general', generalDefinitions, generalFallback, generalCommand, true);
|
||||
const generalActionDurationNs = options.onActionProfiled
|
||||
? process.hrtime.bigint() - generalActionStartedAt
|
||||
: 0n;
|
||||
options.onActionResolved?.({
|
||||
kind: 'general',
|
||||
generalId: currentGeneral.id,
|
||||
@@ -1837,6 +1889,21 @@ export const createReservedTurnHandler = async (options: {
|
||||
...(generalResult.blockedReason ? { blockedReason: generalResult.blockedReason } : {}),
|
||||
...(generalAiState ? { aiState: generalAiState } : {}),
|
||||
});
|
||||
options.onActionProfiled?.({
|
||||
kind: 'general',
|
||||
generalId: currentGeneral.id,
|
||||
nationId: currentNation?.id ?? null,
|
||||
officerLevel: currentGeneral.officerLevel,
|
||||
npcState: currentGeneral.npcState,
|
||||
year: context.world.currentYear,
|
||||
month: context.world.currentMonth,
|
||||
requestedAction: generalCommand.action,
|
||||
actionKey: generalResult.actionKey,
|
||||
usedFallback: generalResult.usedFallback,
|
||||
usedAi: generalUsedAi,
|
||||
aiDecisionDurationNs: generalAiDecisionDurationNs,
|
||||
actionDurationNs: generalActionDurationNs,
|
||||
});
|
||||
let nextTurnAt = 'nextTurnAt' in generalResult ? generalResult.nextTurnAt : undefined;
|
||||
options.reservedTurns.shiftGeneralTurns(currentGeneral.id, -1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user