analyze.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. """
  2. 分析缓存命中情况的脚本
  3. """
  4. import json
  5. import sys
  6. from pathlib import Path
  7. def analyze_cache(trace_dir):
  8. """分析指定 trace 的缓存情况"""
  9. events_file = Path(trace_dir) / "events.jsonl"
  10. if not events_file.exists():
  11. print(f"错误: 找不到 {events_file}")
  12. return
  13. print("=" * 80)
  14. print("缓存命中情况详细分析")
  15. print("=" * 80)
  16. print()
  17. # 统计数据
  18. total_messages = 0
  19. assistant_messages = 0
  20. tool_messages = 0
  21. total_prompt_tokens = 0
  22. total_cache_creation = 0
  23. total_cache_read = 0
  24. cache_events = []
  25. with open(events_file) as f:
  26. for line in f:
  27. event = json.loads(line)
  28. if event.get("event") == "message_added":
  29. msg = event["message"]
  30. role = msg.get("role")
  31. total_messages += 1
  32. if role == "assistant":
  33. assistant_messages += 1
  34. seq = msg["sequence"]
  35. prompt = msg.get("prompt_tokens", 0)
  36. creation = msg.get("cache_creation_tokens", 0)
  37. read = msg.get("cache_read_tokens", 0)
  38. total_prompt_tokens += prompt
  39. total_cache_creation += creation
  40. total_cache_read += read
  41. cache_events.append({
  42. "seq": seq,
  43. "prompt": prompt,
  44. "creation": creation,
  45. "read": read,
  46. })
  47. elif role == "tool":
  48. tool_messages += 1
  49. # 打印统计
  50. print(f"总消息数: {total_messages}")
  51. print(f" - Assistant: {assistant_messages}")
  52. print(f" - Tool: {tool_messages}")
  53. print(f" - 其他: {total_messages - assistant_messages - tool_messages}")
  54. print()
  55. print(f"Token 统计:")
  56. print(f" - Total prompt tokens: {total_prompt_tokens:,}")
  57. print(f" - Cache creation: {total_cache_creation:,} ({total_cache_creation/total_prompt_tokens*100:.1f}%)")
  58. print(f" - Cache read: {total_cache_read:,} ({total_cache_read/total_prompt_tokens*100:.1f}%)")
  59. print()
  60. # 计算缓存命中率
  61. if total_prompt_tokens > 0:
  62. hit_rate = total_cache_read / total_prompt_tokens * 100
  63. print(f"缓存命中率: {hit_rate:.1f}%")
  64. print()
  65. # 详细的缓存事件
  66. print("=" * 80)
  67. print("详细缓存事件")
  68. print("=" * 80)
  69. print()
  70. print(f"{'Seq':>4} | {'Prompt Tokens':>14} | {'Cache Creation':>15} | {'Cache Read':>11} | {'Hit Rate':>9}")
  71. print("-" * 80)
  72. for event in cache_events:
  73. seq = event["seq"]
  74. prompt = event["prompt"]
  75. creation = event["creation"]
  76. read = event["read"]
  77. rate = f"{read/prompt*100:.1f}%" if prompt > 0 else "0%"
  78. # 标记特殊事件
  79. marker = ""
  80. if creation > 0:
  81. marker = " 🔵 创建"
  82. elif read == 0:
  83. marker = " ❌ 失效"
  84. elif read > 0:
  85. marker = " ✅ 命中"
  86. print(f"{seq:4d} | {prompt:14,d} | {creation:15,d} | {read:11,d} | {rate:>9s}{marker}")
  87. print()
  88. # 分析缓存失效的原因
  89. print("=" * 80)
  90. print("缓存失效分析")
  91. print("=" * 80)
  92. print()
  93. miss_count = sum(1 for e in cache_events if e["read"] == 0 and e["creation"] == 0)
  94. if miss_count > 0:
  95. print(f"发现 {miss_count} 次缓存失效")
  96. print("可能的原因:")
  97. print(" 1. Level 2 压缩导致消息序列改变")
  98. print(" 2. 缓存过期(5 分钟)")
  99. print(" 3. 消息内容发生变化")
  100. else:
  101. print("没有发现缓存失效")
  102. print()
  103. if __name__ == "__main__":
  104. if len(sys.argv) < 2:
  105. print("用法: python3 analyze.py <trace-directory>")
  106. print("示例: python3 analyze.py .trace/abc123...")
  107. sys.exit(1)
  108. trace_dir = sys.argv[1]
  109. analyze_cache(trace_dir)