News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Advice on memory handling

Started by minor28, October 09, 2010, 09:31:41 AM

Previous topic - Next topic

minor28

I am working on my own chart plotter with GPS data. I have the free SeaClear and the commersial Fugawi chart plotters.

I would appreciate some advice on memory handling. A marine chart file is about 5MB of size. The image is about 13,000px wide and 9,200px high. You can find us free marine charts here.

I have compared memory use for the three applications.

Loading a chart in SeaClear will use 7,644kB and the Page File increases with a couple of MB.

The same chart and Fugawi uses 31,556kB and the Page File increases with 25MB.

My app with the same chart uses 254,152kB and the Page File increases with 240MB.

I don't know how these two apps handles the chart image but this is how I do it


  • Map the file with CreateFileMapping
  • Allocate memory with HeapAlloc for pixeldata. Size about 123MB.
  • Unpack file data with three parallell threads writing to allocated memory (to increas speed)
  • Create a DIB section with CreateDIBSection as a buffer on a compatible context of a static window.
  • Fill the DIB section with StretchDIBits from allocated memory
  • In static window process, in WM_PAINT message, the DIB section is copied to static window with BitBlt.

The filemapping is unmapped after allocated memory is filled. Allocated memory is freed when my app is closed and the heap is destoyed and the contexts are released.

I have not find a better way to minimize memory usage but there obviously is a better way. Does anyone have any ideas how?

If you try my app the com port is hardcoded to com1. If you register charts, charts data is stored in registry at HKEY_CURRENT_USER\Software\MINOR28\NavApp. This registration gives the ability to automatic load a new chart whitin the new charts bounderies.

oex

I would guess that the other applications are only loading and displaying a partial image as needed.... Additionally they might be using a lower color depth (ie 8 bit rather than 32 bit....

As different areas of the maps are loaded onscreen they are loaded from file

(Similar to google earth.... You dont download the whole earth just images a bit at a time)
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

clive

They probably load enough of the image to display, plus some extra around the edges to anticipate movement. Boats move relatively slowly, and typically don't go up/down (waves of course, but water tends to be flat at rest, and charts are 2D with depths). Even in a car going at 60 mph, you are only looking at a mile a minute, so caching a mile on either side would allow for relatively few updates. Plus if you have some idea of course-over-ground you can anticipate what data would be needed next. A thread could go off and speculatively fetch and prepare tiles.

You could probably parse the whole chart, and store a catalogue of tiles for quick access, and information for tiles in adjoining charts/files.

The zoom level may also permit a great deal of information to be discarded. The display resolution is small relative to the whole chart.

People have classically coded these kinds of applications to use memory as limited commodity, loading the whole file tends to be a lazy approach. The charts are typically very large, and the plotters are lower powered processors. The old Northstar 962's used a 200 MHz Pentium MMX, NT 4.0 and 64-128MB of RAM.
It could be a random act of randomness. Those happen a lot as well.

Farabi

You can load the whole big image on a single DC without any problem, since it only render spesific location specified by you using bitblt.
Those who had universe knowledges can control the world by a micro processor.
http://www.wix.com/farabio/firstpage

"Etos siperi elegi"

minor28

Thank you very much for your answers. I really appraciate it.

A marine chart file consists of three sections. A header, pixeldata and a jumptable.

Header:
different chart data, at least 3 ref points but mostly more than 30, points for the chart outlining, a colortable etc.

Pixeldata:
compressed data

Jumptable:
with file offset to each image row.

As I understand I must load the whole file. But this is not a problem with filemapping.

My first atempt was to read the file with memoryblocks of 32kB with API crt_fread and unpack. Unpacking was three times slower than reading. The compressing algorithm is something like RLE compressing algo.

Quote
Additionally they might be using a lower color depth (ie 8 bit rather than 32 bit....
All charts have max 256 colors (8bit)

Quote
I would guess that the other applications are only loading and displaying a partial image as needed....
Quote
They probably load enough of the image to display, plus some extra around the edges to anticipate movement. Boats move relatively slowly ..
I have tryed. As I understand the image can only be devided in vertically parts. The whole row must be unpacked. If I unpack and load only a part of the image, dragging and zooming will be too slow compared to the other applications.

Quote
You could probably parse the whole chart, and store a catalogue of tiles for quick access, and information for tiles in adjoining charts/files.
I don't quite understand. But if you mean how to access adjacent chart I store registered charts outlingings in registry and when I dblclick or the boat is near the new chart the new chart is loaded. I use API CreatePolygonRgn and PtInRegion.

Quote
The zoom level may also permit a great deal of information to be discarded. The display resolution is small relative to the whole chart.
Yes, but don't I still have to unpack the whole image to be able to zoom? For route planning reasons I zoom the whole chart into view with HALFTONE palette. This will slow down painting but I can live with that because the image is much better quality.

Quote
You can load the whole big image on a single DC without any problem, since it only render spesific location specified by you using bitblt.
Yes, no problem. This will reduce memory use but is still more than the other apps. And other functions will be worse.

Best regards

Tedd

Keep the file mapping open, and cache pointers to the various sections in your own variables.
Now, consider the image to be split into a grid of squares ("tiles") - I know it's not, but that's how you'd like to be able to treat it - then you can update only the tiles you need as the map view shifts.
So, write yourself a function that takes (x,y) co-ordinates and returns an array of pixels for 'that' tile. In order to do this, you'll need to work out which rows are required, but that's quite simple. Once you have the row numbers (the file gives you offsets to their start), you can skip through the RLE data without actual decoding, just keep an accumulated count until you reach the required 'x' value, and then decode enough pixels to fill a tile row.
Once you've initially filled the area with tiles, keep those tiles in memory so they don't need to be decoded again. When you need to shift the view, you already have 90% of the data cached, and you only need to decode the new tiles that come into view - which will be much quicker.
No snowflake in an avalanche feels responsible.

minor28

Thank you,

I will test new methods based on your suggestions. The next few days I will be away from home so I am not sure when I can come back with a report

oex

Quote
I would guess that the other applications are only loading and displaying a partial image as needed....
Quote
They probably load enough of the image to display, plus some extra around the edges to anticipate movement. Boats move relatively slowly ..
Quote
I have tryed. As I understand the image can only be devided in vertically parts. The whole row must be unpacked. If I unpack and load only a part of the image, dragging and zooming will be too slow compared to the other applications.

Maybe they resave the data in another format? Maybe in a temporary file.... Even if the whole vertical column is unpacked you wont fit 13,000 pixels on a screen.... On a 1280x1024 display you will fit 1280 pixels which means about a 6Mb image at 32 bit

Indexng each vertical column with a load of pointers will allow you to access only what you need

Quote
You could probably parse the whole chart, and store a catalogue of tiles for quick access, and information for tiles in adjoining charts/files.
Quote
I don't quite understand. But if you mean how to access adjacent chart I store registered charts outlingings in registry and when I dblclick or the boat is near the new chart the new chart is loaded. I use API CreatePolygonRgn and PtInRegion.

You could compress these tiles of the main image in memory also
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

clive

Quote from: minor28
Quote
The zoom level may also permit a great deal of information to be discarded. The display resolution is small relative to the whole chart.
Yes, but don't I still have to unpack the whole image to be able to zoom? For route planning reasons I zoom the whole chart into view with HALFTONE palette. This will slow down painting but I can live with that because the image is much better quality.

Ok, If you zoom in fully you only have to process enough rows/rasters to fill the screen.

If you zoom out, you can basically skip dozens of rows/rasters for every one you display. Depends of course of you want to interpolate data from multiple rows into the visible one. Even then there is probably little reason to interpolate across all the rows.
It could be a random act of randomness. Those happen a lot as well.

minor28

Quote
If you zoom out, you can basically skip dozens of rows/rasters for every one you display. Depends of course of you want to interpolate data from multiple rows into the visible one. Even then there is probably little reason to interpolate across all the rows.

I have not had time to start with zooming yet. But how do I interpolate across rows?

I have been concentrated on handling the image in normal scale. First I keep the filemapping and I allocated memory for an imagesize equal to the client area and StretchDIBits direct to static window hDC. Painting worked well but moving did not. Jerky movements. Memory use, if I remeber right, about 9MB.

Next I allocated memory for an imagesize of three times the client area in a compatible DC and then BitBlt. Now I could move the image without jerky movements when moving within client area. To move the image I use WM_LBUTTONDOWN, WM_MOUSEMOVE and WM_LBUTTONUP. On WM_LBUTTONUP I uppdate the pixeldata from filemapping. However on next move the image jumps back to first position. Memory use about 24MB.

I have cleared the app from all but image handling to work with. Attached. Since us charts are free I have uploaded one chart to my homesite if anybody wants to try.

I have been struggling with attempts to minimize memory use without enough success. My first solution with more than 250MB memory use seems to be the solution for further work.

minor28

A few adjustments seems to work

In bsbChart4 proc:

;Allocate memory
.if pPixelData!=0
invoke HeapFree,hHeap,HEAP_NO_SERIALIZE,pPixelData
mov pPixelData,0
.endif

mov eax,yPos
neg eax
mov RowStart,eax
sub eax,FrameRectangle.bottom
.if sdword ptr eax>0
mov RowStart,eax
add eax,FrameRectangle.bottom
add eax,FrameRectangle.bottom
add eax,FrameRectangle.bottom
mov RowEnd,eax
.else
mov RowStart,0
mov eax,yPos
neg eax
add eax,FrameRectangle.bottom
add eax,FrameRectangle.bottom
mov RowEnd,eax
.endif
.if eax>imageH
mov eax,imageH
mov RowEnd,eax
.endif
sub eax,RowStart
mov PixH,eax

mov eax,xPos
neg eax
mov ColStart,eax
sub eax,FrameRectangle.right
.if sdword ptr eax>0
mov ColStart,eax
add eax,FrameRectangle.right
add eax,FrameRectangle.right
add eax,FrameRectangle.right
mov ColEnd,eax
.else
mov ColStart,0
mov eax,xPos
neg eax
add eax,FrameRectangle.right
add eax,FrameRectangle.right
mov ColEnd,eax
.endif
.if eax>imageW
mov eax,imageW
mov ColEnd,eax
.endif
sub eax,ColStart
mov PixW,eax


and in MainDlgProc:

.elseif eax==WM_LBUTTONUP
mov x,0
mov y,0
invoke bsbChart4
invoke CreateChart

minor28

If I save a kap image (size 6.4MB) as a tiff image (size 9.5MB) and open it in mspaint, memory use is 368,044kB and page file increases with 350MB. This makes me wonder if it is so bad to use 250MB of memory in my application. Any comments on that please?

oex

QuoteThe image is about 13,000px wide and 9,200px high

Why are you loading the entire image? You cant display it all at once....

Maybe you could split it into 10x10 or even 100x100 smaller images and compress them all.... Then as the user moves about the view you can uncompress and display them in realtime

I have many apps I have written that use far more than 250Mb RAM :bg however it may be an issue if used on a computer with less than 512 Mb (or more) of RAM.... I guess it depends how you intend to use it.... If only ever on a laptop with 2Gb I wouldnt worry too much....

I havent spent too much time understanding kap format however my assumption is that you must be able to split it into 100x100 smaller kap files, store them end on end and keep a log of what *current image* X,Y the user is at....

This way you will use 40? times less RAM maybe and spend far less time in compression/decompression.... (At least far less time at any given time)....

A 1280x1024x4 image is about 5Mb only....
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

minor28

Yes I can display it all at once like this.


invoke GetClientRect,hWin,addr rect
push rect.bottom
pop imageH

finit
fild bsbW
fild bsbW
fidiv bsbH
fimul rect.bottom
fist imageW
fdivr
fstp zoomFactor
fwait

invoke GetBrushOrgEx,hCDC,addr pt
invoke CreateHalftonePalette,hCDC
invoke SetStretchBltMode,hCDC,HALFTONE
invoke SetBrushOrgEx,hCDC,pt.x,pt.y,0

invoke StretchDIBits,hCDC,0,0,imageW,imageH,
0,0,bsbW,bsbH,pPixelData,pBMI,DIB_RGB_COLORS,SRCCOPY
invoke GdiFlush


This will slow down painting but I can live with that because the image is much better quality and is used only for route planning purposes.

Kap format is header, pixeldata and a jump table. Splitting a kap file into 10,000 files. I don't know if that is the way. Then I think it is better to uncompress directly from filemapping and a sufficient part of the image to display.

oex

Quote from: minor28 on October 20, 2010, 11:30:38 AM
Kap format is header, pixeldata and a jump table. Splitting a kap file into 10,000 files. I don't know if that is the way. Then I think it is better to uncompress directly from filemapping and a sufficient part of the image to display.

I thought you had said there were format issues that prevented you from uncompressing a portion of an image beforehand.... Simply you want only to have decompressed the screen map drawing dimensions eg 1280x1024 plus a small margin for scrolling so there is no decompression delay.... What you do not want is to be drawing a massive uncompressed image....

If you are able to uncompress just a portion then as I suggested before (but without compressing into seperate files) split the image logically into many pieces and display the relevent ones for the viewable area....
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv