在ARMv8-A架构中,统计性能分析(Statistical Profiling Extension, SPE)是一套硬件级性能监控机制,它通过周期性采样方式捕获处理器流水线的执行细节。与传统的基于事件的性能监控不同,SPE采用统计学方法,以较低的开销提供指令级的性能洞察。
SPE的核心组件包括:
典型的SPE工作流程如下图所示(文字描述):
SPEFilterByLatency函数实现了基于指令延迟的采样过滤:
c复制func SPEFilterByLatency(total_latency : integer) => boolean
begin
// 检查是否达到最小延迟阈值
let is_lat : boolean = (total_latency >= UInt(PMSLATFR_EL1().MINLAT));
// 如果满足条件,记录PMU事件
if is_lat then PMUEvent(PMU_EVENT_SAMPLE_FEED_LAT); end;
var is_rejected_latency : boolean = FALSE;
// 检查延迟过滤是否启用
if PMSFCR_EL1().FL == '1' then
if !IsZero(PMSLATFR_EL1().MINLAT) then
// 正常情况:根据阈值判断是否拒绝
is_rejected_latency = is_rejected_latency || !is_lat;
else
// MINLAT为0时的特殊处理
is_rejected_latency = ConstrainUnpredictableBool(Unpredictable_BADPMSFCR);
end;
end;
return is_rejected_latency;
end;
关键寄存器说明:
延迟计算原理:
SPEFilterByType函数实现了精细的操作类型过滤:
c复制func SPEFilterByType(opattr : SPEOpAttr) => boolean
begin
// 定义操作类型位域
let B : integer = 0; // 分支
let LD : integer = 1; // 加载
let ST : integer = 2; // 存储
let FP : integer = 3; // 浮点
let SIMD : integer = 4; // SIMD
// 初始化标志和控制位
var flags : bits(5) = Zeros{};
var ctrl : bits(5) = Zeros{};
// 处理GCS特殊情况
let is_gcs_ldst : boolean = (opattr.op_type == SPEOpType_Branch &&
opattr.ldst_type == SPELDSTType_GCS);
// 确定加载/存储类型
let is_load : boolean = (opattr.op_type IN {SPEOpType_Load, SPEOpType_LoadAtomic}
|| (is_gcs_ldst && opattr.procedure_return));
let is_store : boolean = (opattr.op_type IN {SPEOpType_Store, SPEOpType_LoadAtomic}
|| (is_gcs_ldst && opattr.branch_has_link));
// 设置标志位
flags[B] = (if opattr.op_type == SPEOpType_Branch then '1' else '0');
flags[LD] = (if is_load then '1' else '0');
flags[ST] = (if is_store then '1' else '0');
flags[FP] = (if opattr.is_floating_point then '1' else '0');
flags[SIMD] = (if opattr.is_simd then '1' else '0');
// 应用类型过滤掩码
if IsFeatureImplemented(FEAT_SPE_EFT) then
ctrl[4:3] = PMSFCR_EL1().TYPE[4:3];
mask[4:0] = PMSFCR_EL1().TYPEm;
end;
// 计算最终过滤结果
let is_op : boolean = ((IsZero(ctrl_or) || !IsZero(flags AND ctrl_or)) &&
((flags AND mask) == ctrl_and));
// 根据FT位决定是否拒绝
if PMSFCR_EL1().FT == '1' then
if IsFeatureImplemented(FEAT_SPE_EFT) || !IsZero(ctrl) then
is_rejected_type = !is_op;
else
is_rejected_type = ConstrainUnpredictableBool(Unpredictable_BADPMSFCR);
end;
end;
return is_rejected_type;
end;
操作类型分类:
配置技巧:
SPEToCollectSample函数控制采样触发逻辑:
c复制func SPEToCollectSample() => boolean
begin
if IsZero(PMSICR_EL1().COUNT) then
SPEResetSampleCounter();
else
PMSICR_EL1().COUNT = PMSICR_EL1().COUNT - 1;
if IsZero(PMSICR_EL1().COUNT) then
// 处理随机间隔模式
if PMSIRR_EL1().RND == '1' && IsFeatureImplemented(FEAT_SPE_ERnd) then
PMSICR_EL1().ECOUNT = SPEGetRandomInterval();
return IsZero(PMSICR_EL1().ECOUNT);
else
return TRUE;
end;
end;
end;
return FALSE;
end;
采样间隔配置:
SPEStartSample函数初始化采样过程:
c复制func SPEStartSample() => boolean
begin
if !StatisticalProfilingEnabled() then
return FALSE;
end;
PMUEvent(PMU_EVENT_SAMPLE_POP);
if !SPEToCollectSample() then
return FALSE;
end;
if SPESampleInFlight then
SPESampleCollision();
return FALSE;
end;
SPESampleInFlight = TRUE;
// 初始化关键计数器
SPEStartCounter(SPECounterPosTotalLatency);
SPEStartCounter(SPECounterPosIssueLatency);
// 记录PC值
SPESampleAddAddressPCVirtual();
// 设置默认操作属性
SPESampleOpOther(FALSE);
// 收集上下文信息
SPESampleAddContext();
// 记录时间戳
SPESampleAddTimeStamp();
return TRUE;
end;
数据收集要点:
对于同时包含加载和存储的操作(如原子指令),SPEMultiAccessSample提供智能选择:
c复制func SPEMultiAccessSample() => boolean
begin
let loads_pass_filter : boolean = PMSFCR_EL1().FT == '1' && PMSFCR_EL1().TYPE[LD] == '1';
let stores_pass_filter : boolean = PMSFCR_EL1().FT == '1' && PMSFCR_EL1().TYPE[ST] == '1';
if loads_pass_filter && !stores_pass_filter then
return TRUE; // 只采样加载
elsif !loads_pass_filter && stores_pass_filter then
return FALSE; // 只采样存储
else
return SPEGetRandomBoolean(); // 随机选择
end;
end;
应用场景:
SPEWriteToBuffer函数处理采样数据写入:
c复制func SPEWriteToBuffer()
begin
let align : integer{} = UInt(PMBIDR_EL1().Align);
let aligned : boolean = IsAlignedP2(PMBPTR_EL1().PTR, align);
for i = 0 to SPERecordSize - 1 do
if !SPEProfilingStopped() then
// 执行实际写入
let (memstatus, addrdesc) = DebugMemWrite(address, accdesc, aligned,
SPERecordData[[i]]);
// 错误处理
if IsFault(memstatus) then
DebugWriteExternalAbort(memstatus, addrdesc, start_vaddr);
end;
// 更新指针
PMBPTR_EL1() = PMBPTR_EL1() + 1;
end;
end;
end;
缓冲区优化建议:
针对SIMD和浮点运算的特殊处理:
c复制func SPESampleSIMDFPLoadStore(is_load : boolean, scalar : boolean)
begin
SPESampleOpAttr.ldst_type = SPELDSTType_SIMDFP;
SPESampleOpAttr.op_type = if is_load then SPEOpType_Load else SPEOpType_Store;
SPESampleOpAttr.is_simd = !scalar;
SPESampleOpAttr.is_floating_point = scalar;
end;
优化方向:
分支指令的特殊标记:
c复制flags[B] = (if opattr.op_type == SPEOpType_Branch then '1' else '0');
...
if flags[B] == '1' then PMUEvent(PMU_EVENT_SAMPLE_FEED_BR); end;
分析建议:
可能原因及解决方案:
调试步骤:
降低开销的方法: