Skip to content
Advertisement

How to correctly time speed of writing to a disk (i.e. file) in C

I have a Zynq SoC which runs a Linux system and would like to time the speed at which I can write to its SD card in C.

I have tried out clock() and clock_gettime() where for the latter, I have done the following:

#define BILLION 1000000000.0
#define BUFFER_SIZE 2097152
...

for (int i=0; i<100; i++) {
    memcpy(buf, channel->dma + offset, BUFFER_SIZE);
    
    /* Open file for output */
    FILE *f = fopen(path, "w");

    /* Start timer */
    clock_gettime(CLOCK_MONOTONIC, &start);

    /* Write data from cpu ram to sd card*/
    fwrite(buf, 1, BUFFER_SIZE, f);
    fclose(f);

    /* Stop timer and report result */
    clock_gettime(CLOCK_MONOTONIC, &end);
    elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / BILLION;
    printf("%lf secondsn", elapsed_time);
}

The times that I’m getting are around 0.019 seconds for 2097152 bytes which I believe is wrong because the speed of writing to the SD card is quoted as 10 MB/s and can’t possibly be the 110 MB/s that I appear to be getting. When I, instead put the timing code outside the loop and, basically, time how long it takes to write the whole 100*BUFFER_SIZE, I get a more reasonable 18 MB/s.

My question is, is it incorrect to try to time a single fwrite operation? Does clock_gettime() not give me the adequate accuracy/precision for that? I would like to have the most accurate value possible for how quickly I can write to the disk because it is a very important parameter in the design of the system and so this discrepancy I’m getting is rather disconcerting.

Advertisement

Answer

The Linux Kernel often caches read write access to disk storage. That is, it returns from the write call and does the actual writing in the background. It does that transparently, so that if you would read the same file, just after writing, you would get the results you wrote, even if they are not yet transferred and written completely to disk.

To force a complete write you can call the fsync function. It blocks until all file IO for a specific file has completed. In your case a call to

#include <unistd.h>

...
fwrite(...);
fsync(fileno(f));

should suffice.

Edit
as @pmg mentioned in the comments, there is also be buffering at stream level. Although it probably is not that large of a buffer, you can force the stream buffer to be written with a call to fflush() before the fsync.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement