git: 6fa041d7f125 - main - Measure latency of PMC interruptions

Mateusz Guzik mjguzik at gmail.com
Mon Sep 13 08:01:43 UTC 2021


On 9/13/21, Wojciech Macek <wma at freebsd.org> wrote:
> The branch main has been updated by wma:
>
> URL:
> https://cgit.FreeBSD.org/src/commit/?id=6fa041d7f125db65f400af7f520a41ff78d19cd7
>
> commit 6fa041d7f125db65f400af7f520a41ff78d19cd7
> Author:     Wojciech Macek <wma at FreeBSD.org>
> AuthorDate: 2021-09-13 04:08:32 +0000
> Commit:     Wojciech Macek <wma at FreeBSD.org>
> CommitDate: 2021-09-13 04:08:32 +0000
>
>     Measure latency of PMC interruptions
>
>     Add HWPMC events to measure latency.
>     Provide sysctl to choose the number of outstanding events which
>     trigger HWPMC event.
>
>     Obtained from:          Semihalf
>     Sponsored by:           Stormshield
>     Differential revision:  https://reviews.freebsd.org/D31283
> ---
>  sys/kern/kern_intr.c | 58
> ++++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 52 insertions(+), 6 deletions(-)
>
> diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
> index 1660414a50ef..19401877dfbd 100644
> --- a/sys/kern/kern_intr.c
> +++ b/sys/kern/kern_intr.c
> @@ -30,6 +30,7 @@
>  __FBSDID("$FreeBSD$");
>
>  #include "opt_ddb.h"
> +#include "opt_hwpmc_hooks.h"
>  #include "opt_kstack_usage_prof.h"
>
>  #include <sys/param.h>
> @@ -75,6 +76,7 @@ struct intr_thread {
>  	struct thread *it_thread;	/* Kernel thread. */
>  	int	it_flags;		/* (j) IT_* flags. */
>  	int	it_need;		/* Needs service. */
> +	int	it_waiting;		/* Waiting in the runq. */
>  };
>
>  /* Interrupt thread flags kept in it_flags */
> @@ -100,13 +102,19 @@ SYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold,
> CTLFLAG_RWTUN,
>  static int intr_epoch_batch = 1000;
>  SYSCTL_INT(_hw, OID_AUTO, intr_epoch_batch, CTLFLAG_RWTUN,
> &intr_epoch_batch,
>      0, "Maximum interrupt handler executions without re-entering
> epoch(9)");
> +#ifdef HWPMC_HOOKS
> +static int intr_hwpmc_waiting_report_threshold = 1;
> +SYSCTL_INT(_hw, OID_AUTO, intr_hwpmc_waiting_report_threshold,
> CTLFLAG_RWTUN,
> +    &intr_hwpmc_waiting_report_threshold, 1,
> +    "Threshold for reporting number of events in a workq");
> +#endif
>  static TAILQ_HEAD(, intr_event) event_list =
>      TAILQ_HEAD_INITIALIZER(event_list);
>  static struct mtx event_lock;
>  MTX_SYSINIT(intr_event_list, &event_lock, "intr event list", MTX_DEF);
>
>  static void	intr_event_update(struct intr_event *ie);
> -static int	intr_event_schedule_thread(struct intr_event *ie);
> +static int	intr_event_schedule_thread(struct intr_event *ie, struct
> trapframe *frame);
>  static struct intr_thread *ithread_create(const char *name);
>  static void	ithread_destroy(struct intr_thread *ithread);
>  static void	ithread_execute_handlers(struct proc *p,
> @@ -115,6 +123,16 @@ static void	ithread_loop(void *);
>  static void	ithread_update(struct intr_thread *ithd);
>  static void	start_softintr(void *);
>
> +#ifdef HWPMC_HOOKS
> +#include <sys/pmckern.h>
> +PMC_SOFT_DEFINE( , , intr, all);
> +PMC_SOFT_DEFINE( , , intr, ithread);
> +PMC_SOFT_DEFINE( , , intr, filter);
> +PMC_SOFT_DEFINE( , , intr, stray);
> +PMC_SOFT_DEFINE( , , intr, schedule);
> +PMC_SOFT_DEFINE( , , intr, waiting);
> +#endif
> +
>  /* Map an interrupt type to an ithread priority. */
>  u_char
>  intr_priority(enum intr_type flags)
> @@ -773,7 +791,7 @@ intr_handler_barrier(struct intr_handler *handler)
>  	}
>  	if ((handler->ih_flags & IH_CHANGED) == 0) {
>  		handler->ih_flags |= IH_CHANGED;
> -		intr_event_schedule_thread(ie);
> +		intr_event_schedule_thread(ie, NULL);
>  	}
>  	while ((handler->ih_flags & IH_CHANGED) != 0)
>  		msleep(handler, &ie->ie_lock, 0, "ih_barr", 0);
> @@ -872,7 +890,7 @@ intr_event_remove_handler(void *cookie)
>  	KASSERT((handler->ih_flags & IH_DEAD) == 0,
>  	    ("duplicate handle remove"));
>  	handler->ih_flags |= IH_DEAD;
> -	intr_event_schedule_thread(ie);
> +	intr_event_schedule_thread(ie, NULL);
>  	while (handler->ih_flags & IH_DEAD)
>  		msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0);
>  	intr_event_update(ie);
> @@ -944,7 +962,7 @@ intr_event_resume_handler(void *cookie)
>  }
>
>  static int
> -intr_event_schedule_thread(struct intr_event *ie)
> +intr_event_schedule_thread(struct intr_event *ie, struct trapframe *frame)
>  {
>  	struct intr_entropy entropy;
>  	struct intr_thread *it;
> @@ -986,11 +1004,28 @@ intr_event_schedule_thread(struct intr_event *ie)
>  	atomic_store_rel_int(&it->it_need, 1);
>  	thread_lock(td);
>  	if (TD_AWAITING_INTR(td)) {
> +#ifdef HWPMC_HOOKS
> +		atomic_set_int(&it->it_waiting, 0);

atomic_set does not assign the passed value, it or's it.

> +		if (frame != NULL)
> +			PMC_SOFT_CALL_TF( , , intr, schedule, frame);
> +		else
> +			PMC_SOFT_CALL( , , intr, schedule);
> +#endif
>  		CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, td->td_proc->p_pid,
>  		    td->td_name);
>  		TD_CLR_IWAIT(td);
>  		sched_add(td, SRQ_INTR);
>  	} else {
> +#ifdef HWPMC_HOOKS
> +		atomic_add_int(&it->it_waiting, 1);

Why is this using atomics to begin with? To my reading the field is de
facto protected by thread lock, so you can just it->it_waiting++
> +
> +		if (atomic_load_int(&it->it_waiting) >=
> intr_hwpmc_waiting_report_threshold) {

The option is enabled by default but hwpmc itself is rarely loaded.
Then this avoidable loads intr_hwpmc_waiting_report_threshold to begin
with. Instead you can do something in the lines:

#define PMC_HOOK_INSTALLED_ANY() __predict_false(pmc_hook != NULL)

and use that to guard the other branches. Later on this will be hot
patchable so it wont be a problem by default.

> +			if (frame != NULL)
> +				PMC_SOFT_CALL_TF( , , intr, waiting, frame);
> +			else
> +				PMC_SOFT_CALL( , , intr, waiting);
> +		}
> +#endif
>  		CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
>  		    __func__, td->td_proc->p_pid, td->td_name, it->it_need,
> TD_GET_STATE(td));
>  		thread_unlock(td);
> @@ -1083,7 +1118,7 @@ swi_sched(void *cookie, int flags)
>  #endif
>  	} else {
>  		VM_CNT_INC(v_soft);
> -		error = intr_event_schedule_thread(ie);
> +		error = intr_event_schedule_thread(ie, NULL);
>  		KASSERT(error == 0, ("stray software interrupt"));
>  	}
>  }
> @@ -1374,12 +1409,23 @@ intr_event_handle(struct intr_event *ie, struct
> trapframe *frame)
>  			ret = ih->ih_filter(frame);
>  		else
>  			ret = ih->ih_filter(ih->ih_argument);
> +#ifdef HWPMC_HOOKS
> +		PMC_SOFT_CALL_TF( , , intr, all, frame);
> +#endif
>  		KASSERT(ret == FILTER_STRAY ||
>  		    ((ret & (FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) != 0 &&
>  		    (ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0),
>  		    ("%s: incorrect return value %#x from %s", __func__, ret,
>  		    ih->ih_name));
>  		filter = filter || ret == FILTER_HANDLED;
> +#ifdef HWPMC_HOOKS
> +		if (ret & FILTER_SCHEDULE_THREAD)
> +			PMC_SOFT_CALL_TF( , , intr, ithread, frame);
> +		else if (ret & FILTER_HANDLED)
> +			PMC_SOFT_CALL_TF( , , intr, filter, frame);
> +		else if (ret == FILTER_STRAY)
> +			PMC_SOFT_CALL_TF( , , intr, stray, frame);
> +#endif
>
>  		/*
>  		 * Wrapper handler special handling:
> @@ -1416,7 +1462,7 @@ intr_event_handle(struct intr_event *ie, struct
> trapframe *frame)
>  	if (thread) {
>  		int error __unused;
>
> -		error =  intr_event_schedule_thread(ie);
> +		error =  intr_event_schedule_thread(ie, frame);
>  		KASSERT(error == 0, ("bad stray interrupt"));
>  	}
>  	critical_exit();
>


-- 
Mateusz Guzik <mjguzik gmail.com>


More information about the dev-commits-src-all mailing list