MathGroup Archive 2007

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Re: Avoid slow initialization of DynamicModule

  • To: mathgroup at smc.vnet.net
  • Subject: [mg84482] Re: [mg84467] Re: [mg84436] Avoid slow initialization of DynamicModule
  • From: John Fultz <jfultz at wolfram.com>
  • Date: Fri, 28 Dec 2007 04:10:57 -0500 (EST)
  • Reply-to: jfultz at wolfram.com

Well, this isn't quite encapsulated.  Consider...

In[1]:= Module[{img}, img]

Out[1]= img$380

Here's a case where the implementation of Module[]'s scoping ends up leaving=
 a 
bread crumb.  And this permanently remains in the namespace...

In[2]:= Names["Global`img*"]

Out[2]= {"img", "img$380"}

Turns out that something very similar happens if you use a Module variable 
inside a Dynamic that is in the body of that Module...

(* The DynamicModule here is unnecessary...just added it to make it similar=
 *)
(* to your example *)
In[3]:= Module[{img = 1}, DynamicModule[{x = 1}, Dynamic[img x]]]

(* note that DynamicBox has img$701, a Module variable *)
Out[3]= \!\(\*
DynamicBox[
   ToBoxes[$CellContext`img$701 $CellContext`x$$, StandardForm],
ImageSizeCache->{7., {0., 8.}}]\)

(* and sure enough, it shows up here, too *)
In[4]:= Names["Global`img*"]

Out[4]= {"img", "img$380", "img$701"}

Sincerely,
 
John Fultz
jfultz at wolfram.com
User Interface Group
Wolfram Research, Inc.


