This is an archive of the discontinued LLVM Phabricator instance.

Add ThreadPriority::Low, and use QoS class Utility on Mac
ClosedPublic

Authored by stefanhaller on Apr 30 2022, 7:55 AM.

Details

Summary

On Apple Silicon Macs, using a Darwin thread priority of PRIO_DARWIN_BG seems to
map directly to the QoS class Background. With this priority, the thread is
confined to efficiency cores only, which makes background indexing take forever.

Introduce a new ThreadPriority "Low" that sits in the middle between Background
and Default, and maps to QoS class "Utility" on Mac. Make this new priority the
default for indexing. This makes the thread run on all cores, but still lowers
priority enough to keep the machine responsive, and not interfere with
user-initiated actions.

I didn't change the implementations for Windows and Linux; on these systems,
both ThreadPriority::Background and ThreadPriority::Low map to the same thread
priority. This could be changed as a followup (e.g. by using SCHED_BATCH for Low
on Linux).

See also https://github.com/clangd/clangd/issues/1119.

Diff Detail

Event Timeline

stefanhaller created this revision.Apr 30 2022, 7:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 30 2022, 7:55 AM
stefanhaller requested review of this revision.Apr 30 2022, 7:55 AM
Herald added projects: Restricted Project, Restricted Project, Restricted Project. · View Herald TranscriptApr 30 2022, 7:55 AM
dgoldman added inline comments.Apr 30 2022, 8:43 AM
llvm/include/llvm/Support/Threading.h
249–250

Should be "Low" now

Wonder if this comment should be moved up into ThreadPriority?

Fix documentation of ThreadPriority::Low (was: Background), and move it up from
set_thread_priority to ThreadPriority.

