sccn / liblsl

C++ lsl library for multi-modal time-synched data transmission over the local network
Other
115 stars 67 forks source link

[macOS] 100% cpu load when running sample app. #45

Closed CodingMeSwiftly closed 4 years ago

CodingMeSwiftly commented 4 years ago

I'm using the latest release https://github.com/sccn/liblsl/releases/tag/1.13.0-b13 and include the .dylib in my Xcode project as an embedded framework.

Screen Shot 2019-12-16 at 20 40 34

I created a bridging header in oder to be able to use the c library from Swift code.

Screen Shot 2019-12-16 at 20 42 11

I can use the library and invoke lsl_* functions so I assume the lib is linked and included properly in my app target.

However, when I invoke lsl_resolve_all the function does not return and the app consumes 100% cpu.

Screen Shot 2019-12-16 at 21 32 44

I understand that the latest release is targeting macOS 10.12. I'm running 10.15(.1). Is that the problem? If so, why are some functions of the lib working just fine but lsl_resolve_all hangs the app? Any idea on how to resolve this?

CodingMeSwiftly commented 4 years ago

Curious thing I found while trying to resolve the issue: If I clone the repo and build the lib on my machine, the resulting .dylib file is 1.6MB. The .dylib downloaded from the release page linked above is 1.3MB.

Nevertheless, the issue is still there when I try the lib built on my machine.

cboulay commented 4 years ago

It's not that surprising that the .dylib's are different sizes. The release one is targeting an older MacOS and is built by a CI, using whatever dependencies the CI pulls in.

FYI, when you create a stream info, that doesn't create the stream, just the metadata. The stream isn't created until you create the outlet. So I don't know if it's what you were expecting, but you wouldn't be able to find "Foo".

Regardless, that shouldn't prevent lsl_resolve_all from returning with no streams found after a timeout.

Just so we can isolate the issue, can you try using lsl_resolve_all in a simple C/C++ app and see if that works for you? If yes then I really don't know what the issue is. I have zero experience with Swift. If no, then there's some more digging we can do together.

CodingMeSwiftly commented 4 years ago

Thank you for the quick response!

Yes the stream info and library info prints are just to verify that the Swift-C interop is working. I'm aware lsl_streaminfo is just the data model for an actual connection point :)

I can verify that the simplest of C / C++ implementations (call lsl_resolve_all in main) work without issues.

I have tried to make more sense out of the cpu overload and captured some backtraces / callstacks of the thread running at 100% cpu usage:

Screen Shot 2019-12-17 at 01 05 26

It seems to me that the call to _lslboost::asio::detail::socketops::bind is the culprit. Whatever the reason might be is beyond me :/

Is it possible that the underlying networking for outlet discovery is using some exotic socket config? I am not really sure if Apple locked some multi- / broadcast or other socket functionality for macOS and iOS apps for "security" reasons :( That could be the reason why a C++ command line tool works, when a signed Cocoa application doesn't :/

CodingMeSwiftly commented 4 years ago

I will build a separate macOS App using Objective-C to make sure the issue is not caused by Swift. I don’t know if it’s appropriate to mention this in this thread (If you want me to open another issue or feature request please let me know): is there any chance the library might get iOS support in the future? I think it should be possible to build for iOS since macOS works, but unfortunately I am very inexperienced with CMake and don’t really know where to start on that. Thanks for your help.

tstenner commented 4 years ago

Is it possible that the underlying networking for outlet discovery is using some exotic socket config?

Not really, the service discovery uses plain UDP sockets + multicast.

I am not really sure if Apple locked some multi- / broadcast or other socket functionality for macOS and iOS apps for "security" reasons.

That's what I suspect, we've had some problems with Macs (#28, #36) but nothing we've been able to reproduce on our local Macs (i.e. Chad's Mac and a spare Macbook I can use from time to time).

In theory, it shouldn't matter what language you call the functions from, except when the Swift runtime somehow restricts the OS functions the C library can call.

There are two things you might try: I've reworked some of the multicast handling to be hopefully more reliable (#31, OS X binaries), maybe it also fixes your problem.

If not, you could capture the actual network packets (sudo tcpdump -i any -n -w test.pcap port 16571 or igmp or icmp6 or icmp or ip6 multicast or so) for the both the working C++ example and an equivalent Swift example.

CodingMeSwiftly commented 4 years ago

Thank you for your answer. I did some more tests and found the following:

Cocoa App in Swift >> 100% CPU Cocoa App in ObjC >> 100% CPU CommandLineTool in C >> Works CommandLineTool in C++ >> Works CommandLineTool in ObjC >> Works CommandLineTool in Swift >> Works

So the issue is definitely not Swift, but rather some quirks within the Cocoa application.

I tried to capture the tcpdump. It works fine for CommandLineTool applications. For Cocoa Apps, the resulting .pcap file is Zero KB. No idea what that could mean.

Further, I have verified that App Transport Security - https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity - which is the only networking constraint for macOS and iOS apps I can think of from the top of my head, is not causing the issue. I.e.: If I turn it off, the issue is still there.

CodingMeSwiftly commented 4 years ago

Well, this is a bit embarrassing...

The "quirk within the Cocoa application" was a checkbox in the Capabilities section of the Xcode project.

Screen Shot 2019-12-17 at 10 40 18

I had to enable Outgoing Connections for the App Sandbox. For whatever reason Xcode did not produce and error and inform me about the missing capability, but rather choked the CPU ...

Well it's working now. Thank you for your time and help.

I don’t know if it’s appropriate to mention this in this thread (If you want me to open another issue or feature request please let me know): is there any chance the library might get iOS support in the future? I think it should be possible to build for iOS since macOS works, but unfortunately I am very inexperienced with CMake and don’t really know where to start on that. Thanks for your help.

Is there any chance this might get addressed in the future? :)

tstenner commented 4 years ago

is there any chance the library might get iOS support in the future?

Sure, and I don't mean that someone buys me a fancy Macbook Pro) :-)

CMake can cross-compile if it's told which compiler + settings to use. For iOS, there's a toolchain configuration that should suffice, but so far no-one has tested it yet. If that's not working, you should get a more or less helpful error message to create a new issue with.

CodingMeSwiftly commented 4 years ago

Ok thanks for the info and all the help. Very much appreciate it :) I'll close the issue.

tstenner commented 4 years ago

Just for the record: the current implementation has an infinite loop in case no port can be bound to so I fixed it (cdce3aaf2044fa823beb7cac0e3ec376f1c7d78c).