Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface
Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface
- Subject: Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface
- From: Jean Suisse <email@hidden>
- Date: Thu, 17 Sep 2015 13:02:48 +0200
> What makes you think that:
>
> (a) this is a lot of activity?
It is not a lot of activity. I am not trying to do performance optimization. Right now, the app is taking 3 % CPU on the latest 13” MBP Retina.
I am trying to find why my app can’t run for two days without exhausting the 16 GB RAM it has.
> (b) your monolithic replacement runs faster than this?
I don’t know, but as long as it runs reasonably I am not sure I care. The MAC is dedicated to the project. There is no user to complain. All I can tell is that there is no visible jump in CPU consumption.
> In design terms, you have two instances of the MVC pattern, not one. You have inputs (V-1) updating a model (M), and you have UI elements (V-2) tracking the same model (M). So you have two design problems: input to model, and model to UI. It’s much harder to try to solve inputs-to-UI in a single coordinated step — nor do I think you need to.
>
> I know nothing of the details of your app, of course, but if, for example, only 20% of the inputs change every second, then suppressing input-to-model updates entirely, at the source, seems like a good approach to performance problems, without involving the UI. Separately, if the overall rate of UI updates is very high (in particular if it’s over 100% per second), then using a timer to limit the model-to-UI update rate sounds like a simple approach, without involving the inputs.
Well, at this point it is better for me to say more.
It is a scientific data acquisition app. Basically, I mad many electronic boards performing various tasks (actuation & measurements mainly). These electronic boards have been incorporated in nice boxes to build what I will call hereafter “instruments”.
These instruments either communicate wirelessly or not, depending on their physical location, and use different protocol (buses, interfaces) according to their nature. All these instruments together allow me to cover a large area and monitor around 150 parameters every second.
The application does that. Of these 150 variables, a little above 100 are displayed on a UI that is refreshed every second.
This in itself is a challenge and I had to add some piece of electronics, work on the (custom) protocol and on the firmware of the boards to get it to work reliably. Especially for the wireless part. One solution was to have distinct data buses (distinct communication interfaces).
Now, this job is done and the design of the app reflects some of these constraints.
First, I have a communication interface server which ensures that there is only one instance representing each data bus connection. Same for the electronic board server. It ensures that that there is only one object for each physical board and communication interface (so dealing with concurrency is dead simple). Then I have actuator objects, sensor objects, instruments objects all requesting their electronic board on their bus to these object servers. I manipulate the instruments objects. Communication follows. Communication is slow. It is expected.
Then, I have one dispatch source that takes care of synchronization & timestamps. Four that trigger data collection from the devices through the 4 buses (1 wireless, 2 RS-485, one GPIB), one that collects measured values during the last cycle, takes care of the processing & on the disk storage. And now, one extra that sync the UI.
Everything works fine with no leaks, except for that last part. This is where the issue lies. The timer dispatch source that syncs the UI is dead simple. It only sends updateUI to each object representing an instruments.
These objects are declared as:
@interface MyInstrument : JSScientificInstrument
{
double aMeasuredValue;
}
@property (readwrite) double theMeasured Value; // IB binding NSTextField with NSFormatter
@end
And implemented as :
- (void)updateUI
{
assert([NSThread isMainThread]);
self.theMeasuredValue = self->aMeasuredValue;
}
Somewhere in those lines is the issue. If I only comment "self.theMeasuredValue = ... “, the issue disappears, despite the fact that I am only transferring a double through a setter bound to the UI.
I believe it is somewhere in the way GCD, appkit, Core Animation, cocoa bindings are implemented. So at this stage I am looking to pinpoint the issue and find a workaround.
> On 16 sept. 2015, at 23:54, Quincey Morris <email@hidden> wrote:
>
> On Sep 16, 2015, at 14:28 , Jean Suisse <email@hidden> wrote:
>>
>> I thought of that at first, to solve the uncommitted CA transactions issues. But the syntax is ugly.
>
> Sure, but in modern Cocoa programming it’s a standard pattern, so it’s not unreasonable to grin and bear it.
>
> (It’s about a million times less ugly in Swift. Just sayin'.)
>
>> And I didn’t want to post blocks from all over the place to the main thread (I have 100+ NSTextfields with number formatters updated every second… meaning as many blocks…).
>
> What makes you think that:
>
> (a) this is a lot of activity?
>
> (b) your monolithic replacement runs faster than this?
>
> Indeed, if the “obvious” approach leads to your app using 100% of a single CPU for days on end, is that a consideration? If so, then what is the allowable threshold? 50% of a CPU? 10%?
>
> That’s what I mean about premature optimization. You don’t really know yet what problem you need to solve.
>
>> The issue, to me, is to get my app to run for a few days without crashing. The only way I have to make it work, currently, is by not updating the UI.
>
> Sorry, I was pontificating a bit in my previous post. I guess I still am.
>
> In design terms, you have two instances of the MVC pattern, not one. You have inputs (V-1) updating a model (M), and you have UI elements (V-2) tracking the same model (M). So you have two design problems: input to model, and model to UI. It’s much harder to try to solve inputs-to-UI in a single coordinated step — nor do I think you need to.
>
> I know nothing of the details of your app, of course, but if, for example, only 20% of the inputs change every second, then suppressing input-to-model updates entirely, at the source, seems like a good approach to performance problems, without involving the UI. Separately, if the overall rate of UI updates is very high (in particular if it’s over 100% per second), then using a timer to limit the model-to-UI update rate sounds like a simple approach, without involving the inputs.
>
>
>
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
References: | |
| >Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Jean Suisse <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Quincey Morris <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Charles Srstka <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, Cocoa bindings & User interface (From: Ken Thomases <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface (From: Quincey Morris <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface (From: Jean Suisse <email@hidden>) |
| >Re: Lost memory, GCD, dispatch sources, ?Cocoa bindings & User interface (From: Quincey Morris <email@hidden>) |