新增: - hjha-console/Program.cs: --stress N 压测模式 - 每局独立日志 stress_logs/round_NNNNN.txt - 每 50 局进度汇报 + 异常捕获 - docs/stress-test-report.md: 完整分析报告 - P0: 包庄严重高估(5.2%成功) → 需校准阈值 - P1: 75 moves 异常局 → 疑似死循环 - P2: 只出单张不组合 → rollout 优化 - P3: 性能瓶颈分析 - .gitignore: stress_logs/, analyze_stress.py 压测结果: 12.8min, 0 crashes, 1000/1000通过
108 lines
4.1 KiB
C#
108 lines
4.1 KiB
C#
using PdkFriendServer.Logic;
|
||
using System;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
|
||
namespace hjha_console
|
||
{
|
||
class Program
|
||
{
|
||
static void Main(string[] args)
|
||
{
|
||
if (args.Length > 0 && args[0] == "--stress")
|
||
{
|
||
int rounds = args.Length > 1 ? int.Parse(args[1]) : 100;
|
||
RunStressTest(rounds);
|
||
return;
|
||
}
|
||
|
||
Console.WriteLine("=== HJHA Console Mode - 跑得快 Bot对局 (3人自动) ===");
|
||
Console.WriteLine("牌型:关牌玩法 16张/人 | 策略:ISMCTS 800sims");
|
||
Console.WriteLine("压测: dotnet run --project hjha-console -- --stress 1000");
|
||
Console.WriteLine();
|
||
|
||
var main = new PdkGameMain(null);
|
||
main.BotMode = true;
|
||
main.Test(args.Length > 0 ? args[0] : "");
|
||
}
|
||
|
||
static void RunStressTest(int totalRounds)
|
||
{
|
||
var logDir = "stress_logs";
|
||
if (!Directory.Exists(logDir)) Directory.CreateDirectory(logDir);
|
||
|
||
// 清理旧日志
|
||
foreach (var f in Directory.GetFiles(logDir, "round_*.txt"))
|
||
File.Delete(f);
|
||
File.Delete("stress_errors.txt");
|
||
File.Delete("stress_summary.txt");
|
||
|
||
Console.WriteLine($"=== PdkBot Stress Test: {totalRounds} rounds ===");
|
||
Console.WriteLine($"Logs: {logDir}/");
|
||
Console.WriteLine($"Start: {DateTime.Now:HH:mm:ss}");
|
||
Console.WriteLine();
|
||
|
||
int completed = 0, errors = 0;
|
||
var totalSw = Stopwatch.StartNew();
|
||
var errorLog = new StreamWriter("stress_errors.txt", true) { AutoFlush = true };
|
||
|
||
for (int r = 1; r <= totalRounds; r++)
|
||
{
|
||
var roundSw = Stopwatch.StartNew();
|
||
try
|
||
{
|
||
var main = new PdkGameMain(null);
|
||
main.BotMode = true;
|
||
|
||
// 重定向 output.txt 到本轮日志
|
||
var logPath = $"{logDir}/round_{r:D5}.txt";
|
||
if (File.Exists("output.txt")) File.Delete("output.txt");
|
||
|
||
main.Test("");
|
||
|
||
// 移动 output.txt → 本轮日志
|
||
if (File.Exists("output.txt"))
|
||
File.Move("output.txt", logPath);
|
||
|
||
completed++;
|
||
roundSw.Stop();
|
||
|
||
if (r % 50 == 0 || r == totalRounds)
|
||
{
|
||
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {r}/{totalRounds} rounds | " +
|
||
$"{errors} errors | avg {totalSw.Elapsed.TotalSeconds / r:F1}s/round | " +
|
||
$"last {roundSw.ElapsedMilliseconds}ms");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
errors++;
|
||
errorLog.WriteLine($"Round {r}: {ex.GetType().Name}: {ex.Message}");
|
||
errorLog.WriteLine(ex.StackTrace);
|
||
errorLog.WriteLine("---");
|
||
Console.WriteLine($" R{r} ERROR: {ex.GetType().Name}: {ex.Message}");
|
||
|
||
// 保存本轮部分日志
|
||
if (File.Exists("output.txt"))
|
||
File.Move("output.txt", $"{logDir}/round_{r:D5}_ERROR.txt");
|
||
}
|
||
}
|
||
|
||
totalSw.Stop();
|
||
errorLog.Close();
|
||
|
||
// 汇总
|
||
Console.WriteLine();
|
||
Console.WriteLine($"=== Stress Test Complete ===");
|
||
Console.WriteLine($"Rounds: {completed}/{totalRounds} completed, {errors} errors");
|
||
Console.WriteLine($"Total time: {totalSw.Elapsed.TotalMinutes:F1} min");
|
||
Console.WriteLine($"Avg per round: {totalSw.Elapsed.TotalSeconds / totalRounds:F1}s");
|
||
File.WriteAllText("stress_summary.txt",
|
||
$"Rounds: {completed}/{totalRounds}\n" +
|
||
$"Errors: {errors}\n" +
|
||
$"Total: {totalSw.Elapsed.TotalMinutes:F1}min\n" +
|
||
$"Avg: {totalSw.Elapsed.TotalSeconds / totalRounds:F1}s/round\n");
|
||
}
|
||
}
|
||
}
|