9

A very concise question: How do I prove with a simple test, that setting:

android.os.Process.setThreadPriority(int); 

actually works?

The reason I post this question is mainly generic, as I can't find a simple test that I can replicate.

Further reading:

It is important to me and my application specifically, as it captures audio, which must be the priority. The audio data is also written to a file as well as being analysed for its properties, which is of less importance - Therefore I don't require these tasks to be 'truly simultaneous'.

In my audio thread, I set:

Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);

I can simply test the above has 'applied' by checking before and after:

Process.getThreadPriority(Process.myTid());

However, my need for a test is due to the documentation, which states:

Standard priority of the most important audio threads. Applications can not normally change to this priority.

Despite the log output showing the priority changed to -19, my concern, raised by the wording in the documentation, is that the System may not allow a value of -19 for a normal application at the time of execution and it is possibly reserved for System applications only?

If the above is true, I wonder how I could simply prove what happens to this priority value - Is it defaulted to the maximum permitted, or could it be ignored completely?

In regards to the actual test itself, I've experimented with loops and pauses, but without success and I don't trust the results of the attempts I've made. I'm also aware that the behaviour is OS dependent, so perhaps I cannot replicate a stand-alone Java test of which I've failed to find any upvoted examples?

Hope someone can help. Thanks in advance.

EDIT - Further to the initial answers, I do appreciate that the behaviour may not be what I want or expect. I'd like the actual physical test of this please, rather than an explanation of possibilities.

The test would consist of multiple threads running with different priorities and the order they complete in printed out to the log, nothing more complex than that. My attempts were seemingly over-complex, hence I'm asking for assistance here.

Community
  • 1
  • 1
brandall
  • 6,094
  • 4
  • 49
  • 103
  • You can't prove that it "works" unless you know what it means. I don't now what it means in Android specifically, but in most non-real-time operating systems, it's meaning is rather soft: Something along the lines of, If two threads are competing with one another for CPU time, the one with the higher 'priority' will get a larger share of time. But note! If your test does not have more runnable threads than your hardware has CPU cores, then the threads won't actually be _competing_. – Solomon Slow Jun 24 '16 at 14:16
  • @jameslarge The maximum number of cores I've seen on an Android device is 4, and the number online `Runtime.getRuntime().availableProcessors()` so I hope that won't be an issue. – brandall Jun 24 '16 at 15:10
  • The best you can do with a unit test is verify that your app sets the correct priority value. With an integration test, you could verify that your app set the value, then (presumably) retrieve the priority value from the OS and confirm that it was set. – DwB Jun 28 '16 at 15:50
  • @DwB but I could run tests at different priorities and, all things being equal, see which priority levels of other threads it finished in-between – brandall Jun 28 '16 at 15:52
  • All this discussion has led me to ask for some clarification. Why do you care about the priority at all? What undesirable behavior are you trying to avoid by setting the priority? If you can answer this, you can start to think about how to specify in quantitative (in other words, testable) terms what you're looking for. – eh9 Jun 30 '16 at 12:45
  • @eh9 performance on Android, my application is complex. I believe you may be overthinking things. The test would fail if the threads didn't finish in their priority order. Job done. I need nothing more. – brandall Jun 30 '16 at 14:23
  • Ah. Well, you can't get a guarantee that threads finish in priority order in a non-real-time OS such as Android. – eh9 Jun 30 '16 at 14:39
  • @eh9 how would you prove that........... – brandall Jun 30 '16 at 14:40
  • To prove that it's not reliable, all you do is run a simple-looking test until it fails. It might never fail if the system is lightly loaded, though. It might also never fail if the tests are the only thing running; you might need background load as well (mimicking real-world use). – eh9 Jul 04 '16 at 16:08
  • @eh9 that's what I'm after. Once I have the test, I can run it under any variable conditions, that I set or mimic. – brandall Jul 04 '16 at 16:19
  • @brandall After five years, have you experienced any problem with this? The "Applications can not normally change to this priority" statement also confuses me because all my devices work as intended.. – Jenix Apr 21 '21 at 09:13

3 Answers3

4

Answer: You can't. If the test you're looking for works, it's not simple. If the test you want is simple, it can't work.

Android is not considered a "real-time" operating system, where guarantees about priority are hard (i.e. guaranteed and reliable) rather than soft (i.e. advisory and only largely honored). In a RT O/S, you could write a simple test that evaluated a race condition with one high priority thread and one low priority thread, and this test would evaluate deterministically. On a non-real-time OS, you'll only get a statistical guarantee. And that means you need a statistical test, which doesn't pass the criterion of simple. A statistical test, however, can be generic. Write a test harness that runs a test N times and passes the test based on some threshold value less than N.

But even setting up a base test isn't simple. As a rule, scheduling priority only matters when the machine is running at load, that is, when there's not enough CPU to go around. So to set up your test, you need to be running something that will swamp the CPU; you might as well mine bitcoin to make sure your process is running. In case this isn't obvious, count mining attempts rather than successes. Beware of voluntarily yielding to the OS too easily (wait calls) and operations that can optimized out by the compiler (simple loops).

Once you've set up your base load, you can then set your high-priority thread. It also needs to actually do something in order to verify that it's running at high priority, so you might as well mine bitcoin in this thread as well. If this thread is running at higher priority, you should get a higher count for some given duration in the higher priority thread over the lower one.

But you might not. Since you're not on a RT OS, you'll only get higher counts (presumably) most of the time. If the duration is too small, you'll be subject to the typical duration of the scheduler. So you'll likely need to do some experimentation to determine what minimum duration yields something of consistent answers.

