3

Is there a way to create a custom DispatchQueue quality of service with its own custom "speed"? For example, I want a QoS that's twice as slow as .utility.

Ideas on how to solve it

  • Somehow telling the CPU/GPU that we want to run the task every X operation cycles? Not sure if that's directly possible with iOS.
  • This is a really bad hack which produces messy code and doesn't really solve the issue if 1 line of code runs for several seconds, but we can introduce a wait after every line of code.
  • In SpriteKit/SceneKit, it's possible to slow down time. Is there a way to utilize that somehow to slow down an arbitrary piece of code?
  • Blocking the thread every X seconds so that it slows down - not sure if possible without sacrificing app speed
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
  • From https://developer.apple.com/documentation/dispatch/dispatchqos/qosclass. Looks like `.background` should be slower than `.utility` – Suyash Medhavi Sep 09 '22 at 15:41
  • could you explain why you want a slower QOS than `background` – Vikram Parimi Sep 09 '22 at 15:44
  • @VikramParimi Just an example for the sake of the question. – Tamás Sengel Sep 09 '22 at 15:47
  • 1
    "background" is not a speed. It's a quality. Its minimum "speed" is zero (background is not promised to ever run). How would you be "slower" than that? Doing what you're describing would cause the system to schedule a task to do almost no work at all, in which case the scheduling and context switch dominates the cost. What is your actual goal here; what you're describing is inefficient and costly. – Rob Napier Sep 09 '22 at 16:12
  • @RobNapier You're correct (that's why I've put "speed" in quotes), but that's just a really easy way to describe it. – Tamás Sengel Sep 09 '22 at 16:13
  • But it isn't an easy way to describe it. The quality of background is defined as "lowest." There can be nothing lower except "do not schedule at all." Background is already "no promise to schedule." Running "every X cycles" would be dramatically *faster* than background. – Rob Napier Sep 09 '22 at 16:13
  • @RobNapier I've changed .background to a higher QoS (.utility) more which has a promise to schedule, hope that clears up things. Basically, my goal is the following: let's say there is a function which runs for 10 seconds on average when using .utility, I want to make it so that it runs for 20 seconds on average. – Tamás Sengel Sep 09 '22 at 16:17
  • Imo you are solving the wrong problem. If "1 line of code runs for several seconds", then you rather should either make it faster, or reduce how many times you hit that line (or both). For example when dealing with frame-based work, you may want to only process every X frame, or make frame processing rate slower if you see that your "work queue" grows. – timbre timbre Sep 09 '22 at 16:17
  • @khjfquantumjj Here's an example, hope that makes it easier to understand. Let's say I need to run a function every 1 second. With .utility, it runs for 0.5 seconds on average, but the CPU overheats and I want to make it slower so that it runs for 0.8 seconds on average. – Tamás Sengel Sep 09 '22 at 16:19
  • As for "slow down an arbitrary piece of code" - depends what you mean by that. Is `DispatchQueue.whatever.asyncAfter` technically slows down your code, since it runs it later. You can also "burden" your app with some busy work on CPU, and by that slow it down. – timbre timbre Sep 09 '22 at 16:21
  • @khjfquantumjj "DispatchQueue.whatever.asyncAfter technically slows down your code, since it runs it later." - sure, but that doesn't solve the overheating issue. "You can also "burden" your app with some busy work on CPU, and by that slow it down." That would make the overheating issue even worse. – Tamás Sengel Sep 09 '22 at 16:22
  • @TamásSengel so what I am saying, trying to control the speed of execution is a wrong approach. Try to control amount of work instead. If you send 1 task that runs 0.5 sec, CPU won't overheat. It will overheat if you sending tasks constantly so that CPU has to handle them one after the other non-stop. So don't send that much work to CPU. Instead, control the rate at which you create the intensive tasks – timbre timbre Sep 09 '22 at 16:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/247923/discussion-between-tamas-sengel-and-khjfquantumjj). – Tamás Sengel Sep 09 '22 at 16:25

2 Answers2

3

Technically you cannot alter the speed on the QoS such as .background or .utility or any other Qos.

The way to handle this is to choose the right QoS based on the task you want to perform.

The higher the QoS is, the more resources the OS will spend on it and descends when you use a lower one.

Vikram Parimi
  • 777
  • 6
  • 29
3

There is no mechanism in iOS or any other Cocoa platform to control the "speed" (for any meaning of that word) of a work item. The only tool offered us is some control over scheduling. Once your work item is scheduled, it will get 100% (*) of the CPU core until it ends or is preempted. There is no way to be asked to be preempted more often (and it would be expensive to allow that, since context switches are expensive).

The way to manage how much work is done is to directly manage the work, not preemption. The best way is to split up the work into small pieces, and schedule them over time and combine them at the end. If your algorithm doesn't support that kind of input segmentation, then the algorithm's main "loop" needs to limit the number of iterations it performs (or the amount of time it spends iterating), and return at that point to be scheduled later.

If you don't control the algorithm code, and you cannot work with whoever does, and you cannot slice your data into smaller pieces, this may be an unsolvable problem.

(*) With the rise of "performance" cores and other such CPU advances, this isn't completely true, but for this question it's close enough.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610