A hit tracer sets a breakpoint at the beginning of every basic block, and records and clears every breakpoint hit (so the performance hit is relatively low).
You'd use a hit tracer to record a "baseline" of your target program when it's not doing the thing you care about. Then you'd run the program again and trigger the behavior. Then you'd diff the traces.
AFL is doing something related when it explores states in targets.
There are a lot of free hit tracers, but they're also kind of a build-your-own-light-saber deal. If you have a Python debugger library and a disassembly, a hit tracer is close to "hello world".