epoch: with EPOCH_TRACE add epoch_where_report()

which will report where the epoch was entered and also
mark the tracker, so that exit will also be reported.

Helps to understand epoch entrance/exit scenarios in
complex cases, like network stack.  As everything else
under EPOCH_TRACE it is a developer only tool.
This commit is contained in:
Gleb Smirnoff 2021-12-02 10:59:43 -08:00
parent 9e93d2b335
commit d96fccc505
2 changed files with 36 additions and 7 deletions

View File

@ -147,6 +147,13 @@ static struct sx epoch_sx;
#define EPOCH_LOCK() sx_xlock(&epoch_sx)
#define EPOCH_UNLOCK() sx_xunlock(&epoch_sx)
static epoch_record_t
epoch_currecord(epoch_t epoch)
{
return (zpcpu_get(epoch->e_pcpu_record));
}
#ifdef EPOCH_TRACE
struct stackentry {
RB_ENTRY(stackentry) se_node;
@ -230,6 +237,7 @@ epoch_trace_enter(struct thread *td, epoch_t epoch, epoch_tracker_t et,
et->et_epoch = epoch;
et->et_file = file;
et->et_line = line;
et->et_flags = 0;
SLIST_INSERT_HEAD(&td->td_epochs, et, et_tlink);
}
@ -250,6 +258,9 @@ epoch_trace_exit(struct thread *td, epoch_t epoch, epoch_tracker_t et,
SLIST_REMOVE(&td->td_epochs, et, epoch_tracker, et_tlink);
} else
SLIST_REMOVE_HEAD(&td->td_epochs, et_tlink);
if (et->et_flags & ET_REPORT_EXIT)
printf("Td %p exiting epoch %s at %s:%d\n", td, epoch->e_name,
file, line);
}
/* Used by assertions that check thread state before going to sleep. */
@ -262,6 +273,28 @@ epoch_trace_list(struct thread *td)
printf("Epoch %s entered at %s:%d\n", iet->et_epoch->e_name,
iet->et_file, iet->et_line);
}
void
epoch_where_report(epoch_t epoch)
{
epoch_record_t er;
struct epoch_tracker *tdwait;
MPASS(epoch != NULL);
MPASS((epoch->e_flags & EPOCH_PREEMPT) != 0);
MPASS(!THREAD_CAN_SLEEP());
critical_enter();
er = epoch_currecord(epoch);
TAILQ_FOREACH(tdwait, &er->er_tdlist, et_link)
if (tdwait->et_td == curthread)
break;
critical_exit();
if (tdwait != NULL) {
tdwait->et_flags |= ET_REPORT_EXIT;
printf("Td %p entered epoch %s at %s:%d\n", curthread,
epoch->e_name, tdwait->et_file, tdwait->et_line);
}
}
#endif /* EPOCH_TRACE */
static void
@ -422,13 +455,6 @@ epoch_free(epoch_t epoch)
EPOCH_UNLOCK();
}
static epoch_record_t
epoch_currecord(epoch_t epoch)
{
return (zpcpu_get(epoch->e_pcpu_record));
}
#define INIT_CHECK(epoch) \
do { \
if (__predict_false((epoch) == NULL)) \

View File

@ -61,6 +61,8 @@ struct epoch_tracker {
SLIST_ENTRY(epoch_tracker) et_tlink;
const char *et_file;
int et_line;
int et_flags;
#define ET_REPORT_EXIT 0x1
#endif
} __aligned(sizeof(void *));
typedef struct epoch_tracker *epoch_tracker_t;
@ -86,6 +88,7 @@ void _epoch_enter_preempt(epoch_t epoch, epoch_tracker_t et EPOCH_FILE_LINE);
void _epoch_exit_preempt(epoch_t epoch, epoch_tracker_t et EPOCH_FILE_LINE);
#ifdef EPOCH_TRACE
void epoch_trace_list(struct thread *);
void epoch_where_report(epoch_t);
#define epoch_enter_preempt(epoch, et) _epoch_enter_preempt(epoch, et, __FILE__, __LINE__)
#define epoch_exit_preempt(epoch, et) _epoch_exit_preempt(epoch, et, __FILE__, __LINE__)
#else