import tkinter as tk
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
class HighPrecisionTimer:
"""高精度计时器基类"""
def __init__(self):
self.start_time = 0
self.total_elapsed = 0
self.running = False
self.interrupt_count = 0 # 中断计数器
self.core_usage = defaultdict(float) # 各核心使用时间
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.update_core_usage(elapsed) # 更新核心使用情况
self.running = False
def reset(self):
"""重置计时器"""
self.total_elapsed = 0
self.running = False
self.interrupt_count = 0
self.core_usage.clear()
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 update_core_usage(self, elapsed):
"""更新核心使用情况"""
# 此处为简化实现,实际项目中应使用系统API获取各核心使用数据
if platform.system() == 'Windows':
# 模拟多核使用情况
for core in range(os.cpu_count()):
self.core_usage[core] += elapsed * (0.3 + 0.6 * np.random.random())
else:
# Linux系统可读取/proc/stat获取实际数据
self.core_usage[0] = elapsed # 默认单核心
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("800x600")
root.resizable(True, True)
# 创建两种计时器实例
self.performance_timer = PerformanceCounterTimer()
self.cpu_cycle_timer = CPUCycleTimer()
# 当前选中的计时方案
self.current_timer = self.performance_timer
self.interrupt_monitor_running = False
# 创建UI
self.create_widgets()
# 启动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)
# 统计按钮
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))
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))
self.cpu_time_label.pack(side=tk.LEFT)
# 时间分解分析
analysis_frame = tk.LabelFrame(display_frame, text="时间分解分析", padx=10, pady=10)
analysis_frame.pack(fill=tk.X, pady=5)
# CPU利用率
util_frame = tk.Frame(analysis_frame)
util_frame.pack(fill=tk.X, pady=2)
tk.Label(util_frame, text="CPU利用率:", width=15).pack(side=tk.LEFT)
self.util_label = tk.Label(util_frame, text="0.0%")
self.util_label.pack(side=tk.LEFT)
# 系统等待时间
wait_frame = tk.Frame(analysis_frame)
wait_frame.pack(fill=tk.X, pady=2)
tk.Label(wait_frame, text="系统等待时间:", width=15).pack(side=tk.LEFT)
self.wait_label = tk.Label(wait_frame, text="0.0 ms")
self.wait_label.pack(side=tk.LEFT)
# 能耗估算
energy_frame = tk.Frame(analysis_frame)
energy_frame.pack(fill=tk.X, pady=2)
tk.Label(energy_frame, text="能耗估算:", width=15).pack(side=tk.LEFT)
self.energy_label = tk.Label(energy_frame, text="0.0 J")
self.energy_label.pack(side=tk.LEFT)
# 多核热力图
heatmap_frame = tk.LabelFrame(display_frame, text="多核利用率热力图", padx=10, pady=10)
heatmap_frame.pack(fill=tk.BOTH, expand=True, pady=5)
# 创建热力图
self.figure, self.ax = plt.subplots(figsize=(6, 3))
self.canvas = FigureCanvasTkAgg(self.figure, heatmap_frame)
self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
self.update_heatmap() # 初始化热力图
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="开始")
else:
self.performance_timer.start()
self.cpu_cycle_timer.start()
self.start_btn.config(text="停止")
def reset(self):
"""重置计时器"""
self.performance_timer.reset()
self.cpu_cycle_timer.reset()
self.physical_label.config(text="00:00:00.000")
self.cpu_time_label.config(text="00:00:00.000")
self.util_label.config(text="0.0%")
self.wait_label.config(text="0.0 ms")
self.energy_label.config(text="0.0 J")
self.interrupt_label.config(text="中断次数: 0")
self.start_btn.config(text="开始")
self.update_heatmap() # 重置热力图
def update_heatmap(self):
"""更新多核热力图"""
self.ax.clear()
cores = sorted(self.cpu_cycle_timer.core_usage.keys())
if not cores:
cores = list(range(os.cpu_count()))
util = [0] * len(cores)
else:
total_time = max(1, self.cpu_cycle_timer.total_elapsed)
util = [self.cpu_cycle_timer.core_usage[core] / total_time * 100 for core in cores]
# 创建热力图数据
data = np.array(util).reshape(1, -1)
im = self.ax.imshow(data, cmap='viridis', aspect='auto', vmin=0, vmax=100)
# 添加标注
for i in range(len(cores)):
self.ax.text(i, 0, f'{util[i]:.1f}%', ha='center', va='center', color='w')
self.ax.set_title(f'CPU核心利用率 (%)')
self.ax.set_xticks(range(len(cores)))
self.ax.set_xticklabels([f'Core {core}' for core in cores])
self.ax.get_yaxis().set_visible(False)
self.figure.colorbar(im, ax=self.ax)
self.canvas.draw()
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):
"""生成详细分析报告"""
import csv
import os
import platform
import sys
from datetime import datetime
from tkinter import messagebox
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(["核心ID", "使用时间(毫秒)", "占比"])
# 计算核心使用占比
cores = sorted(self.cpu_cycle_timer.core_usage.keys())
total_cpu_time = max(1, cpu_time) # 防止除零
for core in cores:
core_time = self.cpu_cycle_timer.core_usage.get(core, 0)
percentage = (core_time / total_cpu_time) * 100
writer.writerow([f"Core {core}", f"{core_time:.3f}", f"{percentage:.2f}%"])
# 添加数学公式注解
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=功耗模型)"])
# 显示成功消息
messagebox.showinfo("报告生成", f"分析报告已保存至:\n{os.path.abspath(filename)}")
if __name__ == "__main__":
root = tk.Tk()
app = TimerApp(root)
root.mainloop()
[Running] python -u "e:\system\Desktop\项目所需文件\工具\计时器工具\timer copy.py"
e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py:352: UserWarning: Glyph 26680 (\N{CJK UNIFIED IDEOGRAPH-6838}) missing from font(s) DejaVu Sans.
self.canvas.draw()
e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py:352: UserWarning: Glyph 24515 (\N{CJK UNIFIED IDEOGRAPH-5FC3}) missing from font(s) DejaVu Sans.
self.canvas.draw()
e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py:352: UserWarning: Glyph 21033 (\N{CJK UNIFIED IDEOGRAPH-5229}) missing from font(s) DejaVu Sans.
self.canvas.draw()
e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py:352: UserWarning: Glyph 29992 (\N{CJK UNIFIED IDEOGRAPH-7528}) missing from font(s) DejaVu Sans.
self.canvas.draw()
e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py:352: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from font(s) DejaVu Sans.
self.canvas.draw()
Traceback (most recent call last):
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py", line 459, in <module>
app = TimerApp(root)
^^^^^^^^^^^^^^
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u8ba1\u65f6��H��\timer copy.py", line 170, in __init__
self.update_display()
^^^^^^^^^^^^^^^^^^^
AttributeError: 'TimerApp' object has no attribute 'update_display'