@mfikes: another interesting discovery
I'm finding that when I issue an 'sh' with a long-running CPU-bound command (5-10 seconds on average), planck itself also uses 100% CPU. That doesn't seem right to me
Any idea why that would happen?
[I have 8 cores and end up using 200/800% during each of these-- 100% for each of planck and the command executed]
@johanatan: Does the command itself emit a lot to stdout?
@mfikes: nope, it's emitting nothing
I agree. That does appear to be odd. There are a few bugs surrounding sh
, this one being the most troubling: https://github.com/mfikes/planck/issues/88
did you try reproducing?
Feel free to log an issue… I plan to continue to work on sh
until it is bug free
Can’t yet (busy)
ahh, ok. i will file an issue. thx!
Thanks!
@mfikes: I filed the issue and am now thinking that I'd like to take a stab at solving it. Do you have any tips/advice for how to approach this one?
@johanatan: Here is where external shell tasks are executed: https://github.com/mfikes/planck/blob/master/planck/PLKSh.m#L117
@johanatan: There is a Wiki page here describing stuff surrounding building Planck: https://github.com/mfikes/planck/wiki/Development
ahh, this is the problem
"polls the current run loop until the class exits"
Other than that, it is using a fairly standard-looking way to launch processes
If there is a better way, perhaps some other mechanism could be used, one that also doesn’t hang like NSTask appears to do
I think it would be better to return immediately and allow the terminationHandler to 'wake' us back up: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTask_Class/#//apple_ref/occ/instp/NSTask/terminationHandler
Give it a shot 🙂 There are definitely issues with the way it is currently being done.
Ok. 🙂
I'm super-confused by these lines: https://github.com/mfikes/planck/blob/0dee6638aa7487f251042dce5418324ccd738b4a/planck/PLKClojureScriptEngine.m#L200-L202
How is that even valid Objective-C?
[Also throughout the file]
Oh, nevermind.
I see the close square bracket corresponds to line 172
🙂 Obviously I don’t give much concern about the gracefulness of that code
Haha, yea
It is all just a means to make ClojureScript available 🙂
Do you have any example in the code where an async method call from JS -> Obj-C -> JS is performed?
[i.e., an Obj-C func that accepts a JS callback]
That's probably what we'd have to do here I think.
I think perhaps the timer callbacks are the only place
If planck.shell/sh
gains async, we’d have to figure out a way to support the older sync interface, and also, play the same trick to keep Planck processing alive when there are outstanding async tasks
Actually I just thought of a simpler solution
[for sync only]
So, just replace the call to 'waitUntilExit' (which stupidly polls killing the CPU) with use of dispatch_semaphore
.
We'd still be 'blocking' but we wouldn't eat the CPU up while doing so. 🙂
Worth a try
[but yes going forward when the time is right for async, i think we'd want to follow the pattern of the timers on the js -> objc bridge side of things and use core.async/andare on the JS side]
Ok, I'll give it a shot. Pretty sure it will work.
Maybe there’s a slight chance something like that will fix #254
The real problem (apart from hogging some CPU) is the inexplicable hanging that occurs if you try to use Planck to, say, run something that does a maven build or lein build, which makes it hard to use Planck to automate dev stuff
(That’s #88)
Bummer.
These changes didn't help the CPU usage:
Jonathans-MacBook-Pro:planck jonathan$ git diff
diff --git a/planck/PLKSh.m b/planck/PLKSh.m
index 4e4b8b1..9387b26 100644
--- a/planck/PLKSh.m
+++ b/planck/PLKSh.m
@@ -111,11 +111,17 @@ NSDictionary* cljs_shell(NSArray *args, id arg_in, NSString *encoding_in, NSStri
[errData appendData:data];
[errLock unlock];
}];
-
+
+ NSLog(@"doing semaphore thingie\n");
+ dispatch_semaphore_t sema = dispatch_semaphore_create(0);
+ aTask.terminationHandler = ^(NSTask *task) {
+ dispatch_semaphore_signal(sema); };
+
// We'll block during execution
@try {
[aTask launch];
- [aTask waitUntilExit];
+ dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+ NSLog(@"done doing semaphore thingie\n");
}
@catch (NSException *exception) {
return @{@"exit": @(-1),
Looks like internally that method dispatch_sempahore_wait
also polls 😮
[According to 'Barry' on this page: http://stackoverflow.com/questions/4326350/how-do-i-wait-for-an-asynchronously-dispatched-block-to-finish , quote: "Yep, this is ghetto polling that will murder the battery" lol