@@ -12,6 +12,16 @@ enum {
12
12
LBR_FORMAT_LIP = 0x01 ,
13
13
LBR_FORMAT_EIP = 0x02 ,
14
14
LBR_FORMAT_EIP_FLAGS = 0x03 ,
15
+ LBR_FORMAT_EIP_FLAGS2 = 0x04 ,
16
+ LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_EIP_FLAGS2 ,
17
+ };
18
+
19
+ static enum {
20
+ LBR_EIP_FLAGS = 1 ,
21
+ LBR_TSX = 2 ,
22
+ } lbr_desc [LBR_FORMAT_MAX_KNOWN + 1 ] = {
23
+ [LBR_FORMAT_EIP_FLAGS ] = LBR_EIP_FLAGS ,
24
+ [LBR_FORMAT_EIP_FLAGS2 ] = LBR_EIP_FLAGS | LBR_TSX ,
15
25
};
16
26
17
27
/*
56
66
LBR_FAR)
57
67
58
68
#define LBR_FROM_FLAG_MISPRED (1ULL << 63)
69
+ #define LBR_FROM_FLAG_IN_TX (1ULL << 62)
70
+ #define LBR_FROM_FLAG_ABORT (1ULL << 61)
59
71
60
72
#define for_each_branch_sample_type (x ) \
61
73
for ((x) = PERF_SAMPLE_BRANCH_USER; \
@@ -81,9 +93,13 @@ enum {
81
93
X86_BR_JMP = 1 << 9 , /* jump */
82
94
X86_BR_IRQ = 1 << 10 ,/* hw interrupt or trap or fault */
83
95
X86_BR_IND_CALL = 1 << 11 ,/* indirect calls */
96
+ X86_BR_ABORT = 1 << 12 ,/* transaction abort */
97
+ X86_BR_IN_TX = 1 << 13 ,/* in transaction */
98
+ X86_BR_NO_TX = 1 << 14 ,/* not in transaction */
84
99
};
85
100
86
101
#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
102
+ #define X86_BR_ANYTX (X86_BR_NO_TX | X86_BR_IN_TX)
87
103
88
104
#define X86_BR_ANY \
89
105
(X86_BR_CALL |\
@@ -95,6 +111,7 @@ enum {
95
111
X86_BR_JCC |\
96
112
X86_BR_JMP |\
97
113
X86_BR_IRQ |\
114
+ X86_BR_ABORT |\
98
115
X86_BR_IND_CALL)
99
116
100
117
#define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
@@ -270,21 +287,31 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
270
287
271
288
for (i = 0 ; i < x86_pmu .lbr_nr ; i ++ ) {
272
289
unsigned long lbr_idx = (tos - i ) & mask ;
273
- u64 from , to , mis = 0 , pred = 0 ;
290
+ u64 from , to , mis = 0 , pred = 0 , in_tx = 0 , abort = 0 ;
291
+ int skip = 0 ;
292
+ int lbr_flags = lbr_desc [lbr_format ];
274
293
275
294
rdmsrl (x86_pmu .lbr_from + lbr_idx , from );
276
295
rdmsrl (x86_pmu .lbr_to + lbr_idx , to );
277
296
278
- if (lbr_format == LBR_FORMAT_EIP_FLAGS ) {
297
+ if (lbr_flags & LBR_EIP_FLAGS ) {
279
298
mis = !!(from & LBR_FROM_FLAG_MISPRED );
280
299
pred = !mis ;
281
- from = (u64 )((((s64 )from ) << 1 ) >> 1 );
300
+ skip = 1 ;
301
+ }
302
+ if (lbr_flags & LBR_TSX ) {
303
+ in_tx = !!(from & LBR_FROM_FLAG_IN_TX );
304
+ abort = !!(from & LBR_FROM_FLAG_ABORT );
305
+ skip = 3 ;
282
306
}
307
+ from = (u64 )((((s64 )from ) << skip ) >> skip );
283
308
284
309
cpuc -> lbr_entries [i ].from = from ;
285
310
cpuc -> lbr_entries [i ].to = to ;
286
311
cpuc -> lbr_entries [i ].mispred = mis ;
287
312
cpuc -> lbr_entries [i ].predicted = pred ;
313
+ cpuc -> lbr_entries [i ].in_tx = in_tx ;
314
+ cpuc -> lbr_entries [i ].abort = abort ;
288
315
cpuc -> lbr_entries [i ].reserved = 0 ;
289
316
}
290
317
cpuc -> lbr_stack .nr = i ;
@@ -334,6 +361,16 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
334
361
335
362
if (br_type & PERF_SAMPLE_BRANCH_IND_CALL )
336
363
mask |= X86_BR_IND_CALL ;
364
+
365
+ if (br_type & PERF_SAMPLE_BRANCH_ABORT_TX )
366
+ mask |= X86_BR_ABORT ;
367
+
368
+ if (br_type & PERF_SAMPLE_BRANCH_IN_TX )
369
+ mask |= X86_BR_IN_TX ;
370
+
371
+ if (br_type & PERF_SAMPLE_BRANCH_NO_TX )
372
+ mask |= X86_BR_NO_TX ;
373
+
337
374
/*
338
375
* stash actual user request into reg, it may
339
376
* be used by fixup code for some CPU
@@ -408,7 +445,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event)
408
445
* decoded (e.g., text page not present), then X86_BR_NONE is
409
446
* returned.
410
447
*/
411
- static int branch_type (unsigned long from , unsigned long to )
448
+ static int branch_type (unsigned long from , unsigned long to , int abort )
412
449
{
413
450
struct insn insn ;
414
451
void * addr ;
@@ -428,6 +465,9 @@ static int branch_type(unsigned long from, unsigned long to)
428
465
if (from == 0 || to == 0 )
429
466
return X86_BR_NONE ;
430
467
468
+ if (abort )
469
+ return X86_BR_ABORT | to_plm ;
470
+
431
471
if (from_plm == X86_BR_USER ) {
432
472
/*
433
473
* can happen if measuring at the user level only
@@ -574,7 +614,13 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
574
614
from = cpuc -> lbr_entries [i ].from ;
575
615
to = cpuc -> lbr_entries [i ].to ;
576
616
577
- type = branch_type (from , to );
617
+ type = branch_type (from , to , cpuc -> lbr_entries [i ].abort );
618
+ if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX )) {
619
+ if (cpuc -> lbr_entries [i ].in_tx )
620
+ type |= X86_BR_IN_TX ;
621
+ else
622
+ type |= X86_BR_NO_TX ;
623
+ }
578
624
579
625
/* if type does not correspond, then discard */
580
626
if (type == X86_BR_NONE || (br_sel & type ) != type ) {
0 commit comments