Page 1 of 1

optimizing performance in my application

Posted: 2016-11-07T18:39:04-07:00
by tsftd
Okay, so I have a working and nearly feature complete application. At this point, I'm beginning to work on optimization rather than just getting it to do what I want. FYI, I'm not a professional programmer, but have worked on and off with Magick++ for several years.

What the program does, in a nutshell, is batch-create images for use in education. Primarily flashcards, but it can also do things like convert said flashcards into smaller cards for use in games, or bingo sheets, or simple (e.g. Snakes & Ladders) boardgames. Basically, it reads an INI file (and optionally, commandline arguments) and makes the (overall image) canvas, then it will create an additional layer, stick text/images/draws onto that layer, and paste the layer onto the canvas. Rinse and repeat. So, for instance, to make the small cards, it will make a canvas, then draw a grid onto it (as a cutting aid and border for the cards), and then paste the images into the appropriate places between the guides.

I have internally threaded most operations, as I found that there were some things that Magick++ didn't thread. So just about everything runs in concurrence, only pausing for threads to end when syncing is required.

My main query is how to improve the performance of the Magick++ side of things. For instance, I'm using annotate to draw my text; is this the most efficient method for doing so, or would draw be faster? When I'm, for example, composeing a small layer onto a (relatively) small section of the main image, would it be faster to use the pixel cache, or would the overhead of initializing it outweigh any performance gains? Would converting the Image to a blob help (currently, I only use Images)?

The basic workflow is:
Image canvas(dimensions,background color);
Image layer;
while(layer deque.size()>0){
layer=Image(layer dimensions,layer background color);
for(loop=0;loop<elements deque.size();loop++){
if(elements deque[loop]=="Image")
//load that image from disk and trim and/or resize and/or rotate it, then compose it onto the layer
else if(elements deque[loop]=="text")
//annotate that text onto the layer
}
canvas.compose(layer);
layer deque.pop_front();
}
canvas.write("filename.png");

It's obviously more complicated than that (and threaded), but that's the idea.

Note that this is running on a powerful server (overclocked 6-core/12-logical i7, 16gb ddr4 -- soon to be upgraded to 32gb, 4 Samsung SSD raid 10), so I'm happy to make memory-for-speed tradeoffs, though disk access should be a minimal issue. When I go up to 32gb, I may well end up making a ramdisk to hold all of the input/output files (they don't need to be permanent, this is just the backend to a php frontend), in which case disk access will become a completely null point. And finally, while obviously the input images may be of any dimension (prior to resize), the output images are NOT extremely high resolution. These are intended for classroom use, e.g. printed onto a4/a3 paper, so 1260x1782 or so is typical. Not low resolution by any means, but not super-megapixel professional photographs by any means.

I'll also be compiling a customized magick++ (@q8), but that's the last step.

Re: optimizing performance in my application

Posted: 2016-11-07T19:38:56-07:00
by snibgo
Even without a disk, reading and writing files takes CPU time, especially when there is compression, so thinking about this is probably worthwhile.

For example, writing graphics to PNG, I get a 5:1 ratio of slowest vs fastest, depending on compression method. See my "Outputs: speed and size" page, though my timings include disk.

If you need to write temporary results, mpc or miff is generally quicker than other formats.

Re: optimizing performance in my application

Posted: 2016-11-07T20:55:15-07:00
by tsftd
Thanks, I write the pngs out with no compression (I use an external optimization program) -- and only write the image out once, when it is fully processed. That is to say, I can tell the program "make a flashcard for each image in folder X", and it will write as many images (flashcards) as are in folder X, but each output is written only pnce, when it is complete.

I assume that magick++ isn't disk writing without my knowledge? I seem to recall a cache setting, but I tgink that it defaults to a large enough number?

Re: optimizing performance in my application

Posted: 2016-11-07T21:16:16-07:00
by snibgo
If IM can't get enough memory for pixel caches, it will use disk instead, which is massively slower (of course). Users sometimes finds this happens unexpectedly, and it turns out their sysadmin has configured limits on memory per process or per user.

Re: optimizing performance in my application

Posted: 2016-11-07T22:35:59-07:00
by tsftd
I don't explicitly use pixel caches, are they used implicitly as part of the internal functions? And if so, then cacheThreshold should let me set it high enough to eliminate paging? FYI, I'm on Win10x64 (my Linux server is not nearly as beefy), compiling as 64-bit, and have no limits on mem use.

Re: optimizing performance in my application

Posted: 2016-11-08T00:14:47-07:00
by snibgo
Pixel caches are implicit. See http://www.imagemagick.org/script/architecture.php

I don't use Magick++ much, but I assume it's like the other interfaces: IM doesn't limit it's own use of memory unless you tell it to.