Skip to content

Commit 2735aeb

Browse files
libipt, block: tick events
Add a new block decoder configuration flag enable_tick_events to generate ptev_tick events on conditional or indirect branch instructions. The precision of timing information depends on the trace configuration. If cycle accurate tracing is enabled, the time should correspond to the last instruction in the block that indicated the event. Change-Id: If3fa121cdf3de044f6ebe641c27a6de7888db24b Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
1 parent 0fb3d3f commit 2735aeb

File tree

2 files changed

+142
-11
lines changed

2 files changed

+142
-11
lines changed

libipt/include/intel-pt.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ struct pt_conf_flags {
300300
struct {
301301
/** End a block after a call instruction. */
302302
uint32_t end_on_call:1;
303+
304+
/** Enable tick events for timing updates. */
305+
uint32_t enable_tick_events:1;
303306
} block;
304307

305308
/* Reserve a few bytes for future extensions. */

libipt/src/pt_block_decoder.c

Lines changed: 139 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ static void pt_blk_reset(struct pt_block_decoder *decoder)
177177
decoder->process_event = 0;
178178
decoder->speculative = 0;
179179

180+
memset(&decoder->event, 0, sizeof(decoder->event));
180181
pt_retstack_init(&decoder->retstack);
181182
pt_asid_init(&decoder->asid);
182183
}
@@ -269,6 +270,126 @@ void pt_blk_free_decoder(struct pt_block_decoder *decoder)
269270
free(decoder);
270271
}
271272

273+
/* Maybe synthesize a tick event.
274+
*
275+
* If we're not already processing events, check the current time against the
276+
* last event's time. If it changed, synthesize a tick event with the new time.
277+
*
278+
* Returns zero if no tick event has been created.
279+
* Returns a positive integer if a tick event has been created.
280+
* Returns a negative error code otherwise.
281+
*/
282+
static int pt_blk_tick(struct pt_block_decoder *decoder, uint64_t ip)
283+
{
284+
struct pt_event *ev;
285+
uint64_t tsc;
286+
uint32_t lost_mtc, lost_cyc;
287+
int errcode;
288+
289+
if (!decoder)
290+
return -pte_internal;
291+
292+
/* We're not generating tick events if tracing is disabled. */
293+
if (!decoder->enabled)
294+
return -pte_internal;
295+
296+
/* Events already provide a timestamp so there is no need to synthesize
297+
* an artificial tick event. There's no room, either, since this would
298+
* overwrite the in-progress event.
299+
*
300+
* In rare cases where we need to proceed to an event location using
301+
* trace this may cause us to miss a timing update if the event is not
302+
* forwarded to the user.
303+
*
304+
* The only case I can come up with at the moment is a MODE.EXEC binding
305+
* to the TIP IP of a far branch.
306+
*/
307+
if (decoder->process_event)
308+
return 0;
309+
310+
errcode = pt_qry_time(&decoder->query, &tsc, &lost_mtc, &lost_cyc);
311+
if (errcode < 0) {
312+
/* If we don't have wall-clock time, we use relative time. */
313+
if (errcode != -pte_no_time)
314+
return errcode;
315+
}
316+
317+
ev = &decoder->event;
318+
319+
/* We're done if time has not changed since the last event. */
320+
if (tsc == ev->tsc)
321+
return 0;
322+
323+
/* Time has changed so we create a new tick event. */
324+
memset(ev, 0, sizeof(*ev));
325+
ev->type = ptev_tick;
326+
ev->variant.tick.ip = ip;
327+
328+
/* Indicate if we have wall-clock time or only relative time. */
329+
if (errcode != -pte_no_time)
330+
ev->has_tsc = 1;
331+
ev->tsc = tsc;
332+
ev->lost_mtc = lost_mtc;
333+
ev->lost_cyc = lost_cyc;
334+
335+
/* We now have an event to process. */
336+
decoder->process_event = 1;
337+
338+
return 1;
339+
}
340+
341+
/* Query an indirect branch.
342+
*
343+
* Returns zero on success, a negative error code otherwise.
344+
*/
345+
static int pt_blk_indirect_branch(struct pt_block_decoder *decoder,
346+
uint64_t *ip)
347+
{
348+
uint64_t evip;
349+
int status, errcode;
350+
351+
if (!decoder)
352+
return -pte_internal;
353+
354+
evip = decoder->ip;
355+
356+
status = pt_qry_indirect_branch(&decoder->query, ip);
357+
if (status < 0)
358+
return status;
359+
360+
if (decoder->flags.variant.block.enable_tick_events) {
361+
errcode = pt_blk_tick(decoder, evip);
362+
if (errcode < 0)
363+
return errcode;
364+
}
365+
366+
return status;
367+
}
368+
369+
/* Query a conditional branch.
370+
*
371+
* Returns zero on success, a negative error code otherwise.
372+
*/
373+
static int pt_blk_cond_branch(struct pt_block_decoder *decoder, int *taken)
374+
{
375+
int status, errcode;
376+
377+
if (!decoder)
378+
return -pte_internal;
379+
380+
status = pt_qry_cond_branch(&decoder->query, taken);
381+
if (status < 0)
382+
return status;
383+
384+
if (decoder->flags.variant.block.enable_tick_events) {
385+
errcode = pt_blk_tick(decoder, decoder->ip);
386+
if (errcode < 0)
387+
return errcode;
388+
}
389+
390+
return status;
391+
}
392+
272393
static int pt_blk_start(struct pt_block_decoder *decoder, int status)
273394
{
274395
if (!decoder)
@@ -281,6 +402,14 @@ static int pt_blk_start(struct pt_block_decoder *decoder, int status)
281402
if (!(status & pts_ip_suppressed))
282403
decoder->enabled = 1;
283404

405+
/* We will always have an event.
406+
*
407+
* If we synchronized onto an empty PSB+, tracing is disabled and we'll
408+
* process events until the enabled event.
409+
*
410+
* If tracing is enabled, PSB+ must at least provide the execution mode,
411+
* which we're going to forward to the user.
412+
*/
284413
return pt_blk_proceed_trailing_event(decoder, NULL);
285414
}
286415

@@ -506,7 +635,7 @@ static int pt_blk_next_ip(uint64_t *pip, struct pt_block_decoder *decoder,
506635
const struct pt_insn *insn,
507636
const struct pt_insn_ext *iext)
508637
{
509-
int status;
638+
int status, errcode;
510639

511640
if (!pip || !decoder || !insn || !iext)
512641
return -pte_internal;
@@ -521,7 +650,7 @@ static int pt_blk_next_ip(uint64_t *pip, struct pt_block_decoder *decoder,
521650
uint64_t ip;
522651
int taken;
523652

524-
status = pt_qry_cond_branch(&decoder->query, &taken);
653+
status = pt_blk_cond_branch(decoder, &taken);
525654
if (status < 0)
526655
return status;
527656

@@ -534,10 +663,10 @@ static int pt_blk_next_ip(uint64_t *pip, struct pt_block_decoder *decoder,
534663
}
535664

536665
case ptic_return: {
537-
int taken, errcode;
666+
int taken;
538667

539668
/* Check for a compressed return. */
540-
status = pt_qry_cond_branch(&decoder->query, &taken);
669+
status = pt_blk_cond_branch(decoder, &taken);
541670
if (status < 0) {
542671
if (status != -pte_bad_query)
543672
return status;
@@ -584,7 +713,7 @@ static int pt_blk_next_ip(uint64_t *pip, struct pt_block_decoder *decoder,
584713
* This covers indirect jumps and calls, non-compressed returns, and all
585714
* flavors of far transfers.
586715
*/
587-
return pt_qry_indirect_branch(&decoder->query, pip);
716+
return pt_blk_indirect_branch(decoder, pip);
588717
}
589718

590719
/* Proceed to the next IP using trace.
@@ -1929,7 +2058,7 @@ static int pt_blk_proceed_no_event_cached(struct pt_block_decoder *decoder,
19292058
* We can't use the normal decode and proceed-with-trace
19302059
* flow since we already consumed the TNT bit.
19312060
*/
1932-
status = pt_qry_cond_branch(&decoder->query, &taken);
2061+
status = pt_blk_cond_branch(decoder, &taken);
19332062
if (status < 0)
19342063
return status;
19352064

@@ -2072,7 +2201,7 @@ static int pt_blk_proceed_no_event_cached(struct pt_block_decoder *decoder,
20722201
if (status < 0)
20732202
return status;
20742203

2075-
status = pt_qry_indirect_branch(&decoder->query, &decoder->ip);
2204+
status = pt_blk_indirect_branch(decoder, &decoder->ip);
20762205
if (status < 0)
20772206
return status;
20782207

@@ -2090,16 +2219,15 @@ static int pt_blk_proceed_no_event_cached(struct pt_block_decoder *decoder,
20902219
block->iclass = ptic_return;
20912220

20922221
/* Check for a compressed return. */
2093-
status = pt_qry_cond_branch(&decoder->query, &taken);
2222+
status = pt_blk_cond_branch(decoder, &taken);
20942223
if (status < 0) {
20952224
if (status != -pte_bad_query)
20962225
return status;
20972226

20982227
/* The return is not compressed. We need another query
20992228
* to determine the destination IP.
21002229
*/
2101-
status = pt_qry_indirect_branch(&decoder->query,
2102-
&decoder->ip);
2230+
status = pt_blk_indirect_branch(decoder, &decoder->ip);
21032231
if (status < 0)
21042232
return status;
21052233

@@ -2140,7 +2268,7 @@ static int pt_blk_proceed_no_event_cached(struct pt_block_decoder *decoder,
21402268
*
21412269
* Just query the destination IP.
21422270
*/
2143-
status = pt_qry_indirect_branch(&decoder->query, &decoder->ip);
2271+
status = pt_blk_indirect_branch(decoder, &decoder->ip);
21442272
if (status < 0)
21452273
return status;
21462274

0 commit comments

Comments
 (0)