thread_policy_set(1) returned 46

Hi there,

Recently we have been seeing thread_policy_set(1) returned 46 flooding our log output. We tracked down that the flood of this is coming from a separate library whom we've contacted.

They mentioned that this is a Apple internal message that comes up in the library's deadlock detector. The proposed solution was to use OS_ACTIVITY_MODE env var to hide the logs as suggested from the post on StackOverflow..

I tried all suggestions from that StackOverflow post, which were able to hide other system logs generated from Apple but it specifically did not hide the thread_policy_set(1) returned 46

What I am hoping to understand is:

  1. Why does this message come up? I see that the documentation for this on Apple's docs is very limited.
  2. Is this message's visibility controllable via a separate variable in project settings outside of modifying settings for all logs?
  3. As a last resort, how can I disable only this log message?

Thank you!

flooding our log output

By log output I presume you’re talking about the console pane in Xcode when you run the app under the debugger?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I don’t think that these log messages are is coming via the unified logging system; rather, I suspect that someone is printing them to stdout or stderr. I’d like to confirm that before we go further:

  1. Add the code below to your app’s main.

  2. Run the app in a way that would normally trigger this problem.

  3. Do you see these log messages?

  4. Don’t forget to remove that code from main when you’re done!

int fd = open("/dev/null", O_RDWR);
assert(fd >= 0);
BOOL success = dup2(fd, STDOUT_FILENO) >= 0;
assert(success);
success = dup2(fd, STDERR_FILENO) >= 0;
assert(success);

If this suppress the log messages, remove the dup2 to stderr. Do you still get the log messages? That’ll tell you whether they’re coming via stdout or stderr.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn,

This was super helpful, I confirmed via the code you linked that the log messages are coming from stderr.

the log messages are coming from stderr.

Cool. You can now set a symbolic breakpoint on fprintf to see who’s printing it and get a backtrace of how you got there.

Oh, and if you find this coming from Apple code then it’s definitely bugworthy. It’s very likely to be log noise but, even if it’s not, such logging should go via unified logging not stderr.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Alright looking at the backtrace for this I believe this log is coming from Apple, specifically com.apple.coremedia.JVTlib,

Please let me know if I can provide a different output format

libsystem_c.dylib`fprintf:
->  0x1800c4878 <+0>:   sub    sp, sp, #0x40             ; =0x40 
    0x1800c487c <+4>:   stp    x22, x21, [sp, #0x10]
    0x1800c4880 <+8>:   stp    x20, x19, [sp, #0x20]
    0x1800c4884 <+12>:  stp    x29, x30, [sp, #0x30]
    0x1800c4888 <+16>:  add    x29, sp, #0x30            ; =0x30 
    0x1800c488c <+20>:  mov    x19, x1
    0x1800c4890 <+24>:  mov    x20, x0
    0x1800c4894 <+28>:  add    x8, x29, #0x10            ; =0x10 
    0x1800c4898 <+32>:  str    x8, [sp, #0x8]
    0x1800c489c <+36>:  adrp   x8, 360430
    0x1800c48a0 <+40>:  ldr    x0, [x8, #0x7d8]
    0x1800c48a4 <+44>:  adrp   x21, 360430
    0x1800c48a8 <+48>:  add    x21, x21, #0x210          ; =0x210 
    0x1800c48ac <+52>:  cmn    x0, #0x1                  ; =0x1 
    0x1800c48b0 <+56>:  b.eq   0x1800c48c0               ; <+72>
    0x1800c48b4 <+60>:  bl     0x1800ff3fc               ; symbol stub for: pthread_getspecific
    0x1800c48b8 <+64>:  cmp    x0, #0x0                  ; =0x0 
    0x1800c48bc <+68>:  csel   x21, x21, x0, eq
    0x1800c48c0 <+72>:  ldr    x3, [sp, #0x8]
    0x1800c48c4 <+76>:  mov    x0, x20
    0x1800c48c8 <+80>:  mov    x1, x21
    0x1800c48cc <+84>:  mov    x2, x19
    0x1800c48d0 <+88>:  bl     0x1800caf24               ; vfprintf_l
    0x1800c48d4 <+92>:  ldp    x29, x30, [sp, #0x30]
    0x1800c48d8 <+96>:  ldp    x20, x19, [sp, #0x20]
    0x1800c48dc <+100>: ldp    x22, x21, [sp, #0x10]
    0x1800c48e0 <+104>: add    sp, sp, #0x40             ; =0x40 
    0x1800c48e4 <+108>: ret   

Please let me know if I can provide a different output format

I’d like to see the full backtrace. To do that, go to the Xcode console (View > Debug Area > Activate Console) and run the bt (backtrace) command. For example:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000100002868 MyTool`main() at main.swift:12:11
    frame #1: 0x0000000100002859 MyTool`main at main.swift:15:1
    frame #2: 0x00000001000154fe dyld`start + 462

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Here's the full backtrace, I printed this out at a few different occurrences of the log and it appears they all have the same backtrace,

