lfence works as a execution barrier and has an explicit cost of only a few cycles. You can accurately time a region with something like:
lfence
rdtsc
lfence
// timed region
lfence
rdtsc
This will give you accurate timing with some offset (i.e. even with an empty region you get a result on the order of 25-40 cycles), which you can mostly subtract out.Carefully done you can get results down to a nanosecond or so.
rdtscp has few advantages over lfence + rdtsc, and arguably some disadvantages (you can control where the implied fence goes).