This object is in archive! 

Is vector map rendering multitasking?

joeloc shared this question 10 years ago
Answered

When I watch cpu usage while Locus renders vector maps, it hardly ever goes above 50% (displayed with CoolTool). Is this simply a measuring problem? Or does Locus maybe not use all available CPU cores for rendering?

Replies (20)

photo
0

what you see is correct. Default library from MapsForge is whole in single thread! Implementation in Locus is partially multi-thread, but just minor part that draw data on screen. Main and slowest part that read and prepare data from file, is still in single-thread.

photo
0

Then I`d like to turn this thread from a question to an idea: Make it multi-threaded and increase speed by 250% at no cost :-).

photo
0

Just kidding. You`d probably have done it already if it was simple.

photo
0

Although... couldnt you just run two mapsforge threads, one for even tiles and one for odd tiles? Or one for top half of screen and one for bottom half? Ie multithread it without actually changing the library?

photo
0

in my version it`s not a problem to load data in more threads at once


problem is, that this library compare already finished tiles around, if they contain part of texts, icons etc. that should be partially rendered also on this current tile.


Whole system works like


1. in four threads, locus starts to render vector map tiles


2. first thread starts to read data and rest have to wait


3. when this first ends with reading, second (random) start to read. Meanwhile first may in own thread draw lines, points etc ...


4. when second ends, third may start to read. Second in own thread starts to render, but use already read previous tile to check what to draw.


when I allow reading more tiles at once from file, it cause mess in cached data. I already tried it, but in way how it`s done, it cannot work.


There is always any way, but I don`t have it in mind now, and even if so, I`m sure, it should take quite a long time to implement

photo
0

Ok. I guess a faster SD card would boost performance considerably? SD-Card reading is the main factor?

photo
0

Just thinking... can Android read from external sd and internal flash at the same time without slowdown? If that was true and a user wanted to sacrifice storage space for speed doubling, you could do a funky thing here :).

photo
0

to be true, there are currently two factors. Do you know what mean "Garbage collector" in Java? It`s a automatic system that collects empty objects and garbage them. And in MapsForge, there is really a lot of garbage. So it also slow down. On this, I`m working. It`s better but not best still ...


And card helps for sure. I have most personal maps on card, but whole Locus together with vector maps on internal memory as it`s fastest that every card

photo
0

I know garbage collectors... although we mostly did that stuff "manually" back in the good old days when I was still a programmer instead of a fulltime cyclist :-).


Anyway... what I thought of needs two prerequisites:


a) the mapsforge threads spend considerable time waiting for data from sd card (quite likely because we only see 50% cpu usage).


b) android can read data from internal and external sd simultaneously without slowdown (no clue about that).


If both are true, you can speed up your rendering by a factor of 2 with only minimal changes in code. The user would have to prepare this by storing his map twice:


/external_sd/maps/Germany.map and


/sdcard/maps/Germany.map or something.


When opening a vector map, you iterate through all other configured map folders to see if there is another file with the exact same name and size. If you find one, you open that as well. Then in your mapsforge threads, you simply switch between file handles. First thread reads file0, second thread reads file1, third thread reads file0, etcpp.


That might speed things up majorly without much work on your side. Obviously the user has to sacrifice disk space for speed, but its an optional thing anyway. Doesnt need any GUI or settings either, its all automatic.

photo
0

nice try, but it`s really not so simple. There is no need to have two same files. I may read twice from same file at once, but it won`t solve my problem with caching and testing already rendered tiles around ...


anyway you "forced" me to test again where exactly is problem and I again found another place. After a few hours, another speed improvement implemented :)


Anyway this - better-multi-thread-usage - is for now music of future

photo
0

You didnt really see my point of two identical map files being ON SEPARATE HARDWARE (internal and external flash). It is not(!) equal to opening the same file twice on the same hardware.


For example:


(1) android max read spead from external microsd: 80 MB/sec


(2) android max read spead from internal flash: 60 MB/sec


You cannot fix (1) by opening the same file twice. It will still max out at 80MB/s, making your threads spend their time idling around waiting for each other and for the newly read data to appear.