This kind of experimentation is not simple. You're not on a RT OS, so what priority means is very fuzzy. It's (almost certainly) not documented, and so the meaning of the priority numbers is arbitrary. How the scheduler uses these priority numbers is whatever they want. There may be magic thresholds, for example. If there's a priority that means "never interrupt; only wait for a yield" and you run a process that doesn't yield, you'll hang the machine. Since these priority numbers can mean anything, you'll need to find out something of what they mean in practice in order to make your tests meaningful.

All this should be a hint about why there's a market for embedded real-time operating systems. Sometimes you need timing guarantees, and when you do, you should not use a non-real-time OS, even if it's tempting.

eh9
  • 7,340
  • 20
  • 43
  • Thank you for your answer - I do appreciate the pitfalls, but it is the physical **test** that I am after. – brandall Jun 28 '16 at 15:50
  • One of the things I'm saying in my answer is that your question is horribly underspecified. On a non-real-time OS, you can't ask simple questions about priority levels. You have to ask about adequate behavior, and specifying that is far more intricate that a single integer. – eh9 Jun 28 '16 at 16:25
  • I can only set a single integer, therefore the test can surely be no more intricate than that? My question is not asking for clarification on behaviour, it is asking for a test so I can view the behaviour. – brandall Jun 28 '16 at 16:31
  • It certainly is more intricate than that. I've expanded my answer to give some idea why. – eh9 Jun 29 '16 at 13:09
  • I do understand what you are explaining and thank you for expanding. What I really want is a simple test, so I can visualise what you are saying. If the thread priority is ignored, due to the CPU load not being sufficient or other factors, then sobeit - but I'd like to be able to run such a test against the load my code is generating on my multiple test devices, so I can evaluate if another threading approach is required, more complex than just setting the priority. This answer is not upvoted, http://stackoverflow.com/a/37163758/1256219 but it is an example of a basic test. – brandall Jun 29 '16 at 13:28
  • I have no doubt that what you are saying is correct - and I would assume a simple test such as the one above would prove it? Either by the results it outputs, or the over-simplistic nature of it. – brandall Jun 29 '16 at 13:30
  • The linked example isn't a unit test, as your question asks for, since it isn't a predicate (true/false answer) program. It does look like the kind of investigation tool you'll need, though. – eh9 Jun 30 '16 at 12:42
1

What is being tested

The CPU you are running on, has multiple computing units (cores), which can run in parallel.

The operating system has scheduling points (quanta), where it will switch tasks, choosing (through some arcane logic the best threads to execute next.

The operating system has asynchronous resource access. When trying to read from an external device it may :-

  1. Issue a request
  2. Schedule a different thread
  3. Restart the thread after the data is available (possibly immediately, maybe after a quantum expires).

Java the language environment may have further abstractions.

How do I prove with a simple test, that setting: android.os.Process.setThreadPriority(int); actually works?

In order to identify that more processing occurs on the higher priority thread, you need to :-

  1. Ensure that the machine has all its CPU resources tied up.
  2. Ensure that the thing you are testing does not require external asynchronous devices.
  3. Ensure that the test lasts multiple quanta.

Ensure the CPU is tied up

If there are spare CPUs, then code which wants to run, can and will. So the result of tests would show marginal difference between the thread priority, because it didn't matter.

Ensure the test does not require asynchronous IO

If you require writing to a device, the gap for this time would cause you to be driven by the speed of the IO device rather than the thread priority.

Ensure the tests has multiple quanta

The thread priority effects the decision about which thread to schedule next. Given that a thread once executed runs for the whole quanta, and then another schedule decision is made, then the test needs to test multiple of these decisions.

Can thread priority make a difference ?

As Android makes no claims to be a real-time OS, then there is no guarantee, that a thread will have a maximum wait time of X. (The guarantee offered by a real-time OS). However, if a thread is ready to execute (not waiting for devices, or other asynchronous events), then the likelihood is that a high priority thread will start executing in the next quantum.

mksteve
  • 12,614
  • 3
  • 28
  • 50
0

Continuing on where James Large left off, thread priority in Android is more of a suggestive hint to the OS task scheduler, and is completely dependent on the the underlying Android OS. I.E. it may try to provide more resources to higher priority threads but does not guarantee it.

Are you testing on a real device when you change your priority level? While again you can't guarantee that any priority level you set will be respected in terms of resource allocation, if the log output shows a change in priority level, I don't know that you should have any reason to disbelieve it.

gabe3vino
  • 313
  • 1
  • 3
  • 10
  • I don't like to make assumptions - A test would demonstrate the behaviour, hence the question. – brandall Jun 28 '16 at 15:30
  • But if self-report of Process.getThreadPriority(Process.myTid()); isn't sufficient of a test for you, the only way to actually test thread priority is to have conflicting threads run. Which it sounds like you're adverse to doing. But thread priority in Android isn't a property with a deterministic value – gabe3vino Jun 28 '16 at 16:27
  • My question isn't meant to sound adverse to that - that's exactly what I want... A test of conflicting threads, with different priorities set and check the order they complete in. That way I can determine the effectiveness of the audio thread priority mentioned in the question. I'll re-read my question to see if I need to change the wording. – brandall Jun 28 '16 at 16:35
  • Oh I see. I don't know the simplest way to do this in a unit test like form, but I would think that you could set-up some standard test like say sorting a provided list, and then create several threads each with different priorities assigned to them. Concurrently start each thread and have them notify you somehow once they complete. If thread priority is being respected, they should complete in order. But you need to make sure the task is complex enough to require significant resource reallocation and make sure you account for the number of cores vs threads. – gabe3vino Jun 28 '16 at 16:42
  • Agreed, that's exactly what I need! My attempts were becoming over-complicated though... I didn't want to mention in the question extra cores starting under load, to avoid over-complicating! I could always deactivate all but one for the test. – brandall Jun 28 '16 at 16:45