# Different Performance when Saving different Formats

**URL:** <https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252>\
**Category:** C-style API\
**Tags:** performance\
**Created:** [October 19, 2017, 2:50pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252 "2017-10-19T14:50:35Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![taserface](https://avatars.discourse-cdn.com/v4/letter/t/22d042/32.png) [@taserface](https://forum.commonvisionblox.com/u/taserface)\
**Post date:** [October 19, 2017, 2:50pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/1 "2017-10-19T14:50:35Z")

</div>

I have notices that saving jpeg or tiff files in CVB is considerably slower than saving bmp images. Is the compression the only reason? What can I do if I need to save my images faster?

---

<div class="post-metadata">

**Author:** ![illusive](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/illusive/32/61_2.png) [@illusive](https://forum.commonvisionblox.com/u/illusive)\
**Post date:** [October 19, 2017, 3:01pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/2 "2017-10-19T15:01:36Z")

</div>

Hi @taserface! Haven’t seen you in a while here… 🙂

Whether or not I can help you depends on several things:

- What kind of images are you working with (mono/RGB? most importantly: how many bits per pixel?)
- What rates (how many images per second) do you need to save?
- Are you bound to a certain format? Do you have a preference for bitmap formats or would a streaming format also be an option?

---

<div class="post-metadata">

**Author:** ![taserface](https://avatars.discourse-cdn.com/v4/letter/t/22d042/32.png) [@taserface](https://forum.commonvisionblox.com/u/taserface)\
**Post date:** [October 19, 2017, 3:05pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/3 "2017-10-19T15:05:29Z")

</div>

I am working with 8 MPixel monochrome images with 10 bits per pixel of which I’ll need to save on average about 12 images per second. Streaming is not an option as it makes accessing individual images more difficult.

---

<div class="post-metadata">

**Author:** ![illusive](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/illusive/32/61_2.png) [@illusive](https://forum.commonvisionblox.com/u/illusive)\
**Post date:** [October 19, 2017, 3:33pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/4 "2017-10-19T15:33:02Z")

</div>

I see…  
I have played around a little and wrote a small test program to test different formats. In order to be able to benchmark all formats I have decided to use 8bpp, but adapting it to different bit-depths should be fairly easy. For simplicity I have used our new .Net wrapper (see [here](https://forum.commonvisionblox.com/t/introducing-experimental-cvb-net-cvb-and-cvbpy-api/205/2)). The figures are as follows:

| Format | Time to save 1 MPixel mono | Time to save 1 MPixel RGB |
| --- | --- | --- |
| BMP | 9.46 ms | 27.03 ms |
| MIO | 10.89 ms | 25.75 ms |
| JPG | 111.08 ms | 155.86 ms |
| TIF | 82.74 ms | 109.63 ms |
| PNG | 136.19 ms | 275.99 ms |
| J2K | 269.17 ms | 1368.79 ms |

Now, there is indeed a way to speed things up for all formats except BMP and MIO. To understand how one has to know that BMP and MIO are being saved directly by the _CVCImg.dll_, while all the other formats are catered to by the _CVCFile.dll_. If you call `WriteImageFile` in the _CVCImg.dll_, the function looks at the extension of the target file name and if that extension points to anything else but BMP or MIO, it’ll dynamically load the _CVCFile.dll_, pass the job over to that DLL and unload it once the file has been saved. This recurring saving and unloading of files can become a bit of a performance hog, so one workaround for you might be to make sure that the _CVCFile.dll_ is _not_ being unloaded between images. To do so, you simply need to call `LoadLibrary` and _not_ call `FreeLibrary` before you have saved all the images.

To access those two functions in C# you will of course need to import them first:

```auto
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string fileName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);

```

Then you can

```auto
...
var module = LoadLibrary("CVCFile.dll");
...
// save your images here
...
FreeLibrary(module)

```

When benchmarking with that fix in place the numbers are as follows (at leas on my machine):

| Format | Time to save 1 MPixel mono | Time to save 1 MPixel RGB |
| --- | --- | --- |
| BMP | 8.70 ms | 28.25 ms |
| MIO | 8.26 ms | 27.36 ms |
| JPG | 26.23 ms | 74.50 ms |
| TIF | 2.69 ms | 26.76 ms |
| PNG | 59.41 ms | 193.48 ms |
| J2K | 182.76 ms | 1300.56 ms |

The differences for BMP and MIO compared to the previous measurement are probably just fluctuations that would be averaged out when performing more measurements. The increase in speed for the _CVCFile.dll_ formats, however, is notable - at least for all formats except JPEG2000 which generally is a very computationally costly format. Speed may of course also vary with images content for the compressing formats (i.e. all except BMP and MIO), but judging from these numbers your chances are good to reach the required 12 fps with TIFF.

If the `LoadLibrary/FreeLibrary` workaround is not enough, however, I might be out of options here. Streaming formats can - with the help of hardware accelerated codecs - often reach significantly higher throughput, but these capabilities cannot be leveraged by `WriteImageFile` - one would need to code the compression in CUDA or OpenCL to reach similar speed. Plus streaming formats are usually limited to 8 bits per pixel. In summary: If the workaround is not fast enough for you you might need hardware acceleration.

BTW: You will only see these differences if you are _not_ using the Image and/or Display control in your application. Both controls are linked against the _CVCFile.dll_ and will keep the DLL open as long as there are instances of these controls active in your application.

---

<div class="post-metadata">

**Author:** ![illusive](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/illusive/32/61_2.png) [@illusive](https://forum.commonvisionblox.com/u/illusive)\
**Post date:** [October 19, 2017, 3:34pm UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/5 "2017-10-19T15:34:06Z")

</div>

Almost forgot: This is the code I used:

```auto
using Stemmer.Cvb;
using Stemmer.Cvb.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApp1
{
  class Program
  {
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);

    static void Main(string[] args)
    {
      // this 
      var handle = LoadLibrary("CVCFile.dll");

      using (var img = new Image(new Size2D(1024, 1024), 1))
      {
        // produce something that looks nice
        var plane0 = img.Planes[0].GetLinearAccess<byte>();
        var plane1 = img.Planes[1].GetLinearAccess<byte>();
        var plane2 = img.Planes[2].GetLinearAccess<byte>();
        for (int y = 0; y < img.Height; ++y)
          for (int x = 0; x < img.Width; ++x)
          {
            plane0[x, y] = (byte)(x & 0xff);
            plane1[x, y] = (byte)(y & 0xff);
            plane2[x, y] = (byte)((x + y) & 0xff);
          }

        // benchmark saving in different formats
        const int numCycles = 10;
        var formats = new string[] { "bmp", "mio", "jpg", "tif", "png", "j2k" };
        var stopwatch = new StopWatch(StopWatchMode.SingleCPU);
        foreach (var fmt in formats)
        {
          stopwatch.Start();
          for (int i = 0; i < numCycles; ++i)
            img.Save(@"w:\test." + fmt);
          var ms = stopwatch.TimeSpan.TotalMilliseconds / numCycles;
          Console.WriteLine("Format {0}: {1} ms per image of {2:F3} MB", fmt, ms, img.Width * img.Height * img.Planes.Count / 1024.0 / 1024.0);
        }      
      }

      FreeLibrary(handle);
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![taserface](https://avatars.discourse-cdn.com/v4/letter/t/22d042/32.png) [@taserface](https://forum.commonvisionblox.com/u/taserface)\
**Post date:** [October 20, 2017, 6:36am UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/6 "2017-10-20T06:36:49Z")

</div>

Hi @illusive,

Yes, that helps. With the LoadLibrary workaround I get about 15 fps on my machine which is good enough for the moment. But I don’t understand why the CVCFile.dll gets loaded dynamic in the first place - isn’t it kind of obvious tht this slows things down?

---

<div class="post-metadata">

**Author:** ![illusive](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/illusive/32/61_2.png) [@illusive](https://forum.commonvisionblox.com/u/illusive)\
**Post date:** [October 20, 2017, 8:59am UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/7 "2017-10-20T08:59:07Z")

</div>

You do have a point there…

The decision to load the _CVCFile.dll_ dynamically roughly followed this train of thought:

1. The _CVCFile.dll_ has numerous build-time dependencies (basically every format that it is capable of saving introduces a dependency on at least one library) which we did not want to burden the _CVCImg.dll_ with. So it made sense to us to gather all these in a separate DLL - that is how the _CVCFile.dll_ came to exist.
2. On the other hand, the _CVCFile.dll_ has a dependency on the _CVCImg.dll_ - so there would be a cyclic run-time _and_ build-time dependency which we considered unhealthy and resolved by loading the CVCFile.dll dynamically

You are right that the repetitive loading/unloading today is a bottleneck. When the design was decided upon, this was quite different and saving in excess of 10 MB per second as single image files simply was not a use case to be considered back then because of all the other bottlenecks involved (CPU speed, disk speed) so that spending an extra few milliseconds wasn’t considered a problem.

---

<div class="post-metadata">

**Author:** ![illusive](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/illusive/32/61_2.png) [@illusive](https://forum.commonvisionblox.com/u/illusive)\
**Post date:** [October 20, 2017, 11:43am UTC](https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/8 "2017-10-20T11:43:10Z")

</div>

Having said that, it’s possible we’ll reconsider that design in the future… 😉
