@@ -161,4 +161,92 @@ TEST_F(PerfSpeEventsTestHelper, SpeBranchesWithBrstack) {
161161 parseAndCheckBrstackEvents (1234 , ExpectedSamples);
162162}
163163
164+ TEST_F (PerfSpeEventsTestHelper, SpeBranchesWithBrstackAndPbt) {
165+ // Check perf input with SPE branch events as brstack format by
166+ // combining with the previous branch target address (named as PBT).
167+ // Example collection command:
168+ // ```
169+ // perf record -e 'arm_spe_0/branch_filter=1/u' -- BINARY
170+ // ```
171+ // How Bolt extracts the branch events:
172+ // ```
173+ // perf script -F pid,brstack --itrace=bl
174+ // ```
175+
176+ opts::ArmSPE = true ;
177+ opts::ReadPerfEvents =
178+ // "<PID> <SRC>/<DEST>/PN/-/-/10/COND/- <NULL>/<PBT>/-/-/-/0//-\n"
179+ " 4567 0xa002/0xa003/PN/-/-/10/COND/- 0x0/0xa001/-/-/-/0//-\n "
180+ " 4567 0xb002/0xb003/P/-/-/4/RET/- 0x0/0xb001/-/-/-/0//-\n "
181+ " 4567 0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n "
182+ " 4567 0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n "
183+ " 4567 0xe005/0xe009/P/-/-/14/RET/- 0x0/0xe001/-/-/-/0//-\n "
184+ " 4567 0xd456/0xd789/M/-/-/7/RET/- 0x0/0xd123/-/-/-/0//-\n "
185+ " 4567 0xf002/0xf003/MN/-/-/8/COND/- 0x0/0xf001/-/-/-/0//-\n "
186+ " 4567 0xc456/0xc789/P/-/-/13/-/- 0x0/0xc123/-/-/-/0//-\n " ;
187+
188+ // ExpectedSamples contains the aggregated information about
189+ // a branch {{From, To, TraceTo}, {TakenCount, MispredCount}}.
190+ // Where
191+ // - From: is the source address of the sampled branch operation.
192+ // - To: is the target address of the sampled branch operation.
193+ // - TraceTo could be either
194+ // - A 'Type = Trace::BR_ONLY', which means the trace only contains branch
195+ // data.
196+ // - Or an address, when the trace contains information about the previous
197+ // branch.
198+ //
199+ // When FEAT_SPE_PBT is present, Arm SPE emits two records per sample:
200+ // - the current branch (Spe.From/Spe.To), and
201+ // - the previous taken branch target (PBT) (PBT.From, PBT.To).
202+ //
203+ // Together they behave like a depth-1 branch stack where:
204+ // - the PBT entry is always taken
205+ // - the current branch entry may represent a taken branch or a fall-through
206+ // - the destination (Spe.To) is the architecturally executed target
207+ //
208+ // There can be fall-throughs to be inferred between the PBT entry and
209+ // the current branch (Spe.From), but there cannot be between current
210+ // branch's (Spe.From/Spe.To).
211+ //
212+ // PBT records only the target address (PBT.To), meaning we have no
213+ // information as the branch source (PBT.From=0x0), branch type, and the
214+ // prediction bit.
215+ //
216+ // Consider the trace pair:
217+ // {{Spe.From, Spe.To, Type}, {TK, MP}},
218+ // {{PBT.From, PBT.To, TraceTo}, {TK, MP}}
219+ // {{0xd456, 0xd789, Trace::BR_ONLY}, {2, 2}}, {{0x0, 0xd123, 0xd456}, {2, 0}}
220+ //
221+ // The first entry is the Spe record, which represents a trace from 0xd456
222+ // (Spe.From) to 0xd789 (Spe.To). Type = Trace::BR_ONLY, as Bolt processes the
223+ // current branch event first. At this point we have no information about the
224+ // previous trace (PBT). This entry has a TakenCount = 2, as we have two
225+ // samples for (0xd456, 0xd789) in our input. It also has MispredsCount = 2,
226+ // as 'M' misprediction flag appears in both cases.
227+ //
228+ // The second entry is the PBT record. TakenCount = 2 because the
229+ // (PBT.From = 0x0, PBT.To = 0xd123) branch target appears twice in the input,
230+ // and MispredsCount = 0 because prediction data is absent. There is no branch
231+ // source information, so the PBT.From field is zero (0x0). TraceTo = 0xd456
232+ // connect the flow from the previous taken branch at 0xd123 (PBT.To) to the
233+ // current source branch at 0xd456 (Spe.From), which then continues to 0xd789
234+ // (Spe.To).
235+ std::vector<std::pair<Trace, TakenBranchInfo>> ExpectedSamples = {
236+ {{0xa002 , 0xa003 , Trace::BR_ONLY}, {1 , 0 }},
237+ {{0x0 , 0xa001 , 0xa002 }, {1 , 0 }},
238+ {{0xb002 , 0xb003 , Trace::BR_ONLY}, {1 , 0 }},
239+ {{0x0 , 0xb001 , 0xb002 }, {1 , 0 }},
240+ {{0xc456 , 0xc789 , Trace::BR_ONLY}, {2 , 0 }},
241+ {{0x0 , 0xc123 , 0xc456 }, {2 , 0 }},
242+ {{0xd456 , 0xd789 , Trace::BR_ONLY}, {2 , 2 }},
243+ {{0x0 , 0xd123 , 0xd456 }, {2 , 0 }},
244+ {{0xe005 , 0xe009 , Trace::BR_ONLY}, {1 , 0 }},
245+ {{0x0 , 0xe001 , 0xe005 }, {1 , 0 }},
246+ {{0xf002 , 0xf003 , Trace::BR_ONLY}, {1 , 1 }},
247+ {{0x0 , 0xf001 , 0xf002 }, {1 , 0 }}};
248+
249+ parseAndCheckBrstackEvents (4567 , ExpectedSamples);
250+ }
251+
164252#endif
0 commit comments