import tkinter as tk
from tkinter import ttk
import time
import sys
import os
import platform
import ctypes
import csv
import threading
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from ctypes import windll, wintypes
from collections import defaultdict
from datetime import datetime
# 解决中文警告问题
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
class HighPrecisionTimer:
"""高精度计时器基类"""
def __init__(self):
self.start_time = 0
self.total_elapsed = 0
self.running = False
self.interrupt_count = 0 # 中断计数器
self.records = [] # 记录每次计时结果
def start(self):
"""开始计时"""
if not self.running:
self.start_time = self.current_time()
self.running = True
def stop(self):
"""停止计时"""
if self.running:
elapsed = self.current_time() - self.start_time
self.total_elapsed += elapsed
self.running = False
def reset(self):
"""重置计时器"""
self.total_elapsed = 0
self.running = False
self.interrupt_count = 0
self.records = []
def current_elapsed(self):
"""获取当前已过时间(毫秒)"""
if self.running:
return self.total_elapsed + (self.current_time() - self.start_time)
return self.total_elapsed
def current_time(self):
"""抽象方法,由子类实现具体计时方案"""
raise NotImplementedError("Subclasses must implement current_time()")
def record_current(self):
"""记录当前计时值"""
if self.running:
elapsed = self.current_elapsed()
self.records.append({
"timestamp": datetime.now(),
"elapsed": elapsed,
"label": f"记录 {len(self.records)+1}"
})
return elapsed
return 0
def get_cpu_utilization(self, physical_time):
if physical_time > 0:
return min(100, max(0, (self.current_elapsed() / physical_time) * 100))
return 0
def record_interrupt(self):
"""记录中断事件"""
self.interrupt_count += 1
class PerformanceCounterTimer(HighPrecisionTimer):
"""基于性能计数器的物理计时方案"""
def __init__(self):
super().__init__()
# 获取性能计数器频率
if platform.system() == 'Windows':
self.frequency = ctypes.c_int64()
windll.kernel32.QueryPerformanceFrequency(ctypes.byref(self.frequency))
self.frequency = self.frequency.value
else:
# Linux/macOS使用time.perf_counter
self.frequency = 1e9 # 1秒 = 1e9纳秒
def current_time(self):
"""获取当前性能计数器时间(毫秒)"""
if platform.system() == 'Windows':
counter = ctypes.c_int64()
windll.kernel32.QueryPerformanceCounter(ctypes.byref(counter))
return (counter.value * 1000) / self.frequency # 转换为毫秒
else:
# 跨平台方案
return time.perf_counter() * 1000
class CPUCycleTimer(HighPrecisionTimer):
"""基于CPU周期的计时方案"""
def __init__(self):
super().__init__()
# 获取CPU频率
self.frequency = self.get_cpu_frequency()
self.power_model = self.create_power_model() # 创建功耗模型
def get_cpu_frequency(self):
"""尝试获取CPU频率"""
try:
if platform.system() == 'Windows':
# Windows获取CPU频率
import winreg
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
value, _ = winreg.QueryValueEx(key, "~MHz")
winreg.CloseKey(key)
return value * 1e6 # MHz转换为Hz
else:
# Linux/macOS获取CPU频率
with open('/proc/cpuinfo') as f:
for line in f:
if 'cpu MHz' in line:
return float(line.split(':')[1].strip()) * 1e6
# 默认值
return 3.5e9 # 3.5 GHz
except:
return 3.5e9 # 3.5 GHz
def current_time(self):
"""获取当前CPU周期计数并转换为毫秒"""
if platform.system() == 'Windows':
return time.perf_counter_ns() / 1_000_000 # 返回毫秒级精确时间
else:
# 在实际应用中应使用RDTSC指令
return time.process_time() * 1000
def create_power_model(self):
# 简化的线性模型: P = a * utilization + b
return lambda u: 15 + 85 * (u/100) # 基础功耗15W + 动态功耗
def estimate_energy(self, physical_time):
utilization = self.get_cpu_utilization(physical_time)
power = self.power_model(utilization) # 当前功耗(W)
time_seconds = physical_time / 1000 # 转换为秒
return power * time_seconds # 能耗(J)
class TimerApp:
"""计时器应用GUI"""
def __init__(self, root):
self.root = root
root.title("高精度计时器 - 专业版")
root.geometry("900x700")
root.resizable(True, True)
# 创建两种计时器实例
self.performance_timer = PerformanceCounterTimer()
self.cpu_cycle_timer = CPUCycleTimer()
# 当前选中的计时方案
self.current_timer = self.performance_timer
self.interrupt_monitor_running = False
# 计时记录列表
self.time_records = []
# 创建UI
self.create_widgets()
# 性能优化计数器
self.update_count = 0
# 启动UI更新循环
self.update_display()
# 启动中断监控线程
self.start_interrupt_monitor()
def create_widgets(self):
"""创建界面组件"""
# 主框架
main_frame = tk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 左侧控制面板
control_frame = tk.Frame(main_frame)
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
# 方案选择
mode_frame = tk.LabelFrame(control_frame, text="计时方案", padx=10, pady=10)
mode_frame.pack(fill=tk.X, pady=5)
self.mode_var = tk.StringVar(value="performance")
modes = [("性能计数器 (物理时间)", "performance"),
("CPU周期 (CPU时间)", "cpu")]
for text, mode in modes:
rb = tk.Radiobutton(mode_frame, text=text, variable=self.mode_var,
value=mode, command=self.switch_mode)
rb.pack(anchor=tk.W, padx=5, pady=2)
# 控制按钮
btn_frame = tk.Frame(control_frame)
btn_frame.pack(fill=tk.X, pady=10)
self.start_btn = tk.Button(btn_frame, text="开始", width=12,
command=self.start_stop)
self.start_btn.pack(side=tk.LEFT, padx=5)
reset_btn = tk.Button(btn_frame, text="重置", width=12,
command=self.reset)
reset_btn.pack(side=tk.LEFT, padx=5)
# 记录按钮
self.record_btn = tk.Button(btn_frame, text="记录本次", width=12,
command=self.record_current, state=tk.DISABLED)
self.record_btn.pack(side=tk.LEFT, padx=5)
# 统计按钮
stats_btn = tk.Button(btn_frame, text="生成报告", width=12,
command=self.generate_report)
stats_btn.pack(side=tk.LEFT, padx=5)
# CPU信息
info_frame = tk.LabelFrame(control_frame, text="系统信息", padx=10, pady=10)
info_frame.pack(fill=tk.X, pady=5)
cpu_freq = self.cpu_cycle_timer.frequency
freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz"
self.cpu_label = tk.Label(info_frame, text=freq_text, justify=tk.LEFT)
self.cpu_label.pack(anchor=tk.W)
cores_text = f"CPU核心数: {os.cpu_count()}"
tk.Label(info_frame, text=cores_text, justify=tk.LEFT).pack(anchor=tk.W)
# 中断统计
interrupt_frame = tk.LabelFrame(control_frame, text="中断统计", padx=10, pady=10)
interrupt_frame.pack(fill=tk.X, pady=5)
self.interrupt_label = tk.Label(interrupt_frame, text="中断次数: 0")
self.interrupt_label.pack(anchor=tk.W)
# 右侧数据显示
display_frame = tk.Frame(main_frame)
display_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
# 双模式时间显示
time_frame = tk.LabelFrame(display_frame, text="时间显示", padx=10, pady=10)
time_frame.pack(fill=tk.X, pady=5)
# 物理时间显示 - 添加颜色(蓝色)
physical_frame = tk.Frame(time_frame)
physical_frame.pack(fill=tk.X, pady=5)
tk.Label(physical_frame, text="物理时间:", width=10).pack(side=tk.LEFT)
self.physical_label = tk.Label(physical_frame, text="00:00:00.000",
font=("Consolas", 12), fg="blue")
self.physical_label.pack(side=tk.LEFT)
# CPU时间显示 - 添加颜色(红色)
cpu_frame = tk.Frame(time_frame)
cpu_frame.pack(fill=tk.X, pady=5)
tk.Label(cpu_frame, text="CPU时间:", width=10).pack(side=tk.LEFT)
self.cpu_time_label = tk.Label(cpu_frame, text="00:00:00.000",
font=("Consolas", 12), fg="red")
self.cpu_time_label.pack(side=tk.LEFT)
# 计时记录框架
records_frame = tk.LabelFrame(display_frame, text="计时记录", padx=10, pady=10)
records_frame.pack(fill=tk.X, pady=5)
# 创建记录表格
columns = ("序号", "标签", "物理时间", "CPU时间", "差值")
self.records_tree = ttk.Treeview(records_frame, columns=columns, show="headings", height=5)
# 设置列标题
for col in columns:
self.records_tree.heading(col, text=col)
self.records_tree.column(col, width=80, anchor=tk.CENTER)
# 设置列宽
self.records_tree.column("标签", width=120)
# 添加滚动条
scrollbar = ttk.Scrollbar(records_frame, orient="vertical", command=self.records_tree.yview)
self.records_tree.configure(yscrollcommand=scrollbar.set)
self.records_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 统计图表
chart_frame = tk.LabelFrame(display_frame, text="计时统计图", padx=10, pady=10)
chart_frame.pack(fill=tk.BOTH, expand=True, pady=5)
# 创建图表
self.figure, self.ax = plt.subplots(figsize=(8, 4))
self.canvas = FigureCanvasTkAgg(self.figure, chart_frame)
self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
# 初始化图表
self.update_chart()
def switch_mode(self):
"""切换计时方案"""
selected = self.mode_var.get()
if selected == "performance":
self.current_timer = self.performance_timer
else:
self.current_timer = self.cpu_cycle_timer
# 更新CPU频率显示
cpu_freq = self.cpu_cycle_timer.frequency
freq_text = f"CPU频率: {cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"CPU频率: {cpu_freq/1e6:.0f} MHz"
self.cpu_label.config(text=freq_text)
def start_stop(self):
"""开始/停止计时 - 只操作当前选中的计时器"""
if self.current_timer.running:
self.current_timer.stop()
self.start_btn.config(text="开始")
self.record_btn.config(state=tk.DISABLED)
else:
# 只启动当前选中的计时器
self.current_timer.start()
self.start_btn.config(text="停止")
self.record_btn.config(state=tk.NORMAL)
def record_current(self):
"""记录当前计时值"""
if self.current_timer.running:
# 获取当前两种计时器的值
physical_ms = self.performance_timer.current_elapsed()
cpu_ms = self.cpu_cycle_timer.current_elapsed()
# 创建记录
record = {
"id": len(self.time_records) + 1,
"label": f"记录 {len(self.time_records) + 1}",
"physical": physical_ms,
"cpu": cpu_ms,
"difference": abs(physical_ms - cpu_ms)
}
# 添加到记录列表
self.time_records.append(record)
# 更新表格
self.update_records_table()
# 更新图表
self.update_chart()
def update_records_table(self):
"""更新计时记录表格"""
# 清空现有数据
for item in self.records_tree.get_children():
self.records_tree.delete(item)
# 添加新记录
for record in self.time_records:
self.records_tree.insert("", "end", values=(
record["id"],
record["label"],
f"{record['physical']:.1f} ms",
f"{record['cpu']:.1f} ms",
f"{record['difference']:.1f} ms"
))
def update_chart(self):
"""更新计时统计图表"""
self.ax.clear()
if self.time_records:
# 准备数据
labels = [r["label"] for r in self.time_records]
physical_times = [r["physical"] for r in self.time_records]
cpu_times = [r["cpu"] for r in self.time_records]
x = np.arange(len(labels))
width = 0.35
# 绘制柱状图
rects1 = self.ax.bar(x - width/2, physical_times, width, label='物理时间', color='blue')
rects2 = self.ax.bar(x + width/2, cpu_times, width, label='CPU时间', color='red')
# 添加标签、标题等
self.ax.set_ylabel('时间 (ms)')
self.ax.set_title('计时记录对比')
self.ax.set_xticks(x)
self.ax.set_xticklabels(labels)
self.ax.legend()
# 添加数值标签
self.ax.bar_label(rects1, padding=3, fmt='%.1f')
self.ax.bar_label(rects2, padding=3, fmt='%.1f')
# 调整布局
self.figure.tight_layout()
else:
# 没有记录时显示提示信息
self.ax.text(0.5, 0.5, '暂无计时记录',
horizontalalignment='center',
verticalalignment='center',
transform=self.ax.transAxes,
fontsize=14)
self.canvas.draw()
def reset(self):
"""重置当前计时器"""
self.current_timer.reset()
self.start_btn.config(text="开始")
self.record_btn.config(state=tk.DISABLED)
# 更新显示
self.update_display()
def start_interrupt_monitor(self):
"""启动中断监控线程"""
if not self.interrupt_monitor_running:
self.interrupt_monitor_running = True
threading.Thread(target=self.monitor_interrupts, daemon=True).start()
def monitor_interrupts(self):
"""模拟中断监控"""
while self.interrupt_monitor_running:
time.sleep(0.1)
# 在实际应用中,这里应读取系统中断计数器
if self.current_timer.running:
# 模拟随机中断
if np.random.random() < 0.02: # 2%概率发生中断
self.performance_timer.record_interrupt()
self.cpu_cycle_timer.record_interrupt()
self.root.after(0, self.update_interrupt_count)
def update_interrupt_count(self):
"""更新中断计数显示"""
count = self.performance_timer.interrupt_count
self.interrupt_label.config(text=f"中断次数: {count}")
def generate_report(self):
"""生成详细分析报告并保存为CSV文件"""
filename = f"timer_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
# 写入报告头部信息
writer.writerow(["高精度计时器分析报告"])
writer.writerow(["生成时间", datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
writer.writerow([])
# 写入系统信息
writer.writerow(["系统信息"])
writer.writerow(["操作系统", platform.platform()])
writer.writerow(["CPU核心数", os.cpu_count()])
cpu_freq = self.cpu_cycle_timer.frequency
freq_text = f"{cpu_freq/1e9:.2f} GHz" if cpu_freq >= 1e9 else f"{cpu_freq/1e6:.0f} MHz"
writer.writerow(["CPU频率", freq_text])
writer.writerow(["Python版本", sys.version])
writer.writerow([])
# 格式化时间函数
def format_ms(ms):
hours, rem = divmod(ms, 3600000)
minutes, rem = divmod(rem, 60000)
seconds, milliseconds = divmod(rem, 1000)
return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}"
# 写入时间指标
physical_time = self.performance_timer.total_elapsed
cpu_time = self.cpu_cycle_timer.total_elapsed
wait_time = max(0, physical_time - cpu_time) # 系统等待时间
writer.writerow(["时间指标"])
writer.writerow(["度量项", "数值(毫秒)", "格式化时间"])
writer.writerow(["物理时间", f"{physical_time:.3f}", format_ms(physical_time)])
writer.writerow(["CPU时间", f"{cpu_time:.3f}", format_ms(cpu_time)])
writer.writerow(["系统等待时间", f"{wait_time:.3f}", format_ms(wait_time)])
writer.writerow([])
# 写入性能指标
utilization = self.cpu_cycle_timer.get_cpu_utilization(physical_time) if physical_time > 0 else 0
energy = self.cpu_cycle_timer.estimate_energy(physical_time) if physical_time > 0 else 0
writer.writerow(["性能指标"])
writer.writerow(["CPU利用率", f"{utilization:.2f}%"])
writer.writerow(["系统中断次数", self.performance_timer.interrupt_count])
writer.writerow(["估算能耗", f"{energy:.2f} J"])
writer.writerow([])
# 写入计时记录
writer.writerow(["计时记录"])
writer.writerow(["序号", "标签", "物理时间(ms)", "CPU时间(ms)", "差值(ms)"])
for i, record in enumerate(self.time_records, 1):
writer.writerow([
i,
record["label"],
f"{record['physical']:.3f}",
f"{record['cpu']:.3f}",
f"{abs(record['physical'] - record['cpu']):.3f}"
])
writer.writerow([])
# 添加数学公式注解
writer.writerow(["计算公式注解"])
writer.writerow(["CPU利用率", r"$\eta = \frac{T_{cpu}}{T_{physical}} \times 100\%$"])
writer.writerow(["系统等待时间", r"$\Delta t = T_{physical} - T_{cpu}$"])
writer.writerow(["能耗估算", r"$E = \int_{0}^{T} P(u(t)) \, dt$", "(P=功耗模型)"])
# 显示成功消息
tk.messagebox.showinfo("报告生成", f"分析报告已保存至:\n{os.path.abspath(filename)}")
def update_display(self):
"""更新UI显示"""
# 获取两个计时器的当前时间
physical_ms = self.performance_timer.current_elapsed()
cpu_ms = self.cpu_cycle_timer.current_elapsed()
# 格式化时间
physical_str = self.ms_to_time_str(physical_ms)
cpu_str = self.ms_to_time_str(cpu_ms)
# 始终更新两个时间显示
self.physical_label.config(text=physical_str)
self.cpu_time_label.config(text=cpu_str)
# 计算性能指标
if physical_ms > 0:
utilization = min(100, max(0, (cpu_ms / physical_ms) * 100))
wait_time = max(0, physical_ms - cpu_ms)
energy = self.cpu_cycle_timer.estimate_energy(physical_ms)
else:
utilization = 0
wait_time = 0
energy = 0
# 更新性能指标显示
self.util_label.config(text=f"{utilization:.1f}%")
self.wait_label.config(text=f"{wait_time:.1f} ms")
self.energy_label.config(text=f"{energy:.1f} J")
# 每100毫秒更新一次显示
self.root.after(100, self.update_display)
def ms_to_time_str(self, ms):
"""将毫秒数格式化为 HH:MM:SS.ms 字符串"""
ms = max(0, ms) # 确保非负
seconds, milliseconds = divmod(ms, 1000)
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}.{int(milliseconds):03d}" if ms > 0 else "00:00:00.000"
def __del__(self):
"""清理资源"""
self.interrupt_monitor_running = False
if __name__ == "__main__":
root = tk.Tk()
app = TimerApp(root)
try:
root.mainloop()
finally:
# 确保线程安全退出
app.interrupt_monitor_running = False
[Running] python -u "e:\system\Desktop\项目所需文件\工具\计时器工具\timer copy 2.py"
Traceback (most recent call last):
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 567, in <module>
app = TimerApp(root)
^^^^^^^^^^^^^^
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 182, in __init__
self.update_display()
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy 2.py", line 546, in update_display
self.util_label.config(text=f"{utilization:.1f}%")
^^^^^^^^^^^^^^^
AttributeError: 'TimerApp' object has no attribute 'util_label'
最新发布