MathGroup Archive 2008

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

Search the Archive

Re: Avoid slow initialization of DynamicModule

  • To: mathgroup at smc.vnet.net
  • Subject: [mg84566] Re: Avoid slow initialization of DynamicModule
  • From: "Kevin J. McCann" <Kevin.McCann at umbc.edu>
  • Date: Thu, 3 Jan 2008 20:35:03 -0500 (EST)
  • Organization: University System of Maryland
  • References: <200712240946.EAA06236@smc.vnet.net> <fkt9h6$6f7$1@smc.vnet.net>

Thomas,

Your code is really fantastic! I am running it on an AMD dual core 
64-bit 2.6GHz and I don't see any slowness in your original code.

Kevin

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
>>
>>
> 

-- 

Kevin J. McCann
Research Associate Professor
JCET/Physics
Physics Building
University of Maryland, Baltimore County
1000 Hilltop Circle
Baltimore, MD 21250


  • Prev by Date: Re: bug -- advice sought
  • Next by Date: Re: Tensor Contraction
  • Previous by thread: Re: Re: Re: bug -- advice sought
  • Next by thread: Setting Colours of Plots