2

I am interested if there is a theoretical speed difference between

fwrite(str , 1 , 100 , fp );

and

fwrite(str , 100 , 1 , fp );

based on how the function is written in glibc, and how many write calls it makes and how it is buffered (disregarding hardware differences on gcc).

devgirl05
  • 173
  • 7
  • 2
    The `fwrite` function is defined to write "from the array pointed to by ptr, up to nmemb elements whose size is specified by size". So, from a coding style perspective, your code should state *the truth*. If you're writing 100 integers of `sizeof(int) == 4`, your nmemb should be 100 and your size should be 4. If you're writing 400 `char`, your nmemb should be 400 and your size should be 1. Trying to "optimize" at this level is usually a waste of time and reduces readability of your source. (And, as the answer shows, doesn't actually do anything anyway.) – DevSolar Apr 17 '23 at 11:27
  • 1
    Have you looked at the code for fwrite? eg: https://github.com/lattera/glibc/blob/master/libio/iofwrite.c . There's essentially no speed difference between 1, 100 and 100, 1 because the two are multiplied together in the source code to get the number of bytes to write. – Paul Hankin Apr 17 '23 at 11:28
  • 1
    Related question here: https://stackoverflow.com/questions/4350785/performance-of-fwrite-and-write-size – nielsen Apr 17 '23 at 11:43

2 Answers2

7

There's no difference for musl or glibc, or the FreeBSD libc since they all call an underlying function with size*nmemb:

musl

size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f)
{
    size_t k, l = size*nmemb;
    // ...
    k = __fwritex(src, l, f);

glibc

size_t
_IO_fwrite (const void *buf, size_t size, size_t count, FILE *fp)
{
  size_t request = size * count;
  // ...
  written = _IO_sputn (fp, (const char *) buf, request);

freebsd

    n = count * size;
    // ...
    uio.uio_resid = iov.iov_len = n;
    // ...
    if (__sfvwrite(fp, &uio) != 0)
AKX
  • 152,115
  • 15
  • 115
  • 172
1

I wrote 2 pieces of code to examine the difference between their performance.

a.c:

#include <stdlib.h>
#include <stdio.h>

int
main() {

        char* str = "Hello\n";
        FILE* fd = fopen("out.txt", "w");
        for (int i=0; i<1000; i++) 
                fwrite(str , 1 , 100 , fd);

        fclose(fd);
        return 0;

}

b.c:

#include <stdlib.h>
#include <stdio.h>

int
main() {

        char* str = "Hello\n";
        FILE* fd = fopen("out.txt", "w");
        for (int i=0; i<1000; i++) 
                fwrite(str , 100 , 1 , fd);
        fclose(fd);
        return 0;
}

Output:


(a.riahi@asax.local@U-Riahi:cplay) > gcc a.c
(a.riahi@asax.local@U-Riahi:cplay) > time ./a.out 

real    0m0.001s
user    0m0.001s
sys 0m0.000s
(a.riahi@asax.local@U-Riahi:cplay) > gcc b.c
(a.riahi@asax.local@U-Riahi:cplay) > time ./a.out 

real    0m0.001s
user    0m0.000s
sys 0m0.001s

There no real difference between them.

Amir reza Riahi
  • 1,540
  • 2
  • 8
  • 34
  • these minimal differences happen accidentially (e.g.: the 'faster' version uses more sys time). Btw.: writing 100 bytes starting with `str` causes UB as it points to a string literal of only only 6 bytes including `'\0`' and you call `fopen()` 1000 times without closing it. – Ingo Leonhardt Apr 17 '23 at 11:38
  • @IngoLeonhardt Thanks for mentioning it. It edited the answer. – Amir reza Riahi Apr 17 '23 at 11:50
  • When posting a benchmark, it would be useful to specify on which platform (e.g. compiler, library and operating system) you performed the benchmark. – Andreas Wenzel Apr 17 '23 at 12:18