Hello again,

It turns out that it's not a FAT issue, but that the same problem occurs on ext3 systems as well. I've written a small program to test the delays between writes, and the results are not very encouraging. Specially when the disk gets full (it always does, doesn't it?).

In my opinion, this should concert anyone who want to use a Linux box for storing a data stream (audio, video, whatever).

I've attached the source of the program I used. Basically, it loops on writing 32kB chunks of data to a file, creating a list of number telling how much time (in microseconds) elapsed since the last loop (to stdout). There are two modes of testing: One is to let it write as fast as possible, and the second is to put delays between writes, which simulates waiting for incoming data. If there is enough room, the program will write slightly less than 2 GB (guess why?).

Since Linux is a multitasking system, the results are not exactly repeatable. But the general impression is that writing to FAT or on ext3, on my laptop or on my desktop, they all behave more or less the same.

First test regards full-speed write. Data was simply written as fast as possible. For a non-full partition, the write operation dwelled typically 5.5 ms, with occasional bursts of 0.7-0.9 *seconds* delay on the write operation. When the partition gets full, things get even nastier. Several seconds of blocking was observed. 5 seconds, and up to 14 seconds delay typically appeared a few times for a 2 GB writing session.

Then I added a short sleep in the loop, in order to simulate data written at ~ 3MB/sec (which is reasonable for video capturing). This is far below the disk's physical capicity. The disk LED showed occasional flushes.

Results: For a non-full partition, occasional peaks of up to 60ms were observed, which is something one can live with, probably. At 3 MB/s this means 180 kB stuck in the buffer. But when the partition started to get full, peaks of 0.2-0.3 seconds started to appear. The latter means 900 kB waiting to go out, and this maybe explains why I originally had problems.

If you want to see how your system behaves, just compile the attached code and go:
./writefat output-junk-data-file > listfile

The list of loop timings will be in listfile. Use your favourite number cruncher to view graphs. (The program's name is due to "historic reasons"...) If you want to test the slower writing speeds, check the typical delay in the listfile, or see how fast the output file grows. The sleep period defined in the program itself is not reliable, since the operating system may not be able to sleep for too short periods.

And finally: Does an RAM FIFO help? Surprisingly, the answer is no. I did the following:

mknod mypipe p
mbuffer -i mypipe -o /fatfs/output-file &
./writefat mypipe > listfile

and was quite surprised to find delays of 0.2 sec. BTW, mbuffer seems to force the data to be flushed to disk much more often. The disk LED showed that writes occured all the time, unlike the direct write to file, in which flushes occured occasionally. And "mypipe" and "logfile" are on an ext3, while outfile-file is on FAT.

Insights, anybody?

   Eli

--
Web: http://www.billauer.co.il

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>

char junkdata[32768];

int main(int argc, char **argv) {
  FILE *f;

  struct timeval now, sleeptime;
  struct timezone junk;
  long prev_sec, prev_usec, deltat;
  int i;

  if (argc!=2) {
    fprintf(stderr, "Usage: %s output-filename\n", argv[0]);
    return 1;
  }

  f = fopen (argv[1], "wb");

  if (f==NULL) {
    fprintf(stderr, "Failed to open output file %s\n", argv[1]);
    return 1;
  }

  if (gettimeofday(&now, &junk) != 0) {
    fprintf(stderr, "gettimeofday() failed!\n");
    return 1;
  }

  prev_sec = now.tv_sec; prev_usec = now.tv_usec;

  for (i=0; i<2047*32; i++) { // Almost 2 GB
    
    // Time to sleep between writes. Check this program's output values
    // to see what you actually got as typical values. They may be
    // significantly longer than requested due to context switch overhead
    // when the desired time is very short.
    sleeptime.tv_sec = 0; 
    sleeptime.tv_usec = 100; // Yeah, right. The real value will be much longer
    
    // Next line should be commented out for full-speed
    // select(0, NULL, NULL, NULL, &sleeptime);
    
    if (fwrite (junkdata, 1, sizeof(junkdata), f) != sizeof(junkdata)) {
      fprintf(stderr, "Data write failed!\n");
      return 1;
    }
    
    if (gettimeofday(&now, &junk) != 0) {
      fprintf(stderr, "gettimeofday() failed!\n");
      return 1;
    }
  
    deltat = now.tv_sec - prev_sec;
    deltat = deltat * 1000000;
    deltat +=  now.tv_usec - prev_usec;

    prev_sec = now.tv_sec; prev_usec = now.tv_usec;

    printf("%ld\n", deltat);

  }
  
  fclose(f);
  return 0;
}

Reply via email to