(Is it ok that there's no documentation left for set_thread_priority? I couldn't
come up with anything that's not trivial and redundant, e.g. "Sets the priority
of the current thread.")

dgoldman accepted this revision.May 3 2022, 7:01 AM

Fix documentation of ThreadPriority::Low (was: Background), and move it up from
set_thread_priority to ThreadPriority.

(Is it ok that there's no documentation left for set_thread_priority? I couldn't
come up with anything that's not trivial and redundant, e.g. "Sets the priority
of the current thread.")

LGTM, no need for a trivial comment, the priorities themselves are documented.

This revision is now accepted and ready to land.May 3 2022, 7:01 AM

With this priority, the thread is
confined to efficiency cores only, which makes background indexing take forever

(How) does this interact with battery vs mains power on laptops?
It seems like there's a common scenario where:

  • the user is on a relatively slow laptop, running off battery
  • the codebase is large, and indexing is unlikely to finish within an editing session

In this case, it seems like only using efficiency cores is what you'd want, and that people are likely to be upset if clangd 15 keeps their performance cores running at all times.

Reading the docs it seems like background is the intended QoS for this type of work ("such as indexing"..."minutes or hours").

(Sorry to bring this up at code review time, I wasn't thinking about laptops when we discussed on the bug)

(How) does this interact with battery vs mains power on laptops?
It seems like there's a common scenario where:

  • the user is on a relatively slow laptop, running off battery
  • the codebase is large, and indexing is unlikely to finish within an editing session

In this case, it seems like only using efficiency cores is what you'd want, and that people are likely to be upset if clangd 15 keeps their performance cores running at all times.

I can only speak for myself here: I'm a laptop user myself, and I work on battery the majority of the day; but I still wouldn't trade indexing speed for saving battery. The clangd index is so essential for my work that I always want it to be available as quickly as possible.

Reading the docs it seems like background is the intended QoS for this type of work ("such as indexing"..."minutes or hours").

How long it takes is only one aspect of it. Other clues from the documentation:

Utility: "typically have a progress bar that is visible to the user. Focuses on providing a balance between responsiveness, performance, and energy efficiency."
Background: "isn't visible to the user. Focuses on energy efficiency."

The way I read it, Background is intended for tasks that don't make a significant difference to the functionality of the software. An example might be face detection in the Photos app; as long as it is not finished, it only affects a small part of the functionality, the rest of the app is perfectly usable. That's not the case for clangd, the software is pretty much not usable without an index.

(How) does this interact with battery vs mains power on laptops?
It seems like there's a common scenario where:

  • the user is on a relatively slow laptop, running off battery
  • the codebase is large, and indexing is unlikely to finish within an editing session

In this case, it seems like only using efficiency cores is what you'd want, and that people are likely to be upset if clangd 15 keeps their performance cores running at all times.

I can only speak for myself here: I'm a laptop user myself, and I work on battery the majority of the day; but I still wouldn't trade indexing speed for saving battery. The clangd index is so essential for my work that I always want it to be available as quickly as possible.

Reading the docs it seems like background is the intended QoS for this type of work ("such as indexing"..."minutes or hours").

How long it takes is only one aspect of it. Other clues from the documentation:

Utility: "typically have a progress bar that is visible to the user. Focuses on providing a balance between responsiveness, performance, and energy efficiency."
Background: "isn't visible to the user. Focuses on energy efficiency."

The way I read it, Background is intended for tasks that don't make a significant difference to the functionality of the software. An example might be face detection in the Photos app; as long as it is not finished, it only affects a small part of the functionality, the rest of the app is perfectly usable. That's not the case for clangd, the software is pretty much not usable without an index.

See also Argyrios's comment - I think the main problem is it competes with Spotlight indexing and disk backups. Maybe we'd want to keep this customizable though e.g. via a clangd flag?

My recommendation is that indexing belongs to 'utility', as @stefanhaller mentioned the user is actively depending on functionality coming from the index.
That said, you may want to consider dynamically switching to background if running on laptop with battery, or other heuristics, but that could be a follow-up enhancement, I don't think always using 'background' is appropriate.

That said, you may want to consider dynamically switching to background if running on laptop with battery, or other heuristics,

My take on this is that it would be Apple's responsibility to add a QoS class that has this behavior. I don't think it makes sense for every application to implement this logic client-side.

OK, so wanting this to be utility makes sense, and maybe/probably it should be the default.

I'm still concerned some users will find this a large regression and we won't have a good workaround:

  • it'll use a lot more battery than before
  • not everyone will see the background index as so critical
  • I think our only advice can be to disable background indexing entirely

What do you think about keeping Background in the enum along with Low, and switching clangd to Low?
I'm happy to do the plumbing to add a flag to clangd, and to implement Low for other OSes.
(Digging into windows, it looks like the background mode there is also much slower).

@kadircet any opinion here?

I'm still concerned some users will find this a large regression and we won't have a good workaround:

  • it'll use a lot more battery than before

On Intel Macs, I'm not sure that's true. While it does saturate the CPUs noticeably more with Utility than it does with Background, it will also be finished much quicker, so I guess the total power consumption will probably be roughly the same.

On M1 Macs, it's true that it will use a lot more battery. However, M1 Macs are also much more energy efficient in general, so it doesn't matter nearly as much. I don't think it will be perceived as a regression there.

(On the contrary, people who switch from Intel to M1 Macs perceive it as a regression that indexing is so slow, even though the machine should be so much faster. I have plenty of colleagues who are in that situation, and have heard this complaint several times.)

What do you think about keeping Background in the enum along with Low, and switching clangd to Low?

Personally I don't feel this is necessary, but I can of course change the patch if there's agreement that that's what we should do.

I agree that clangd's indexing should probably be higher priority than whatever FS indexing is going on (because clangd's indexing only start when user actually starts working on a project, hence this indicates some level of "interactiveness"). so I feel like the right default is Utility, rather than Background.
But we had this behavior for a long while and people didn't complain up until M1s. So this is definitely going to result in some behavior change for intel users, even if we agree on this is making the state better for M1s.
Unfortunately I am not in a position to say what does the Utility vs Background imply for intel chips for sure, to tell the behavior change isn't going to be a regression. If this renders next clangd unusable by intel mac folks, it would be really unfortunate.

So I am also in favor of keeping the Background and switch the default in clangd to Low, while providing a flag to turn this back into Background. Hopefully we can retire the flag in between.

Updated the patch to have both Background and Low

As discussed, we provide both Background and Low now, with Low being the
default; Linux and Windows still implement both the same (as Background), this
could be changed as a followup, as I didn't feel comfortable touching these.

sammccall accepted this revision.May 6 2022, 2:34 AM

Thanks a lot, this version looks good to me and I'll follow up with a flag for clangd.

I'm still concerned some users will find this a large regression and we won't have a good workaround:

  • it'll use a lot more battery than before

On Intel Macs, I'm not sure that's true. While it does saturate the CPUs noticeably more with Utility than it does with Background, it will also be finished much quicker, so I guess the total power consumption will probably be roughly the same.

Yes, the issue is with workloads where it doesn't finish during the editor session, e.g. because indexing the full project takes hours.

clang/tools/libclang/CIndex.cpp
9028–9030

There's a mismatch between name and behavior here.

Could you add a comment explaining that setThreadBackgroundPriority name is for historical reasons, but Low is more appropriate?

llvm/include/llvm/Support/Threading.h
236

nit: I'd drop "try to" from each of these.
The failure modes are to do with set_thread_priority rather than the enum, so the comment belongs there if at all (I think the return type covers it though).

llvm/lib/Support/Unix/Threading.inc
259

Maybe add a FIXME: consider SCHED_BATCH for Low?

llvm/lib/Support/Windows/Threading.inc
122–124

maybe add a FIXME: consider THREAD_PRIORITY_BELOW_NORMAL for Low?

  • Added a comment to setThreadBackgroundPriority
  • Improved comments for ThreadPriority enum
  • Add FIXME comments for Windows and Linux
stefanhaller retitled this revision from Use QoS class Utility for ThreadPriority::Low on Mac to Add ThreadPriority::Low, and use QoS class Utility on Mac.May 6 2022, 3:02 AM
stefanhaller edited the summary of this revision. (Show Details)

@sammccall I addressed your last change requests with a revised patch, do you want to have a final look?

Also, I don't have commit rights, could somebody please land this for me once everybody is happy with it?

Looks great! I'm happy to land it, will do so on Tuesday unless anyone has further comments.

Looks great! I'm happy to land it, will do so on Tuesday unless anyone has further comments.

@sammccall Just a friendly ping, in case you forgot. 😄

Looks great! I'm happy to land it, will do so on Tuesday unless anyone has further comments.

@sammccall Just a friendly ping, in case you forgot. 😄

Sorry about that! Landed now :-)