From de3a96e3b12a4450c54eda6a81cc8d9afe7a7b8c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 15 May 2017 21:44:40 +0000 Subject: [PATCH] Ensure that profile and tick probes provide a non-zero PC value. The idle thread may process callouts while reloading the timer in cpu_activeclock(). In this case, provide a representative value, &cpu_idle, instead of 0 for args[0] so that the active thread can be more easily identified from the probe. This addresses intermittent failures of the profile-n/tst.argtest.d test. MFC after: 2 weeks Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D10651 --- sys/cddl/dev/profile/profile.c | 62 ++++++++++++++-------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/sys/cddl/dev/profile/profile.c b/sys/cddl/dev/profile/profile.c index 3b584246d14e..55ea9850e26d 100644 --- a/sys/cddl/dev/profile/profile.c +++ b/sys/cddl/dev/profile/profile.c @@ -266,37 +266,43 @@ sbt_to_nsec(sbintime_t sbt) } static void -profile_fire(void *arg) +profile_probe(profile_probe_t *prof, hrtime_t late) { - profile_probe_percpu_t *pcpu = arg; - profile_probe_t *prof = pcpu->profc_probe; - hrtime_t late; + struct thread *td; struct trapframe *frame; uintfptr_t pc, upc; -#ifdef illumos - late = gethrtime() - pcpu->profc_expected; -#else - late = sbt_to_nsec(sbinuptime() - pcpu->profc_expected); -#endif - - pc = 0; - upc = 0; + td = curthread; + pc = upc = 0; /* - * td_intr_frame can be unset if this is a catch up event - * after waking up from idle sleep. - * This can only happen on a CPU idle thread. + * td_intr_frame can be unset if this is a catch-up event upon waking up + * from idle sleep. This can only happen on a CPU idle thread. Use a + * representative arg0 value in this case so that one of the probe + * arguments is non-zero. */ - frame = curthread->td_intr_frame; + frame = td->td_intr_frame; if (frame != NULL) { if (TRAPF_USERMODE(frame)) upc = TRAPF_PC(frame); else pc = TRAPF_PC(frame); - } - dtrace_probe(prof->prof_id, pc, upc, late, 0, 0); + } else if (TD_IS_IDLETHREAD(td)) + pc = (uintfptr_t)&cpu_idle; + dtrace_probe(prof->prof_id, pc, upc, late, 0, 0); +} + +static void +profile_fire(void *arg) +{ + profile_probe_percpu_t *pcpu = arg; + profile_probe_t *prof = pcpu->profc_probe; + hrtime_t late; + + late = sbt_to_nsec(sbinuptime() - pcpu->profc_expected); + + profile_probe(prof, late); pcpu->profc_expected += pcpu->profc_interval; callout_schedule_sbt_curcpu(&pcpu->profc_cyclic, pcpu->profc_expected, 0, C_DIRECT_EXEC | C_ABSOLUTE); @@ -306,26 +312,8 @@ static void profile_tick(void *arg) { profile_probe_t *prof = arg; - struct trapframe *frame; - uintfptr_t pc, upc; - - pc = 0; - upc = 0; - - /* - * td_intr_frame can be unset if this is a catch up event - * after waking up from idle sleep. - * This can only happen on a CPU idle thread. - */ - frame = curthread->td_intr_frame; - if (frame != NULL) { - if (TRAPF_USERMODE(frame)) - upc = TRAPF_PC(frame); - else - pc = TRAPF_PC(frame); - } - dtrace_probe(prof->prof_id, pc, upc, 0, 0, 0); + profile_probe(prof, 0); prof->prof_expected += prof->prof_interval; callout_schedule_sbt(&prof->prof_cyclic, prof->prof_expected, 0, C_DIRECT_EXEC | C_ABSOLUTE);