On Wed, 26 Dec 2007 05:10:10 -0500 (EST), Thomas Muench wrote:
> Dear John,
>
> Thank you for your detailed reply, you suggestion worked like charm.
> It is quite unexpected behavior at first, but when thinking about it,
> it makes sense.
>
> I changed your code a little bit to restore the encapsulation, because
> I really did not like the idea that you have to load your image data
> into a given variable named "img", and that the program would fail any
> other way. It is quite simple:
>
> stratification[image_]:=
> Module[{img=image},
> DynamicModule[.... same code as before....]
> ]
>
> You can now call the function with
> stratification[whatever]
>
> and it will work. The only disadvantage is that the data will now be
> in memory twice, namely as "img" (in the Module) and as "whatever" (as
> global variable). For really *very* large image data that consumes to
> much memory on my laptop for the kernel to survive. But other than
> that it is fine.
>
> Thank you again very much
>
> thomas
>
> On Dec 25, 2007 6:47 AM, John Fultz <jfultz at wolfram.com> wrote:
>> I'm happy to see users such as yourself creating such impressive
>> interfaces with
>> Mathematica.  What you've done here is very nice, and does a great job
>> of
>> exploiting the new version 6 features.
>>
>> As to the source of your problems, you can forget any inherent overhead
>> in
>> Dynamic.  The system scales extremely well, and the overhead it
>> introduces is
>> trivial.  The principle sources of the typical Dynamic troubles have to
>> do with
>> what the Dynamic is evaluating.  The problems I often see are...
>>
>> * Dynamic has dependencies on too many variables which are triggering
>> too often.
>> So the Dynamic recomputes much more often than necessary.  This is the
>> problem
>> which can lead to 100% CPU usage despite the fact that the Dynamic
>> doesn't
>> appear to change (i.e. it keeps recalculating the same result over and
>> over
>> again).
>>
>> * Dynamic is given more to compute than necessary, making every
>> triggered
>> Dynamic too expensive to compute.
>>
>> * The computation Dynamic is given just requires too much time, and
>> keep the
>> front end and/or kernel in limbo while it's computing.
>>
>> You've set up your interface pretty well, and have avoided these
>> problems.  But
>> due to the scale of your data, another factor is coming into play which
>> is rare
>> in most other Dynamic examples.
>>
>> When Mathematica sends a very large result from the kernel to the front
>> end,
>> things can start to really slow down and consume a lot of memory.  Each
>> of the
>> following contributes to that slowdown, both due to computational
>> overhead and
>> memory consumption (which contributes to memory page faults)...
>>
>> * The kernel code which creates the typeset form of the expression
>> * The transmission of the result over MathLink
>> * The creation and representation of the result in the front end
>>
>> Your example unwittingly exposes the worst possible behaviors for all
>> three of
>> the above cases.  When you do...
>>
>> img=<large thing>
>> stratification[img]
>>
>> By default, this actually executes as...
>>
>> stratification[<large thing>]
>>
>> which is no problem for the kernel.  But because of the way that
>> function
>> variable replacement works, this eventually becomes, e.g....
>>
>> Dynamic[ListLinePlot[<large thing>]] (*I'm simplifying your code
>> slightly here*)
>>
>> which then typesets into...
>>
>> DynamicBox[MakeBoxes[ListLinePlot[<large thing>], StandardForm]]
>>
>> which is then sent, in its entirety to the FE.  The process of creating
>> the
>> DynamicBox[] is very expensive because of <large thing>, and then
>> <large thing>
>> is sent to the FE to be represented inside the Dynamic.  Then the FE
>> sends
>> <large thing> back to the kernel in the evaluation of ListLinePlot, and
>> the
>> kernel finally sends the much more moderately-sized resulting graphic
>> back.  It
>> is as if you took <large thing> and copied and pasted it directly in the
>> definition of 'stratification'.  Of course, this is even worse because
>> <large
>> thing> shows up in three separate Dynamics (the ListLinePlot, the main
>> Raster,
>> and the list of slice Rasters).
>>
>> To illustrate the point, as well as show a very simple workaround,
>> here's a very
>> simple change to make.  Change...
>>
>> stratification[img_]:=
>>
>> to
>>
>> stratification[image_]:=
>>
>> but do *not* change any of the references in the body of
>> stratification.  Assign
>> your source data to 'img' as you did in this email and re-evaluate
>> everything in
>> a fresh kernel.  Now, instead of 'img' being replaced as a function
>> variable, it
>> will be used a global variable.  Now, the evaluation will be...
>>
>> Dynamic[ListLinePlot[img]]
>>
>> which will typeset into
>>
>> DynamicBox[MakeBoxes[ListLinePlot[img], StandardForm]]
>>
>> and what will be sent to the FE will be no more than the 3 bytes of the
>> variable
>> name 'img' (plus another several bytes to qualify that it's in the
>> Global`
>> context).  Then, the FE will evaluate
>>
>> ListLinePlot[img]
>>
>> and the value of img will never have been sent to the FE...only the
>> graphic
>> resulting from ListLinePlot[img].  And, in your example, this will
>> actually be
>> much smaller because you never create a graphical representation of all
>> of img,
>> but only pieces of it.  I tried this with a random set of data of the
>> size you
>> describe, and it was extremely efficient...taking only a few seconds
>> (on a very
>> fast and new machine...your mileage may vary).
>>
>> Now, normally I would say this isn't the best practice.  It's generally
>> good for
>> interfaces to well-encapsulated.  They should use variables which
>> reside in
>> DynamicModules[] and not have side effects by using or creating global
>> variables
>> (unless using global variables is part of the purpose of the interface,
>> of
>> course).  But there's no way to fully encapsulate this interface
>> without the
>> undesirable effects you're seeing.
>>
>> You could store a variable in a private context which represents the
>> source data
>> for the image.  That would encapsulate it somewhat.  But, for as long
>> as you're
>> going to have upwards of 500 megabytes of source data, you're going to
>> have to
>> make sure it doesn't get duplicated, typeset, or transmitted to the FE
>> to be
>> efficient.
>>
>> Sorry for the very long explanation, but I wanted to be as clear as
>> possible.
>> Hope you found it helpful.
>>
>> Sincerely,
>>
>> John Fultz
>> jfultz at wolfram.com
>> User Interface Group
>> Wolfram Research, Inc.
>>
>>
>> On Mon, 24 Dec 2007 04:46:19 -0500 (EST), Thomas Muench wrote:
>>> Dear MathGroup,
>>>
>>> I have written an application (Mathematica 6.0.1 on Windows XP, code
>>> see below) with which I want to analyze image data (3D stacks acquired
>>> with a confocal microscope). The program works very nicely in
>>> principle (with small sample data), but it does NOT work when the data
>>> is of the size that I usually deal with. The dynamic display does not
>>> even initialize. The computer works hard for about 40 minutes, and
>>> then Mathematica quits without an error message.
>>> My image stacks usually have dimension e.g. 63x4x512x512 (each image
>>> has x-y-dimension 512x512, 4 color channels at each z-level, and on
>>> the order of 60 levels).
>>>
>>> My dynamic display consists of 3 graphics (2 of which are
>>> LocatorPanes, and 1 a simple ListLinePlot), which don't take too much
>>> time to be created when I evaluate the corresponding graphic commands
>>> outside of anything "Dynamic" (it takes 1 sec, 0.2 sec and .01 sec,
>>> respectively). So the problem should not be the creation of the
>>> graphics from the image stacks. I think it has something to do with
>>> the overhead that is connected with dynamic displays, whatever that
>>> may be. In fact, once the Dynamic interface is created in the
>>> notebook, all the manipulations I do with it are quite swift.
>>>
>>> Here is some timing information that I obtained: To initialize the
>>> display with sample data of size 63x4x50x50, it takes about 8 seconds.
>>> 4 times as large (63x4x100x100) takes about 30 seconds, i.e. about 4
>>> times as long. If it would keep scaling linearly like that, I would
>>> expect about 15 minutes for my full data, but, as mentioned, it
>>> crashes after 40 minutes. I guess apart from the crash, linearity
>>> brakes down because of memory issues.
>>>
>>> My question is: Why is there such a large overhead? Is there a way to
>>> avoid it? In my particular case, I do not need "usability" of the
>>> dynamic interface preserved over sessions. I need to quickly load and
>>> display the data, do some manipulations to extract some numbers, and
>>> then move on to the next data set. So even if it worked in 15 minutes
>>> it would not be very useful.
>>>
>>> Since the problem scales with data size, I tried to use
>>> LocalizeVariables->False, but this does not seem to be a valid option
>>> for DynamicModule. Any other suggestions to get rid of (at least part
>>> of) the overhead?
>>>
>>> Thank you very much,
>>> thomas




  • Prev by Date: Re: problem with exporting a graph
  • Next by Date: Re: Timing and Pi
  • Previous by thread: Re: Avoid slow initialization of DynamicModule
  • Next by thread: Vector transpose!