Keith said:
The output statement is
fprintf(fp,"%u\n",fib(10));
where fib(10) is 3628800, so that's 7 digits *plus a new-line*. If a
new-line is written as a single character, that's 8 bytes per call.
Oooops, right... I didn't notice that new-line! *red-face*
However, 1 byte new-line is a UNIX thing, on Windows it's usually two
bytes, so my point still hold. ;-)
I did a benchmark, the best IO result was doing the
"Standard C IO no buffering" call, each fwrite() call
used buffer with 64 kb of data. Re-running the same
bench under Linux gave quite a suprise (see below)!!!
On Windows XP I got:
printing '3628800' 10 million times
------------------------------
Standard C IO by OP
Written 1220 pages of ca. size 65536 (80000000 bytes)
CPU time 7.03
DiskIO 11.11 Mb/s
------------------------------
Standard C IO
Written 1221 pages of ca. size 65536 (80019456 bytes)
CPU time 4.36
DiskIO 17.93 Mb/s
------------------------------
Standard C IO no buffering
Buffering turned off
Written 1221 pages of ca. size 65536 (80019456 bytes)
CPU time 2.53
DiskIO 30.86 Mb/s
$ gcc challenge.c stdio_c.c -O3
$ time ./a.out
printing '3628800' 10 million times
------------------------------
Standard C IO by OP
Written 1220 pages of ca. size 65536 (80000000 bytes)
CPU time 2.74
DiskIO 28.51 Mb/s
------------------------------
Standard C IO
Written 1221 pages of ca. size 65536 (80019456 bytes)
CPU time 0.27
DiskIO 289.42 Mb/s
------------------------------
Standard C IO no buffering
Buffering turned off
Written 1221 pages of ca. size 65536 (80019456 bytes)
CPU time 0.26
DiskIO 300.55 Mb/s
real 0m7.834s
user 0m2.528s
sys 0m0.756s
300.55 Mb/s is too good, the theoretical peek should
have been 150 Mb/s, I don't know why Linux is this
blitzing fast! Does it have anything to do with dual
core CPU??? *strange*
/*-------------- listing 'challenge.c' ------------------------*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#define FILE_NAME "log.txt"
#define IO_BLOCK_SIZE (64*1024)
unsigned int fac(int n)
{
if (n != 1)
return n * fac(n - 1);
else
return 1;
}
/* make_io_buf: from number 'u', fill a buffer with this value 'count' times
* return lenght of buffer
*/
static size_t make_io_buf(char *buf, size_t max_buf, size_t * count,
unsigned u)
{
int n, len;
unsigned char u_buf[32];
n = sprintf(u_buf, "%u\n", u);
assert(n == 8);
/* fill up the buffer */
for (len = 0; len + n <= (int)max_buf; len += n) {
strcpy(&buf[len], u_buf);
*count = *count + 1;
}
assert(len <= max_buf);
assert(len + n > max_buf);
return len;
}
static void print_diff(clock_t start, clock_t stop, size_t wr_cnt)
{
double s = (double)(stop - start) / CLOCKS_PER_SEC,
Mb = (double)wr_cnt / 1024000.0;
printf("Written %lu pages of ca. size %d (%lu bytes)\n",
wr_cnt / IO_BLOCK_SIZE, IO_BLOCK_SIZE, wr_cnt);
printf("CPU time %.2f\n", s);
printf("DiskIO %.2f Mb/s\n", Mb / s);
}
extern int stdio_op(const char *fname, const unsigned char *buf,
size_t buf_len);
extern int stdio_c(const char *fname, const unsigned char *buf, size_t
buf_len);
extern int stdio_nobuf(const char *fname, const unsigned char *buf,
size_t buf_len);
int main(void)
{
static unsigned char buffer[IO_BLOCK_SIZE];
size_t buf_len = 0, count = 0, wr_cnt = 0;
clock_t start, stop;
printf("printing '%u' 10 million times\n", fac(10));
printf("------------------------------\nStandard C IO by OP\n");
start = clock();
wr_cnt = stdio_op(FILE_NAME, NULL, 0);
stop = clock();
print_diff(start, stop, wr_cnt);
printf("------------------------------\nStandard C IO\n");
start = clock();
buf_len = make_io_buf(buffer, sizeof buffer, &count, fac(10));
wr_cnt = stdio_c(FILE_NAME, buffer, buf_len);
stop = clock();
print_diff(start, stop, wr_cnt);
printf("------------------------------\nStandard C IO no buffering\n");
start = clock();
buf_len = make_io_buf(buffer, sizeof buffer, &count, fac(10));
wr_cnt = stdio_nobuf(FILE_NAME, buffer, buf_len);
stop = clock();
print_diff(start, stop, wr_cnt);
remove( FILE_NAME );
return 0;
}
/*-------------- listing stdio_c.c ------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int stdio_op(const char *fname, const unsigned char *buf, size_t buf_len)
{
FILE *fp;
unsigned int loop, n=0;
if ( (fp = fopen( "log.txt", "a" )) != NULL )
for (loop=1; loop <= 10000000 ; loop++)
{
n += fprintf(fp,"%u\n",fac(10));
}
fclose (fp);
return n;
}
int stdio_c(const char *fname, const unsigned char *buf, size_t buf_len)
{
FILE *fp;
size_t loop
, count = buf_len / 8;
int wr_cnt = 0;
if ((fp = fopen(fname, "w+b")) != NULL) {
for (loop = 0; loop <= 10000000; loop += count) {
wr_cnt += fwrite(buf, 1, buf_len, fp);
}
fclose(fp);
}
return wr_cnt;
}
int stdio_nobuf(const char *fname, const unsigned char *buf, size_t buf_len)
{
FILE *fp;
size_t loop
, count = buf_len / 8;
int wr_cnt = 0;
if ((fp = fopen(fname, "w+b")) != NULL) {
if(0 == setvbuf(fp, NULL, _IONBF, 0 ))
puts( "Buffering turned off" );
for (loop = 0; loop <= 10000000; loop += count) {
wr_cnt += fwrite(buf, 1, buf_len, fp);
}
fclose(fp);
}
return wr_cnt;
}