2025-11-26 14:35:58 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
2025-11-27 16:46:51 +08:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2025-11-26 14:35:58 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace TracyProfiler
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Tracy 性能分析器的 Unity 封装
|
|
|
|
|
|
/// 提供简单易用的 C# API 来使用 Tracy 性能分析功能
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static class Tracy
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_IOS && !UNITY_EDITOR
|
|
|
|
|
|
private const string DLL_NAME = "__Internal";
|
|
|
|
|
|
#else
|
|
|
|
|
|
private const string DLL_NAME = "UnityTracyPlugin";
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#region Native Methods
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
|
private static extern void TracyInit();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
|
private static extern void TracyShutdown();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
|
private static extern void TracyFrameMark();
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
|
private static extern void TracyPlotValue(string name, double value);
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
2025-11-27 10:15:03 +08:00
|
|
|
|
private static extern void TracySendMessage(string message);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
|
private static extern void TracySetThreadName(string name);
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
2025-11-27 16:46:51 +08:00
|
|
|
|
private static extern void TracyZoneScopedBegin(string name, string function = "", string file = "",
|
|
|
|
|
|
int line = 0);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
|
2025-11-27 16:46:51 +08:00
|
|
|
|
private static extern void TracyZoneScopedEnd(string name);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
private static bool s_initialized = false;
|
|
|
|
|
|
private static bool s_enabled = true;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Tracy 是否已启用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static bool Enabled
|
|
|
|
|
|
{
|
|
|
|
|
|
get => s_enabled;
|
|
|
|
|
|
set => s_enabled = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Tracy 是否已初始化
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static bool IsInitialized => s_initialized;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化 Tracy
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (s_initialized) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-11-27 16:46:51 +08:00
|
|
|
|
#if TRACY_ENABLE
|
2025-11-26 14:35:58 +08:00
|
|
|
|
TracyInit();
|
|
|
|
|
|
s_initialized = true;
|
|
|
|
|
|
Debug.Log("[Tracy] 性能分析器已初始化");
|
|
|
|
|
|
#else
|
|
|
|
|
|
Debug.Log("[Tracy] 性能分析器已禁用(编译时未定义 TRACY_ENABLE)");
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (DllNotFoundException e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"[Tracy] 未找到 Tracy Plugin DLL: {e.Message}");
|
|
|
|
|
|
s_enabled = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[Tracy] 初始化失败: {e.Message}");
|
|
|
|
|
|
s_enabled = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 关闭 Tracy
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void Shutdown()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!s_initialized) return;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
TracyShutdown();
|
|
|
|
|
|
s_initialized = false;
|
|
|
|
|
|
Debug.Log("[Tracy] 性能分析器已关闭");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"[Tracy] 关闭失败: {e.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 标记帧边界(通常在每帧末尾调用)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void MarkFrame()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!s_initialized || !s_enabled) return;
|
|
|
|
|
|
TracyFrameMark();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绘制数值(用于实时监控变量)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void Plot(string name, double value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!s_initialized || !s_enabled) return;
|
|
|
|
|
|
TracyPlotValue(name, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绘制整数值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void Plot(string name, int value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Plot(name, (double)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绘制浮点数值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void Plot(string name, float value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Plot(name, (double)value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 发送消息到 Tracy
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void Message(string message)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!s_initialized || !s_enabled) return;
|
2025-11-27 10:15:03 +08:00
|
|
|
|
TracySendMessage(message);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置当前线程名称
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[System.Diagnostics.Conditional("TRACY_ENABLE")]
|
|
|
|
|
|
public static void SetThreadName(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!s_initialized || !s_enabled) return;
|
|
|
|
|
|
TracySetThreadName(name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Tracy Zone 的作用域包装器
|
|
|
|
|
|
/// 使用 using 语句自动管理生命周期
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public struct ZoneScope : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
private bool isValid;
|
|
|
|
|
|
private string zoneName;
|
|
|
|
|
|
|
2025-11-27 16:46:51 +08:00
|
|
|
|
public ZoneScope(string name, string function = "", string file = "", int line = 0)
|
2025-11-26 14:35:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
zoneName = name;
|
|
|
|
|
|
isValid = s_initialized && s_enabled;
|
|
|
|
|
|
#if TRACY_ENABLE
|
|
|
|
|
|
if (isValid)
|
|
|
|
|
|
{
|
2025-11-27 16:46:51 +08:00
|
|
|
|
TracyZoneScopedBegin(name, function, file, line);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if TRACY_ENABLE
|
|
|
|
|
|
if (isValid && s_initialized && s_enabled)
|
|
|
|
|
|
{
|
2025-11-27 16:46:51 +08:00
|
|
|
|
TracyZoneScopedEnd(zoneName);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建一个 Tracy Zone(性能追踪区域)
|
|
|
|
|
|
/// 使用 using 语句确保自动结束
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// using (Tracy.Zone("MyFunction"))
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// // 要追踪的代码
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// </example>
|
2025-11-27 16:46:51 +08:00
|
|
|
|
public static ZoneScope Zone(string name,
|
|
|
|
|
|
[CallerMemberName] string function = "",
|
|
|
|
|
|
[CallerFilePath] string file = "",
|
|
|
|
|
|
[CallerLineNumber] int line = 0)
|
2025-11-26 14:35:58 +08:00
|
|
|
|
{
|
2025-11-27 16:46:51 +08:00
|
|
|
|
return new ZoneScope(name, function, file, line);
|
2025-11-26 14:35:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Tracy Zone 的属性标记版本
|
|
|
|
|
|
/// 可以标记在方法上,自动追踪整个方法
|
|
|
|
|
|
/// 注意:需要配合 AOP 或代码生成工具使用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
|
|
|
|
|
public class TracyZoneAttribute : Attribute
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public TracyZoneAttribute(string name = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = name;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|