* thread #51, name = 'com.apple.coremedia.JVTlib', stop reason = breakpoint 2.3
  * frame #0: 0x00000001800c4878 libsystem_c.dylib`fprintf
    frame #1: 0x00000001c9462d8c H264SW.videocodec`set_affinity_tag + 108
    frame #2: 0x00000001c94626a8 H264SW.videocodec`ThreadedBatchSlaveMain + 48
    frame #3: 0x00000001c99ce68c libsystem_pthread.dylib`_pthread_start + 116

Yeah, that’s definitely Apple’s code. I’d appreciate you filing a bug about this message. Either we shouldn’t log that error or, if it’s important to log it, we should log it using unified logging.

Please post your bug number, just for the record.

I’ve filed my own bug about the outdated terminology in frame 2 (r. 88894155).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I'm using the WebRTC framework with the H.264 codec in my iOS app and see this log spam in the simulator. I have the same backtrace.

I didn't see a bug filed above so I've filed FB9910079.

I have the same problem

I met the same problem too

Same problem here trying to set the affinity mask/hint. What is return code 46? Is Apple trying to prevent use of this API on iOS? The macOS side correctly returns 0.

We're using the following code as per Apple's documentation. It doesn't for for any mask value. This is good as we can do without real affinity support, and just hint and hope.

thread_affinity_policy_data_t policy = { (int)( mask & 0xFFFFFFFF ) };
		int rc = thread_policy_set( pthread_self(), THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1 );

What is return code 46?

Error 46 is likely to be EPFNOSUPPORT. Admittedly that’s a weird choice — I would’ve gone for 45, ENOTSUP — but I think the meaning is pretty clear.

Is Apple trying to prevent use of this API on iOS?

I’d say that Apple is trying to discourage folks from using this API on any platform. Quoting from the <mach/thread_policy.h> header:

 * This policy is experimental.

That’s a shaky foundation on which to build a shipping product.

Note that the source of the log message which kicked off this thread is a component within the system itself. The system has more leeway in this regard because the components are revlocked: If one changes, the other can change to match. Third-party developers have to be more cautious.

We're using the following code as per Apple's documentation.

Please point me to where you saw that in the docs.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I have no idea where to find 46 is not supported, but thanks as always Quinn. You are super helpful. I guess it's from sys/errno.h.

What is the alternative? QoS control isn't even remotely the same as affinity. The system will always have higher and QoS levels unavailable to us, so the system should always be responsive even if we use affinity in game. At least Android has affinity control, and it hasn't destroyed the platform.

And when you're building a game, and want to run jobs consistently on cores and monitor them in captures, then not having any affinity control on macOS or iOS is a problem. We use affinity control for cores on all products except Apple's, and the workarounds for this aren't ideal for optimizing performance.

I somehow feel this is like removing dll hotloading on iOS in iOS 12. We used to be able to reload our C++ game code, and now Apple requires the app devs to completely relaunch builds. That kills iteration. Look at Unity or UE4/5 having to do the same. What iOS removed affinity hinting?

This came out in macOS 10.5, and the call is available on iOS. Just seems like the call has been disabled of late. Maybe it's available to set other values, but at this point it's a little late for being experimental.

https://developer.apple.com/library/archive/releasenotes/Performance/RN-AffinityAPI/#//apple_ref/doc/uid/TP40006635-CH1-DontLinkElementID_2

We have 2 big and 4 little cores. The 4 little cores run 2-3x slower than the big. We'd like to prioritize tasks on the big cores and then see those tasks running there. Maybe even ignore the little cores so that we hit our frame rate. There are no scheduler examples from Apple on how to do this. Having 50 queues going to libdispatch also isn't the correct model.

Also we're running iOS builds on macOS M1. Does this call work there?

Apparently M1 macOS doesn't implement this call either, and also returns an error. So iOS on M1 macOS is a failure case too. We'll just let threads run wherever for now, but it's less than ideal.

thread_policy_set(1) returned 46
 
 
Q