Is achartengine ready for realtime graphing?

筅森魡賤 提交于 2019-11-27 18:06:55

问题


I'm trying to graph some real-time data, "realtime" here means < 10msec data, ideally as low as possible. I've been able to get Android to fetch and process data this fast but ACE just looks like it's not been designed for real-time use in mind. First symptoms are that garbage collector kicks in like there's no tomorrow and totally kills the app. I'm visualizing data on a "sliding window" fashion so it's not like I'm expecting ACE to plot in real time hundreds of thousandths of points. I've taken a look at it and the onDraw for XYChart certainly allocates very heavily in cases where it looks like it's convenient and probably makes the code much more readable but not really required. This might even be worse than it used to be so it might not have been noticed yet. I saw bugfix for issue #225 solved a concurrency problem changing:

return mXY.subMap(start, stop);

for:

return new TreeMap<Double, Double>(mXY.subMap(start, stop));

This creates huge allocations (still backed by the original subMap though) when it would probably be better to queue updates while onDraw is going on and process them later on atomic updates or something on that line to avoid concurrency issues.

The real pity here is that ACE is certainly fast enough for what I need. It can do what I need on my HW perfectly but since it allocates so heavily on repaint Android goes crazy with GC. It soon starts allocating while GC is running so it has to wait and my app starts looking like a stop-motion movie.

The real question though is: Is it reasonable to expect to be able to repaint 4 or 6 linecharts (tablet app) on realtime (sub 200ms refresh rate) with ACE or is it simply not prepared for that kind of abuse? If the answer is no. Any other options there you'd recommend?

EDIT 20130109: Revision 471 improves things quite a bit for small data sets. 2.000 points / 4 charts / 100 msec refresh rate is doable and smooth. Logs still see "GC_CONCURRENT freed" like crazy (around 10/sec) but no "WAIT_FOR_CONCURRENT_GC blocked" which are the showstoppers that make your app stop-motion like. At 3.000 points / 1 chart / 100 msec it's clearly not smooth. We get again the avalanche of "WAIT_FOR_CONCURRENT_GC blocked" on logcat and the stuttering app. Again it looks like we do not have a speed problem, only a memory management problem.

It may look like I might be asking ACE to do magic but I hit this wall after refactoring all my code to retrieve and store telemetry data at 1KHz. Once I finally saw my app retrieve and store all of that realtime without triggering GC at all I pulled my hair with ACE when trying to graph :)


回答1:


First of all thanks for the great question and for the point you raised. You were definitely right about the huge memory allocation that was done under the onDraw() method. I fixed that and checked in the code in SVN. I have also added a synchronized block inside the onDraw() method such as it will hopefully not throw ConcurrentModificationException when adding new data to the dataset during repaints.

Please checkout the code from SVN and do an ant dist in order to build new AChartEngine jar file and embed it in your application. Please see instructions here.

To answer your question: AChartEngine is definitely ready for dynamic charting. The issue you reported was a show-stopper, but it should be fixed now. I have written dynamic charting using it. However, you need to make sure you don't add 100000s of data values to the datasets. Old data can be removed from the datasets in order to gain performance.

It is definitely reasonable to paint the 5 or so line charts if they have up to a few 1000s points.




回答2:


After a big effort on optimizing everything else on my app I still can't make it plot in what I understand for "realtime". The library is great, and very fast but the way in which every onDraw allocates memory inevitably triggers an avalanche of garbage collection which collides with its own allocation and thus android freezes your app momentarily causing stutter which is totally incompatible with "realtime" graphing. The "stutter" here can range from 50-250ms (yes milliseconds) but that's enough to kill a realtime app.

AChartengine will allow you to create "dynamic" graphs just as long as you don't require them to be "realtime" (10 frames/sec, (<100ms refresh rate) or what you'd call "smooth").

If someone needs more information on the core problem here, or why I'm saying that the library is fast enough but memory allocation patterns end up causing performance problems take a look at Google I/O 2009 - Writing Real-Time Games for Android




回答3:


Ok, so after some time looking for another graphing library I found nothing good enough :) That made me look into ACE again and I ended up doing a small patch which makes it "usable" for me although far from ideal.

On XYSeries.java I added a new method:

/**
* Removes the first value from the series.
* Useful for sliding, realtime graphs where a standard remove takes up too much time.
* It assumes data is sorted on the key value (X component).
*/
public synchronized void removeFirst() {
  mXY.removeByIndex(0);
  mMinX = mXY.getXByIndex(0);
}    

I found that on top of the memory issues there where some real speed issues at high speed framerates too. I was spending around 90% of the time on the remove function as I removed points which scrolled out of view. The reason is that when you remove a min|max point ACE calls InitRange which iterates over every point to recalculate those min/max points it uses internally. As I'm processing 1000 telemetry frames per sec and a have a small viewport (forced by ACE memory allocation strategies) I hit min/max points very often on the remove function. I created a new method used to remove the first point of a series which will normally be called as soon as you add a point which makes that one scroll out of your viewport. If your points are sorted on key value (classic dateTime series) then we can adjust mMinX so the viewport still looks nice and do that very fast. We can't update minY or maxY fast with the current ACE implementation (not that I looked into it though), but if you set up an appropriate initial range it may not be required. In fact I manually adjust the range from time to time using extra information I have because I know what I'm plotting and what the normal ranges are at different points in time.

So, this might be good enough for someone else but I insist that a memory allocation refactoring is still required on ACE for any serious realtime graphing.



来源:https://stackoverflow.com/questions/14187716/is-achartengine-ready-for-realtime-graphing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!