5

I have 1GB binary file which basically contains 3D cube of same type of values. Saving this kind of cube with different order ([x,y,z] or [z x, y]) takes a lot of time with fseek and fwrite. But one of software packages does this a lot faster than my program. Is there any approach to make file writing faster than one with fseek/fwrite?

Tae-Sung Shin
  • 20,215
  • 33
  • 138
  • 240
  • 5
    Maybe it writes the file in order and skips around in memory, instead of accessing memory in order by skipping around the file. Maybe it memory maps the file and is basically getting "better" I/O as a result (by not having to flush each time you seek). Maybe it uses a better buffer size. In short: there are a lot of ways that your code might be sub-optimal, which this other program could take advantage of to beat you. – Steve Jessop Aug 09 '12 at 00:37
  • It is hard to beat `fwrite` as far as the writing speed is concerned. Perhaps using `write` could save you a microsecond or two, but you would not get you from "slow" to "a lot faster". I would definitely avoid `fseek`, though. – Sergey Kalinichenko Aug 09 '12 at 00:47
  • @SteveJessop Thanks for your comment. They are very good points. But first point would not be possible since the buffer in the memory is also read from a different cube file - so I have to use seeks in either file. As for buffer size, I will try to increase and look for memory map approach. – Tae-Sung Shin Aug 09 '12 at 00:54
  • 1
    @david: I don't think that follows: you could read one file sequentially, then transpose the cube in memory, then write the other file sequentially. You just need a GB or two of RAM. No doubt there are systems that have 1GB of disk but not 1GB of RAM, but it's dratted bad luck if you're on one, since it means you've fallen into a fairly narrow window in the development of the platform over time ;-) Some kind of phone, I'd wager. – Steve Jessop Aug 09 '12 at 00:56
  • @SteveJessop I've tried to have all in memory but that didn't work -500MB was maximum as the program also uses memory for its other part. Since I have 6 GB memory, that restriction might come from the fact the program is written in VC6 32 bit. – Tae-Sung Shin Aug 09 '12 at 01:01

3 Answers3

7

You should not use fseek in the inner loop of file io operations. For the writing functions to be fast they cache the writes. If you seek all over the place you keep blowing the cache.

Do all your transformations in memory - e.g rotate the cube in memory, and then write the file in a few sequentual fwrite calls.

If you can't transform your data completely in memory, then assemble your cube one plane at a time in memory and write out each plane.

@edit:

In your case you don't want to use fseek at all. Not even one.

Do something like this:

void writeCubeZYX( int* cubeXYZ, int sizeOfCubeXYZ, FILE* file )
{
   int* cubeZYX = malloc( sizeOfCubeXYZ );

   // all that monkey business you're doing with fseek is done inside this
   // function copying memory to memory. No file IO operations in here.
   transformCubeXYZ_to_ZYX( cubeXYZ, cubeZYX, sizeOfCubeXYZ );

   // one big fat very fast fwrite. Optimal use of file io cache.
   fwrite(  file, cubeZYX, 1, sizeOfCubeXYZ );

   free( cubeZYX ); // quiet pedantry.
}

@edit2:

Ok suppose you can't transform it all in memory then transform it in planes and write out one plane at a time - in file order - that is with no fseeks.

So say an [XYZ] cube is laid out in memory as a series of Z [XY] matrices. That is the [XY] planes of your cube are contiguous in memory. And you want to write out as [ZYX]. So in the file you want to write out a series of X [ZY] matrices. Each [ZY] will be contiguous in the file.

So you do something like this:

void writeCubeZYX( int* cubeXYZ, int x, int y, int z, FILE* file )
{
   int sizeOfPlaneZY = sizeof( int ) * y * z; 
   int* planeZY = malloc( sizeOfPlaneZY );

   for ( int i = 0; i < X; i++ )
   {
      // all that monkey business you're doing with fseek is done inside this
      // function extracting one ZY plane at a time. No file IO operations in here.
      extractZYPlane_form_CubeXYZ( cubeXYZ, planeZY, i );

      // in X big fat very fast fwrites. Near optimal use of file io cache.
      fwrite(  file, planeZY, 1, sizeOfPlaneZY );
   } 

   free( planeZY ); // quiet pedantry.
}    
Rafael Baptista
  • 11,181
  • 5
  • 39
  • 59
  • That (your last suggestion) is exactly what I was doing. But think about conversion from cube with [x,y,z] to one with [z, x, y]. Using one plane, you will need nx*ny*nz number of seeks. Please tell me if this is not true. – Tae-Sung Shin Aug 09 '12 at 01:07
  • Well, I don't know how you decided I can put everything in memory but that's not true. The monkey business should be done since there can be cubes with larger size such as 4GB or even 10GB. If I can put all in memory, .... – Tae-Sung Shin Aug 09 '12 at 04:08
  • In my case cubeXYZ is not in memory either. But anyway, I understand your point and know what to do now - buffer with maximum size would be answer. Thanks for your patience in the process. – Tae-Sung Shin Aug 09 '12 at 18:03
1

If you are doing a lot of random access writing. I suggest you use mmap. mmap maps memory pages to your file and it is controlled by the OS. Similar to memory swap mechanism.

Another way is you can use Asynchronous IO. It is provided by GLIBC http://www.gnu.org/software/libc/manual/html_node/Asynchronous-I_002fO.html

It simply puts the data in a queue in memory then creates another thread to manage IO.

0

If you don't mind having the file on disk be a compressed file, then it may be faster to compress it as you write it. This speeds things up because the bottleneck is usually writing bytes to disk, and by compressing as you write you reduce the number of bytes you need to write.

This will of course depend on whether your data is amenable to compression. One option for compressing output in c++ is gzip. E.g.: How do I read / write gzipped files?

But in your case, this may not be applicable -- It's unclear from your question exactly when/why you're fseeking. What is your expected pattern of writes?

Community
  • 1
  • 1
Edward Loper
  • 15,374
  • 7
  • 43
  • 52