Open dullbananas opened 3 years ago
What device is this on? I'm not seeing this on an iPad, but maybe it's too fast, or my circuit is too small.
Well, I guess if I turn the simulation speed all the way up, I see it.
My circuit has four 8-bit latches, dozens of wires (each connected to a few tri-state buffers), eighteen And gates, and more.
Decreasing simulation speed and increasing time step removes almost all lag, but it makes the clock in my circuit too slow.
There's no visible lag when I'm just watching a circuit run (without touching the UI at all), and that's the only time I need the simulation running.
Does GWT have any means of using async, promise, web worker, etc for stuff that would depend on the JVM thread pools? A separate render thread to keep the simulation from blocking interactivity might make a big difference.
async or promise wouldn't help us much, but web workers might, since those are apparently real threads. I'll have to look into that.
What I did for now is change the simulation loop so that it stops after 50ms, so that you will get around 20fps no matter how high the simulation speed is set. that makes the simulation a bit slower maybe, but it makes it much less laggy.
This should be better now, please check
There is still some lag. An easy way to see this is to make a static RAM element, set "# of address bits" and "# of data bits" to 16, and duplicate it 8 times.
Biggest hangup I've found still seems to be related to inductor ringing even with the trap integration unchecked.
The LTspice manual has a page describing the trap ringing phenomenon (p. 108) as it relates to a dynamic timestep simulation where the timestep apparently oscillates up and down while homing in on the solution. That explains the issue for spice but not for a fixed timestep simulation. It is evidently enough of a problem that ltspice adds a series resistance to every inductor by default, and ngspice has .option rseries
for same. I've seen more intricate simulations including series and parallel resistance with parallel capacitance to simulate a finite SRF and Q-factor / nonzero ESR for inductors. Even with a more complicated multi-part inductor model the simulations are definitely smoother when you get the values tuned right.
It sounds like the dynamic timestep is rather fundamental to the spice-like simulators... you can even set the max timestep to 0 for a transient simulation that will in theory run in the smallest number of steps required to meet the configured tolerance constraints, but I've found that the 0 timestep doesn't work very well. Is that similar to what the "auto-adjust timestep" option does? If that improves performance it would make sense as a default, though I haven't found it to make much difference.
If there's a way to run the simulation in a web worker thread then it would be interesting to have a buffer sitting between the asynchronous simulation and UI for queueing serialized simulation results. Combined with a dynamic timestep you could have the simulation running at whatever pace it wants while the UI "plays back" the buffer at a fixed rate that could be independent of the actual timestep by interpolating results relative to the dynamic timestep and fixed playback rates. When the user modifies the circuit you just flush the buffer and resume reading newly computed simulation output.
Yes that is what auto-adjust timestep does, but that only affects nonlinear elements failing to converge. Bad inductor behavior would never trigger a smaller timestep. I'll have to see what LTspice is doing.
Apparently web workers do not share data with the main thread (except by message-passing)? That is a big problem.
It seems like moving the simulation to web workers would be a really huge change for not that much benefit. That time would be better spent make the simulation faster. And it would be much easier to just stop the simulation while doing UI interaction (maybe only doing so if it's slow, or make an option).
Apparently web workers do not share data with the main thread (except by message-passing)? That is a big problem.
Yep I was sorta recollecting that little detail when thinking about how you'd have to do some kind of object serialization representing the entire simulation state.( I briefly played with web workers long ago... will have to re-read). IIRC there are two different modes with different tradeoffs -- roughly one of them can't modify the DOM or share anything with the other workers other than message passing, and the other has some other set of gotchas, but there was also a way to get at least some limited form of shared memory in one of the modes.
It seems like moving the simulation to web workers would be a really huge change for not that much benefit. That time would be better spent make the simulation faster. And it would be much easier to just stop the simulation while doing UI interaction (maybe only doing so if it's slow, or make an option).
Yeah major architecture change is what I'd predicted... like may as well rewrite the whole thing in javascript at that point. I see GWT has a way to include custom JS but if that's the only way to use such features then meh.
Possibly large benefit given the real-time nature of this app. If you were really ambitious I'd imagine a simulation like this is easy to divide and conquer over N processors. And with UI decoupled from sim and with a message passing scheme it's not a big jump to network-transparency, e.g. running the sim on a beefy PC and the UI from a puny phone.
I'm sure you have a wish list with that not near the top though. :)
Edit: another thought is webassembly - something I know absolutely nothing about but if that were viable then going the opposite direction back to full Java could be a thing.
I don't think this simulation is very easy to parallelize. Solving a matrix (the most expensive step) doesn't seem easy to divide and conquer without lots of communication between the threads.
I strongly agree with doing some kind of optimization effort. Circuitjs isn't as fast as it used to be due to GWT-transpiled javascript being slower than the JVM.
I would rewrite hot spots as native functions and take advantage of HTML5 objects and other things javascript now offers, but I don't know how much gain we'd get from that.
does circuitjs use weebassembly?
does circuitjs use weebassembly?
I don't think so. As far as I know, GWT transpiles the java code to javascript.
there's lots of high-level optimization to do before we start worrying about the overhead of GWT.. I am looking at some of it. Your largest circuits are mostly digital, I'd guess, right?
we don't use webassembly presently
there's lots of high-level optimization to do before we start worrying about the overhead of GWT.. I am looking at some of it.
Oh nice, we should definitely optimize those, then.
I only suggest unabstracting hot spots (extremely frequently executed code), where even small optimizations can lead to decent gains. Especially when GWT's implementation of a Java class is particularly lazy (eg stringbuilder). Converting anything else into native code is a obviously bad idea.
Your largest circuits are mostly digital, I'd guess, right?
My most complex circuits primarily consist of passive and active components. Digital can only get someone so far before they need to learn ohm's law.
Things like pinch to zoom and text fields are very laggy with a big circuit. There should be option to automatically pause simulation during UI interaction