React Profiler: What do the timings mean? - reactjs

I am using react profiler to make my app more efficient. It will commonly spit out a graph like this:
I am confused because the timings do not add up. For example, it would make sense if the total commit time for "Shell" was 0.3ms then "Main" was "0.2ms of 0.3ms." But that is not the case.
What precisely do these timings mean and how do they add up?
(note: I have read "Introducing the React Profiler" but it appears from this section that this time-reporting convention is new since that article.)

The first number (0.2ms) is the self duration and the second number (0.3ms) is the actual duration. Mostly the self duration is the actual duration minus the time spent on the children. I have noticed that the numbers don't always add up perfectly, which I would guess is either a rounding artifact or because some time is spent on hidden work. For example, in your case, the Shell has an actual time of 3.1ms and a self duration of 0.3ms, which means the 2 children (Navbar and Main), should add up to 3.1ms - 0.3ms, or 2.8ms. However, we see that the Navbar is not re-rendered, so it's 0ms, but the actual duration for Main is only 2.7ms, not 2.8ms. It's not going to have any impact in practical terms when you're performance tuning, but it does violate expectations a bit.

Related

Why are the inputs to my guess_nonlinear() all 1s?

The N2 diagram for my full problem is below.
The N2 diagram for the coupled portion of the problem is below.
I have a DirectSolver handling the coupling between LLTForces and ImplicitLiftingLine, and an LNBGS solver handling the coupling between LiftingLineGroup and TestCL.
The gist for the problem is here: https://gist.github.com/eufren/31c0e569ed703b2aea3e2ef5360610f7
I have implemented guess_nonlinear() on ImplicitLiftingLine, which should use various outputs from LLTGeometry to give a good initial guess for the vortex strengths based on a linearised form of the governing equations.
def guess_nonlinear(self, inputs, outputs, resids):
freestream_unit_vector = inputs['freestream_unit_vector']
freestream_velocity = inputs['freestream_velocity']
n = inputs['normal_vectors']
A = inputs['surface_areas']
l = inputs['bound_vortices']
ic_tot = inputs['influence_coefficients_total']
v_inf = freestream_velocity
v_inf_vec = v_inf*freestream_unit_vector
lin_numerator = np.pi * v_inf * A * np.sum(n * v_inf_vec, axis=1)
lin_denominator = (np.linalg.norm(np.cross(v_inf_vec, l), axis=1) - np.pi * v_inf * A * np.sum(np.sum(n * ic_tot, axis=2), axis=1))
lin_vtx_str = lin_numerator / lin_denominator
outputs['vortex_strengths'] = lin_vtx_str
However, when the problem is run for the first time, any inputs not explicitly set with p.set_val() are all 1s. This causes guess_nonlinear() to give a bad output and so the system fails to converge:
As far as I can tell, the execution order for the LLT group is correct, and the geometry components should be being executed before the implicit component. I'm confused as to why this doesn't seem to actually be happening when the code is run, and instead these inputs are taking their default values.
What do I need to change to get this to work properly? Additionally, I've found difficulty in getting LNBGS to converge (hence adding guess_nonlinear()) during optimisation - only DirectSolver gets all the way through the optimisation without issues, but it's very slow for large numbers of LLT nodes). How can I improve the linear and nonlinear solver selection, and improve the reliability of the iterative solver?
Note: Thanks for providing a testable example. It made figuring out the answer to your question a lot simpler. Your problem was a bit subtle and I would not have been able to give a good answer without runnable code
Your first question: "Why are all the inputs 1"
"Short" Answer
You have put the nonlinear solver to high in the model hierarchy, which then included a key precurser component that computed your input values. By moving the solver down to a lower level of the model, I was able to ensure that the precurser component (LTTGeometry) ran and had valid outputs before you got to the guess_nonlinear of implicit component.
Here is what you had (Notice the implicit solver included LTTGeometry even though the data cycle does not require that component:
I moved both the nonlinear solver and the linear solver down into the LTTCycle group, which then allows the LTTGeometry component to execute before getting to the nonlinear solver and guess_nonlinear step:
My fix is only partially correct, since there is a secondary cycle from the TestCL component that also needs a solver and does not have one. However, that cycle still does not involve the LTTGeometry group. So the fully correct fix is to restructure you model top run geometry first, and then put the LTTCycle and TestCL groups together so you can run a solver over just them. That was a bit more hacking than I wanted to do on your test problem, but you can see the general idea from the adjusted N2 above.
Long Answer
The guess_nonlinear sequence in OpenMDAO does NOT run the compute method of explicit components or of groups. It follows the execution hierarchy, and calls any guess_nonlinear that it finds. So that means that any explicit components you have in your model will NOT get executed, their outputs will not get updated with computed values, and those computed values will not get passed to the inputs of downstream components.
Things get a little tricky when you have deep model hierarchies. The guess_nonlinear method is called as the first step in the nonlinear solver process. If you have a NonLinearRunOnce solver at the top level, it will follow the compute chain down the line calling compute or solve_nonlinear on each child and doing a data transfer after each one. If one of those children happens to be a group with a nonlinear solver, then that solver will call guess_nonlinear on its children (grandchildren of the top group with the NonLinearRunOnce solver) as the first step. So any outputs that were computed by the siblings of this group will be valid, but none of the outputs from the grandchild level will have been computed yet.
You may be wondering why not just have the guess_nonlinear method call the compute for any explicit components? There is a difficult to balance trade off here. If you assume that all explicit components are very cheap to run, then it might make sense to run the compute methods --- or it might not. A lot depends on the cyclic data structure. If some early component in the group needs guesses from the later one, then running its compute isn't going to help you much at all. Perhaps more importantly though, not all explicit components are cheap to run. You might have a very expensive computation, and calling compute as part of the guess process would be way too costly.
The compromise here, if you need some kind of top level guess process, is that you can implement guess_nonlinear at the group level. It's less common to do, but it gives you total control over what happens. You can call whatever you need to call in whatever sequence.
So the absolute key thing to remember is that the only data you have available to you when a guess_nonlinear is called is any data that was computed before your containing solver was executed. That means any thing that was computed before you got to the model scope of the containing solver (not the scope of the component with the guess_method itself).
Your second question: "How can I speed this up when the number of nodes gets large?"
This one not possible to give a generic answer to at all. I noticed that you have already specified sparse partial derivatives. That is a great start, but if its still not fast enough for you then it means you're reaching the limits of what you can do with a DirectSolver. You note that this solver is the only one that gets you through the optimization without issues, which I will take to mean that ScipyKryloventer link description here and PetscKrylov are not converging the linear system well for you --- at least not by themselves. Thats not surprising, as krylov solvers almost always require some kind of preconditioner... and this is why I can't offer a generic answer. Setting up efficient linear solvers for larger-scale compute is a tricky subject. If you look into the literature, you'll find some good suggestions. You can also study open source implementations like VSPAero for some tips.
effectively, you've reached the limit of what simple linear solvers can offer you. From this point forward, OpenMDAO can help a bit by making it easier to implement some preconditioning, but you'll have to suffer the math side yourself.

Minimizing an array-returning function using "fminunc"

I am using MATLAB to build a code that does automatic tuning of the three PID controller gains. The way I am thinking of it, is to minimize the error (the difference between the desired state and the obtained one) of my system, for that, I coded a function that accepts the PID gains as input parameters and returns the calculated error, namely:
errors_vector = closedLoopSimulation(pidGains)
Since I have three set points (input commands), then the dimension of the output errors_vector is 3*N, where N is the number of time samples I have (1000 in my case). So that is the function I want to minimize, and for doing so, I tried using fminunc command, namely:
pidGains_ini = [2.4 0.1 0.4];
func = #closedLoopSimulation;
[pid, fval] = fminunc(func, pidGains_ini)
However, when I run the last piece of code, I get this error:
User supplied objective function must return a scalar value.
which is clearly due to the fact that that errors_vector is a 3*1000 array and not a scalar.
My questions would be, from the programming point of view, is there a way that I can make fminunc minimize functions that return arrays?
On the other hand, and from the Control Theory point of view, is there another way which I can optimize the PID gains automatically?
I hope I made myself clear enough.
Thanks
Minimizing a vector is not very well defined (there is something called multi-objective or multi-criteria optimization but that is somewhat specialized). "Normal" optimization methods can only minimize (or maximize) scalar objectives. I suspect in your case you could form such an objective by taking the sum of the squared errors and minimize that. To be complete: this is standard operating procedure and is often called "least squares".

Timing while a value is true in Labview

I have been making a labview program for kids to moniter energy production from various types of power sources. I have a condition where if they are underproducing a warning will fire, and if they are overproducing by a certian threshold, another warning will fire.
I would like to time how long throughout the activity, each type of warning is fired so each group will have a score at the end. This is just to simulate how the eventual program will behave.
Currently I have a timer which can derrive the amount of time the warning is true, but it will overwrite itself each time the warning goes off and on again.
So basically I need to to sum up the total time that the value has been true, even when it has flitted between true and false.
One method of tabulating the total time spent "True" would be exporting the Warning indicator from the While-loop using an indexed tunnel. If you also export from the loop a millisecond counter value of when the indicator was triggered, you can post process what will be an array of True/False values with the corresponding time at which the value transitioned.
The post processing could be a for-loop that keeps a running total of time spent true.
P.s. if you export your code as a VI snippet, others will be able to directly examine and modify the code without needing to remake it from scratch. See the NI webpage on the subject:
http://www.ni.com/white-paper/9330/en/
I would suggest going another way. Personally, I found the code you used confusing, since you subtract the tick count from the value in the shift register, which may work, but doesn't make any logical sense.
Instead, I would suggest turning this into a subVI which does the following:
Keep the current boolean value, the running total and the last reset time in shift registers.
Initialize these SRs on the first call using the first call primitive and a case structure.
If the value changes from F to T (compare the input to the SR), update the start time.
If it changes from T to F, subtract the start time from the current time and add that to the total.
I didn't actually code this now, so there may be holes there, but I'm leaving that as an exercise. Also, I would suggest making the VI reentrant. That way, you can simply call it a second time to get the same functionality for the second timer.

What does the renderingEmSize parameter in GlyphRun specify?

I'm trying to make a GlyphRun instance for use in a GlyphRunDrawing, but the documentation is just so bad that it's almost comical. For example, the parameter renderingEmSize is described like this:
renderingEmSizeType: System.Double
A value of type Double.
Just... wow.
I know what an "em" is in a font (width of the em dash), but I don't know what the grid units are. Device pixels? Device independent pixels?
Turns out the answer is in the source code. Thanks for MS making this available, if they are going to make eyes bleed on the docs.
Interestingly, all the information we need is contained in the xml doc comments on GlyphRun.cs. The renderingEmSize for example, is as follows:
<param name="renderingEmSize">Font rendering size in drawing surface units (96ths of an inch).</param>
The rest of the file is similarly well-commented, including this seemingly out-of-place but gripping read:
/*
The default branch prediction rules for modern processors specify that forward branches
are not to be taken. If the branch is in fact taken, all of the speculatively executed code
must be discarded, the processor pipeline flushed, and then reloaded. This results in a
processor stall of at least 42 cycles for the P4 Northwood for each mis-predicted branch.
The deeper the processor pipeline the higher the cost, i.e. Prescott processors.
Checking for multiple incorrect parameters in a method with high call count like this one can
easily add significant overhead for no reason. Note that the C# compiler should be able to make
reasonable assumptions about branches that throw exceptions, but the current whidbey
implemenation is weak in this regard. Also the current IBC tools are unable to add branch
prediction hints to improve behavior based on run time information. Also note that adding
branch prediction hints increases code size by a byte per branch and doing this in every
method that is coded without default branch prediction behavior in mind would add an
unacceptable amount of working set.
*/
The whole file can be found here: GlyphRun.cs at webtropy

silverlight math performance question

Is there some reason that identical math operations would take significantly longer in one Silverlight app than in another?
For example, I have some code that takes a list of points and transforms them (scales and translates them) and populates another list of points. It's important that I keep the original points intact, hence the second list.
Here's the relevant code (scale is a double and origin is a point):
public Point transformPoint(Point point) {
// scale, then translate the x
point.X = (point.X - origin.X) * scale;
// scale, then translate the y
point.Y = (point.Y - origin.Y) * scale;
// return the point
return point;
}
Here's how I'm doing the loop and timing, in case it's important:
DateTime startTime = DateTime.Now;
foreach (Point point in rawPoints) transformedPoints.Add(transformPoint(point));
Debug.Print("ASPX milliseconds: {0}", (DateTime.Now - startTime).Milliseconds);
On a run of 14356 points (don't ask, it's modeled off a real world number in the desktop app), the breakdown is as follows:
Silverlight app #1: 46 ms
Silverlight app #2: 859 ms
The first app is an otherwise empty app that is doing the loop in the MainPage constructor. The second is doing the loop in a method in another class, and the method is called during an event handler in the GUI thread, I think. But should any of that matter, considering that identical operations are happening within the loop itself?
There maybe something huge I'm missing in how threading works or something, but this discrepancy doesn't make sense to me at all.
In addition to the other comments and answers I'm going to read between the lines a little.
In the first app you have pretty much this code in isolation running in the MainPage constructor. IWO you've create a fresh Silverlight app and slapped this code in it and thats it.
In the second app you have more actual real world stuff. At the very least you have this code running as the result of a button click on a rudimentory UI. Therein lies the clue.
Take a blank app and drop a button on it. Run it and click the button, what does the button do? There are animations attached to visual states of the button. This animation (or other animations or loops) are likely running in parrallel with your code when you click the button. Timers (whether you do it properly with StopWatch or not) record elapsed time, not just the time your thread takes. Hence when other threads are doing other things (like animations) your timing will be off.
My first suspicion would be that Silverlight App #2 triggers a garbage collection. Scaling ~15,000 points should be taking a millisecond, not nearly a second.
Try to reduce memory allocations in your code. Can transformedPoints be an array, rather than a dynamically grown data structure?
You can also look at the GC performance counters, but simply reducing the memory allocation may turn out to be simpler.
Could it be possible your code is not being inlined in the CLR by the app that is running slower?
I'm not sure how the CLR in SL handles inlining, but here is a link to some of the prerequisites for inlining in 3.5 SP1.
http://udooz.net/blog/2009/04/clr-improvements-in-net-35-sp1/

Resources