This looks odd:
LFQueue(std::size_t size) : write_id(0), read_id(0), capacity_(size) { buf = new T[capacity_]; }
Why is buf not initialised in the initializer list, like the other members?
More importantly, this default-constructs capacity_ objects. That might just be inefficient, but when T is not default-constructible, it makes the class unusable.
We should really consider allocating uninitialised storage for the elements, and constructing them in place as required. That's what standard containers do.
Also, instead of using raw new, consider achanging to std::unique_ptrunique_ptr<T[]> const buf to manage the storage. Then there would be no need for a user-defined constructor.
Or just delegate managing the storage to a std::deque and let this class have the Single Responsibility of managing the concurrent access. I'd be surprised if that even costs anything in performance when compiled with -Ofast.
The write() and read() functions are hard to use. Instead of blocking until the operation is possible, they just return false, meaning that the user has to manage retrying (likely leading to spinning at one end or the other instead of polite waiting).
Prefer to use standard collection names for functions such as emplace_back() and empty(), and provide the normal member type aliases such as value_type. That makes it easier for readers to comprehend, and for users to switch implementations as necessary.
I haven't looked at the benchmarking code, because there's no point measuring performance until the interface is finalised.