Post

Replies

Boosts

Views

Activity

Reply to CoreHID: Enumerate all devices *once* (e.g. in a command-line tool)
Agreed. For now, I don't think going the AsyncAlgorithms route buys me anything. I now have a working version with my home-made watchdog sub-task. My original intent was to wrap this into a (blocking) non-async method, but I couldn't figure out how to do that since waiting for the result of the (async) sub-task needs an await and that's not allowed in a synchronous method. The second problem was one that only showed up once I tried to wrap this into a (now async) helper method is the reference to the deviceEnumerationTask (line 4 in my post above) from within that task (so the watchdog can cancel that task). If it's a global variable, the task closure doesn't need to capture it, and everything is fine. But if it's a local variable, the closure wants to capture it, and refuses to do so, since it's not yet initialized (the closure is on the right-hand side of the assignment that initializes it). This looks like let outer = Task { let inner = Task { outer.cancel() } } One approach for that that I couldn't get to work was the attempt to avoid the reference to the variable storing the outer task altogether, and instead get it from within the task, but since I want the parent of the inner task, and not the inner task itself, that didn't work. TaskGroup was another idea, since there the watchdog could cancel itself (so wouldn't need a reference to outer), leading (hopefully) to cancelling the outer task / group, but then I'm missing the ability to pause and restart the watchdog, which I've so far done by cancelling its task and replacing it with a new one to restart. So in the end I made outer an optional (so it is initialized during the capture), and that works but makes things kind of ugly since now it's mutable and no longer a let (so I had to put everything in an actor), and of course makes an optional that really cannot be nil but needs to be used.
Topic: App & System Services SubTopic: Core OS Tags:
May ’25
Reply to CoreHID: Enumerate all devices *once* (e.g. in a command-line tool)
The Debounce route is an intriguing idea, but I couldn't quite make it work. First off, to recap for me and everyone else reading along: Debounce will only emit the last element of the sequence once the acquiescence period is reached. That's why Quinn added the reduction to accumulate all events into an array, so the debounce of the sequence of ever expanding arrays will return the last array (with all values up to then) when reaching the acquiescence period (i.e. we're debouncing the array of events, not the events themselves). Unfortunately, I think this doesn't quite work for my use case: Imagine I have no matching devices, which might look like (in the counter sequence) for (i, delay) in zip(0..., [3, 1, 1, 3, 1, 1, 3]) { // for (i, delay) in zip(0..., [1, 1, 3, 1, 1, 3, 1, 1, 3]) { In this case, I would like to receive no elements and stop iteration after the 2 second "timeout". But debounce only "arms" its timer after it has received the first element from the sequence it is debouncing. So it would work if there always it at least once element, but otherwise it will produce nothing / wait forever.
Topic: App & System Services SubTopic: Core OS Tags:
May ’25
Reply to CoreHID: Enumerate all devices *once* (e.g. in a command-line tool)
I've cobbled the following together, which seems quite roundabout, but at least pretends to work. I'm not sure whether the watchdog timer via a a new Task that sleeps is the brightest idea, but I wasn't sure how the [NS]Timer-based stuff would work with async / await. var manager = HIDDeviceManager() let searchCriteria = HIDDeviceManager.DeviceMatchingCriteria(... omitted...) let deviceEnumerationTask = Task.detached { let managerStream = await manager.monitorNotifications(matchingCriteria: [searchCriteria]) var watchDogTask = Task { NSLog("watchdog start") try await Task.sleep(nanoseconds: 10_000_000) NSLog("watchdog kill") deviceEnumerationTask.cancel() } monitorDevice: for try await notification in managerStream { NSLog("watchdog cancel") watchDogTask.cancel() // handle the actual notification here // rearm the watchdog watchDogTask = Task { NSLog("watchdog start") try await Task.sleep(nanoseconds: 10_000_000) NSLog("watchdog kill") deviceEnumerationTask.cancel() } } // for monitor stream } // Task.detached deviceEnumeration // wait for the deviceEnumeration to be done or cancelled try await deviceEnumerationTask.value
Topic: App & System Services SubTopic: Core OS Tags:
May ’25
Reply to How to bind threads to performance (P) or efficiency (E) cores?
Yeah, I've been running as many threads as there are P-cores for my simulations and making sure to never yield. Unfortunately, it isn't always easy / possible to that, so I would still appreciate either a proper core affinity API, or at least a way to opt out of E-cores. The core asymmetry can create quite annoying situations with OpenMP for example where work is equally distributed.
Topic: App & System Services SubTopic: Core OS Tags:
May ’22
Reply to M1 Pro / Max / Ultra Thread Affinity (e.g. in OpenMP) and scheduler core migration
I got a nice explanation from a person in DTS, which I'll briefly summarize here for posterity: The mach_task_self() shouldn't work at all and is wrong (I got the idea from https://codereview.chromium.org/276043002/ where they are used interchangeably). The other call makes it to the right place, but thread affinity is not implemented / supported for Apple Silicon (There the argument was made that "all the cores are basically sharing a single unified cache" which doesn't quite match up with the video describing the 4 P-core to a shared L2 cache arrangement.) And because I always have trouble following XNU dispatching of function calls (especially once the Mach layer gets involved), here's the walk-though of the dispatches: main entry-point task_policy_set(...) https://github.com/apple-oss-distributions/xnu/blob/xnu-8019.80.24/osfmk/kern/thread_policy.c going to thread_policy_set_internal(...) that one asking thread_affinity_is_supported() which comes from https://github.com/apple-oss-distributions/xnu/blob/e6231be02a03711ca404e5121a151b24afbff733/osfmk/kern/affinity.c then dispatching to ml_get_max_affinity_sets() != 0 (which is an architecture specific function) which for ARM says "no sets supported" https://github.com/apple-oss-distributions/xnu/blob/bb611c8fecc755a0d8e56e2fa51513527c5b7a0e/osfmk/arm/cpu_affinity.h and voila, KERN_NOT_SUPPORTED
Apr ’22
Reply to M1 Pro / Max / Ultra Thread Affinity (e.g. in OpenMP) and scheduler core migration
I've filed a DTS (Case ID: 797192903), the repo looks as follows // #include <pthread.h> #include <mach/mach_init.h> #include <mach/thread_policy.h> #include <mach/thread_act.h> #include <iostream> int main (int argc, char const *argv[]) { #ifdef _OPENMP #pragma omp parallel #endif { thread_affinity_policy_data_t policy = { 1 }; // non-zero affinity tag // todo: should release returned port? auto r1 = thread_policy_set(mach_task_self(), THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, THREAD_AFFINITY_POLICY_COUNT); // 4 = KERN_INVALID_ARGUMENT auto r2 = thread_policy_set(pthread_mach_thread_np(pthread_self()), THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, THREAD_AFFINITY_POLICY_COUNT); // 46 = KERN_NOT_SUPPORTED #ifdef _OPENMP #pragma omp critical #endif std::cout << "r1 = " << r1 << " r2 = " << r2 << std::endl; } return 0; } For non-OpenMP compile with clang++ -std=c++11 main.cpp, for the OpenMP version use something like /opt/homebrew/opt/llvm/bin/clang++ -fopenmp -std=c++11 main.cpp -L /opt/homebrew/opt/llvm/lib.
Mar ’22
Reply to Why is clang removing the loop when using -O3?
IIRC The compiler treats the pointer returned by malloc as not having any defined value (it is "poison"), so it can remove your test against any *specific* value (as there were no writes). Then it simply has a matching malloc and free, which can be elided, which leaves a loop with the rng whose results are never used, and thus removed as well.
Jan ’21
Reply to kAudioChannelLayoutTag_TMH_10_2_full has HI and VI channels
I did some googling and my current guess is that these channels contain content for Hearing Impaired (with emphasis on dialog) Visually Impaired (audio description) The mention I found was https://www.isdcf.com/papers/ISDCF-Doc4-Audio-channel-recommendations.pdf, which doesn't seem related to the THM format (but documentation for that seems to be rather sparse) but still related to multi-channel audio.
Topic: Media Technologies SubTopic: Audio Tags:
Dec ’20
Reply to What kind of Apple Developer Certificate is required to create a custom virtual audio device using Core Audio?
From what I can tell (as I'm doing the same thing), you don't need a special entitlement because the AudioServerPlugIn is not an app extension but a completely stand-alone plug-in. Whether that plug-in needs to be signed with a Developer ID (or notarized) I'm actually not sure about (because AudioServerPlugIns are already sand-boxed). FWIW, I'm doing that (i.e. signing it) with a normal (paid) Developer ID and it seems to work for other people, although setting up the whole process if fraught with potential for errors. I'm not distributing via the App Store, but if you were, you'd have to install your plug-in using the normal mechanism (Apple Installer, or maybe manually copying it to /Library/Audio/Plug-Ins/HAL), but I'm not sure that's encouraged (allowed?) for AppStore apps.
Topic: Media Technologies SubTopic: Audio Tags:
Dec ’20