But if you do (1) and (2) AT THE SAME TIME, chances are pretty good that the reads will happen IN PARALLEL without blocking each other. You would basically get 140 MB/sec total data rate for map file reading.

photo
0

I`ve got it, don`t worry. But please keep in mind what I also wrote "but it won`t solve my problem with caching and testing already rendered tiles around" ... in current system I can always handle just one tile at once, otherwise it will completely corrupt all texts, icons, ways that are not! completely on one tile

photo
0

Of course this depends on the hardware implementation. If all flash reads go through the same slow bus, it will not help at all. But I`d really be surprised if Android wasnt more clever here. External micro-sd is a different interface after all, why would it affect/block/slowdown reading from internal flash?

photo
0

Hmmmm... apparently I fail to understand exactly how your system works. I cant see how simply swapping between two file handles in your threads would mess up anything else.


The required changes to your code are quite minimal, basically not much more than


read(mapfilehandle[cpunr%2]);


instead of


read(mapfilehandle);


where


mapfilehandle[0] = open(mapfile_on_internal_flash);


mapfilehandle[1] = open(mapfile_on_external_flash);


Thats it... nothing else changes.


Hmm... I think I start to see the problem... my idea wont help if your text-checking-tile-caching-thingy does prevent Locus from doing another read() while not completely done processing the previous data?

photo
0

It`s not Menion`s thingy but Mapsforge`s one.


Seems that how it`s implemented there is just a killer for parallelising stuff. More cores and therefore more threads don`t help in this area of the software.


It`s a shame but it seems to be a matter of fact.

photo
0

thanks tommi ...


stefan, imagine it in this way ... one thread reads data, when it`s done, it cache all points/lines that overlap to next tiles. When another tile is read, it check cache and grab all cached data that also lies in this tile, etc etc. So if I handle more tiles at once, there will be missing items on some tiles, because they`ll not be yet cached etc etc ...


yes, it is "MapsForge thing". On other side, I`m sure, that almost quarter of whole library code is rewrote to improved version (to be true I really hope there will be no more updates of this lib :) ). Part already work on multi-thread as I wrote before, but this one part, that slow down rendering, cannot be now simply


separated.


But as I wrote before, I also improved one part, so it will be again little bit faster in next version. dot

photo
0

I am just confused by seeing "40%" cpu usage on my phone by something that you so painstakingly optimized in small steps :-). Where are the remaining 60% hidden? I suppose all that time is spent waiting for read() to finish?

photo
0

probably :)


what app you suggest to measure CPU usage on every thread?

photo
0

In this case I have another suggestion that would work with minimal changes and might give 100%: a pre-fetching read() algorithm.


instead of a simple


buffer = read(file,tile_data_position)


you do something like


if (prefetch_buffer_position == tile_data_position)


{


wait_for_async_read_to_finish(file);


buffer = prefetch_buffer; // memcopy or pointer swapping


}


else


{


abort_previous_read(file); // oops, we were pre-fetching wrong data


buffer = read(file,tile_data_position); // normal sync read


}


prefetch_buffer_position = next_tile_data_position; // make a good prediction


start_async_read(file,prefetch_buffer_position);


... continue as before.


The whole idea behind this is to keep your code BUSY rendering while Android reads data from the file. Waiting for synchronous read()s is just wasted time.

photo
0

I use CoolTool (->play store) to display cpu load (and more). It can be nicely overlayed onto status bar and thus is always in view. Not sure it can do per-core load. But when it says 1600 MHz and 25% (Note 2), it pretty much means that one core is working full time and three are idling around twiddling thumbs.


I have no idea how accurate that is... dont you have way better profiling options in the android dev kit? Even back in the gcc days, gnu profiler could basically tell me the exact time spent in each single line of my code.


Anyway... the general "idea" that CoolTool gives should be correct. And since I wouldnt know why something as cpu-hungry as vector map rendering should waste more than 50% of its time idling, it must be the file reads. That can either be fixed by true multi-threading (apparently way too complex in current mapsforge) or by a simple read-ahead buffer and async reading as suggested above.

Replies have been locked on this page!