Page MenuHomeFreeBSD

Hardware Trace (HWT) framework
ClosedPublic

Authored by br on Jun 7 2023, 3:02 PM.
Tags
None
Referenced Files
F131798355: D40466.id123816.diff
Sat, Oct 11, 6:17 AM
F131778827: D40466.id141894.diff
Sat, Oct 11, 2:30 AM
Unknown Object (File)
Fri, Oct 10, 2:47 AM
Unknown Object (File)
Thu, Oct 9, 11:38 PM
Unknown Object (File)
Thu, Oct 9, 5:42 PM
Unknown Object (File)
Wed, Oct 8, 12:18 PM
Unknown Object (File)
Wed, Oct 8, 7:13 AM
Unknown Object (File)
Tue, Oct 7, 6:36 AM

Details

Summary

Hardware Trace (HWT) v0.1

HWT framework manages hardware technology that collects information about software execution and records it as "events" in highly compressed format into DRAM. The events cover information about control flow changes of a program, whether branches taken or not, exceptions taken, timing information, cycles elapsed and more. This allowing us to restore entire program flow of a given application.

Initially targeting ARM Coresight technology included into ARM64 processors.

Part2: ARM Coresight Support
Part3: hwt(8) instrumentation tool
Part4: ARM Statistical Profiling Extension (SPE) support
Part5: Intel Processor Trace (PT) support

Test Plan

Tested on ARM Morello

Diff Detail

Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
cy removed a subscriber: cy.

Allow attaching to an existed proc

change backend lock, ident set lock, ownerhash lock to standard mtx

sys/sys/hwt.h
59 ↗(On Diff #126853)

The cpuset_t could cause ABI issues when we bump MAXCPU. vmm.ko on amd64 was recently changed to not embed it in the struct in rGe17eca327633efc511450310afb5e4a662724e3d

Replace most of spin locks to standard mtx. Use refcounting in some places

User provides cpusetsize together with *cpuset_t.

sys/sys/hwt.h
59 ↗(On Diff #126853)

Thanks I have updated; cpusetsize is now supplied by a user; cpuset_t is now a pointer

Can you rebase the stack on FreeBSD so we can test on non-Morello hardware?

Pass ctx to backend_deinit().

sys/dev/hwt/hwt_context.c
70 ↗(On Diff #127815)

In what situations do we have more than one hwt_context? This allocates a unique ident from 0 to 1<<8 but as far as I can tell in both hwt_ioctl_alloc_mode_{thread,cpu} we only allocate a single context aka ident 0.

sys/dev/hwt/hwt_context.c
70 ↗(On Diff #127815)

I guess this may happen if two users simultaneously using hwt. This is not possible in coresight, but possible in Intel PT and probably SPE ?

sys/dev/hwt/hwt_context.c
70 ↗(On Diff #127815)

Ah yep - okay makes sense. It should be possible to run Coresight and SPE simultaneously at least.

On SPE everything is per core, so you *should* be able to trace on all cores separately. Two users tracing the same core would not be possible. Not sure how that would work with THREAD_MODE, as would depend on where the task is scheduled - I guess no concurrent SPE users will be possible there. I've only implemented CPU_MODE so far.

br added a reviewer: bnovkov.

Regenerate

br edited the test plan for this revision. (Show Details)

How do you handle different conflicting modes? e.g. a user is tracing a pid & another tries to enable thread tracing. The hardware may not be able to perform both operations.

Prevent tracing the same proc by multiple users.

How do you handle different conflicting modes? e.g. a user is tracing a pid & another tries to enable thread tracing. The hardware may not be able to perform both operations.

I have added a session counter to coresight to ensure it is used for 1 simultaneous sessions at max (regardless of type). @bnovkov is currently working on similar arrangements for Intel PT depending on hardware capabilities.
Generally we could allow thread tracing for multiple users simultaneously in Intel PT.
Coresight is more restricted disallowing us to continue a trace session from specific place in buffer, so we completely disallow multiple users to trace simultaneously.

I don't see any documentation for this, is there a separate review for a man page somewhere?

sys/kern/kern_hwt.c
42 ↗(On Diff #149260)

We definitely don't need all of these includes.

sys/kern/vfs_vnops.c
2934

We should only do this work if the hook is actually enabled.

sys/dev/hwt/hwt_hook.h
29

These tags shouldn't appear in new code.

sys/vm/vm_mmap.c
1067

How is this used? You are not passing the size of the mapping anywhere, which seems wrong.

br marked an inline comment as done.
  • Remove $FreeBSD$ tags
  • Remove unused include headers
  • Check if HWT hooks are installed before constructing data structures
sys/vm/vm_mmap.c
1067

The address of mapping passed to pmcstat. It loads elf file based on mapping address (fullpath). So it knows the size of mapping. See pmcstat_image_link().

sys/kern/imgact_elf.c
1621

Move the ent declaration under the if().

That said, why do you hook elf image activator at all? Such hook should be generic and set somewhere in kern_exec.c.

sys/kern/kern_hwt.c
48 ↗(On Diff #157530)

I doubt that two vars deserve a dedicated kern.c file. Find a place to put them elsewere.

sys/kern/sched_ule.c
3166

What about the same hooks for SCHED_4BSD?

sys/kern/vfs_vnops.c
2931

Move vars declarations under if () block.

sys/vm/vm_mmap.c
1062

Move ent under if().

Also, it seems you only hook vnodes mappings. What about anon memory, or swap-backed non-anon?

sys/vm/vm_mmap.c
1062

Also, it seems you only hook vnodes mappings. What about anon memory, or swap-backed non-anon?

The userspace decoder needs to have access to the binaries that generated the execution trace (and their location within the traced process's address space) to decode the trace, which is we only hook vnode mappings.
These hooks forward the mapping information to the userspace decoder, which will load all executable sections from the mapped binary.

I assume that this approach doesn't covers things like tracing JIT-generated code, but that can probably be fixed by placing another hook, if need be.

  • Move ELF image activator hooks to generic kern_exec.c
  • HWT_HOOKS: Move variable declarations under the if()
  • HWT_HOOKS: Move contents of kern_hwt.c to kern_pmc.c
  • Remove VM_ALLOC_NOBUSY flag from vm_page_alloc_contig() request to meet KASSERTs in vm_page.c

Add SCHED_4BSD hwt hooks

br marked 4 inline comments as done.Jun 27 2025, 9:11 AM
br added inline comments.
sys/kern/imgact_elf.c
1621

Agree, I have it moved to generic kern_exec.c!

sys/kern/kern_hwt.c
48 ↗(On Diff #157530)

Moved to kern_pmc.c

sys/kern/sched_ule.c
3166

Ok, added and tested!

sys/kern/kern_exec.c
945 ↗(On Diff #157658)
946 ↗(On Diff #157658)

There should be a blank line after vars definition block.

947 ↗(On Diff #157658)

What does the hook do? In particular, I wonder why it needs to image text vnode unlocked.

sys/kern/vfs_vnops.c
2933

Blank line is needed after vars block.

br marked 3 inline comments as done.

do not unlock image text vnode

br marked 3 inline comments as done.Jun 30 2025, 1:51 PM
br added inline comments.
sys/kern/kern_exec.c
947 ↗(On Diff #157658)

The hook makes a copy of ent (using uma_zalloc) and stores it into the tail queue of records to the corresponding tracing context. Then it puts the thread to sleep if needed (see hwt_hook_mmap()).
Userspace periodically fetches the queue of records, locates the address of executable/library in the records, reconfigures hardware tracing units and wakes up the sleeping thread.
Sleep is only needed when the user sets up the 'address range filtering' feature to trace a particular function of an executable/dynamic library.

Based on my experiments, unlocking image text vnode is not needed, so I remove it.

sys/kern/kern_exec.c
947 ↗(On Diff #157658)

Sleeping while owning a vnode lock is not prohibited, but is highly undesirable. It is tabooed when the duration of the sleep is controlled by userspace, since it causes a user-controllable live-lock: any process trying to do anything with this vnode, would be put to sleep until the sleeping thread wakes up and unlocks the vnode.

So from your description, the situation is reverse: you do need to unlock the vnode around the hook call.

Restore "unlock the vnode around the exec hook call"

I only read the sys/kern bits.

sys/kern/vfs_vnops.c
2939

The check for != NULL is not needed.

This revision is now accepted and ready to land.Jul 1 2025, 9:49 AM
This revision was automatically updated to reflect the committed changes.