sched-ext / scx

sched_ext schedulers and tools
https://bit.ly/scx_slack
GNU General Public License v2.0
895 stars 84 forks source link

kernel: Implement cached current time interface #858

Open htejun opened 2 days ago

htejun commented 2 days ago

SCX schedulers tend to use bpf_ktime_get_ns() a lot. On x86, this eventually is serviced by rdtsc_ordered() which is the rdtscp instruction. The instruction is known to be expensive and has scalability issues on large machines when the CPUs are saturated (the cost of the instruction increases as machine gets saturated).

In most cases, we don't really care about nanosec accuracy that we're paying for. There can be a couple approaches in addressing this:

  1. Cache ktime_get_ns() result and provide a kfunc to access the cached time. The kernel should have reasonable cache invalidation points (e.g. at the start of dispatch and when rq lock is released during dispatch and so on).
  2. Provide interface to access timestamp which is not program ordered (ie. rdtsc in x86) along with helpers to compare and calculate delta between two timestamps. rdtsc is cheaper and doesn't have scalability issues that rdtscp has but it's unclear how this would map in other archs.

Considerations:

multics69 commented 1 day ago

I have looked a bit, and this is what I am thinking.

Considering the discussion on the BPF mailing list (https://lore.kernel.org/bpf/CAEf4BzaBNNCYaf9a4oHsB2AzYyc6JCWXpHx6jk22Btv=UAgX4A@mail.gmail.com/), I think we can assume the following two (or something similar) new APIs:

Based on these two new APIs, we can provide two common utility functions at common.bpf.h abstracting the details of bpf_get_hw_counter() and bpf_ktime_get_ns().

In my opinion, it would be quite difficult to handle the clock drift of rdtsc if its bound is unknown. So rather than handling the clock drift magically, it would be more straightforward to let scx scheduler handle it. I think in the scx schedulers' usage case, only thing to consider will be checking the new timestampe is smaller than an old timestamp.

What do you think, @htejun ?

htejun commented 21 hours ago

One challenge is that rdtsc is reported to not scale well on large machines on intel sapphire rapids, so even it looks like we'd likely need caching whether we use rdtsc or rdtscp.

For reference, Chris Mason implemented a simple benchmark to tests TSC performance: https://github.com/masoncl/tscbench. The main problem being observed is rdtscp and rdtsc depending on the CPU type getting progressively slower on larger setups as CPUs get saturated.

etsal commented 20 hours ago

Some thoughts on the problem:

1) Why not make the API monotonic by default if there is no apparent good way of handling rdtsc drift, apart from abefore > after check? We could leave it to the scheduler if there was a design choice to be made about this, but that doesn't seem to be the case. Making the call monotonic seems more intuitive if the alternative is to always manually check.

2) Is there a good reason to return both timestamp counters and ns? Possibly returning the raw counter forces the scheduler to consider the source of the timestamp when parsing it which doesn't seem desirable. I think a single both scx_bpf_get_time and scx_bpf_time_to_ns could get rolled into a single scx_bpf_get_time_ns that only returns ns.

3) If rdtsc is problematic for some machines but works fine for others, we still need the option to return a cached value. We can add a flag in the call to explicitly specify the source of the value, but would it be worth it? Are there scenarios where reading rdtsc is superior to returning a cached value, or can we always use the latter?

Thoughts @multics69 @htejun ?

htejun commented 20 hours ago
  1. Yeah, monotonic on each CPU makes sense to me but it'd be difficult to make it monotonic across the system. e.g. Given a sequence of events that are known to be ordered and happening across CPUs, can we guarantee that timestamp taken later on a different CPU is time-wise later? If we can't, then we still have the same ordering problem when comparing.
  2. I think it'd be better to always go for absolute time.
  3. If we can get caching right, we can probably always just use cached timestamp.
multics69 commented 13 hours ago

Thank you for the feedback @htejun and @etsal !

  1. I agree with @htejun 's point. Making a time stamp monotonic system-wide is a hard problem. I think it would be difficult (if not impossible) without a central cache hotspot.

  2. Exposing only absolute time would be less confusing.

  3. I will further develop ideas about the caching, if it would be possible efficiently and scalabily to cache a timestamp without creating cache hotspots.

BTW, @htejun -- do you have some tsc benchmark numbers on sapphire rapids? It would be great to understand how bad rdtsc is to know the budget we can use for caching.

htejun commented 13 hours ago

I only heard results second-hand. IIRC, on sapphire rapids, rdtsc wasn't much better than rdtscp.