I am curious why the performance of my logging routines (using O_APPEND) are so poor on MacOS, and did some testing. The performance is quite bad. Is this a known problem with APFS?
These tests are on a Mac Mini 2018 (Intel) running Sonoma 14.5.
(a) Internal SSD formatted as APFS. (And the performance is worse if the file already exists!)
bll-mac:/Volumes/Users/bll/bdj4/src$ rm -f tt-out.txt; time $HOME/bdj4/src/tt & time $HOME/bdj4/src/tt &
real 0m11.294s
user 0m0.073s
sys 0m6.144s
real 0m11.391s
user 0m0.143s
sys 0m12.304s
(b) /Volumes/spare is an External HDD formatted as HFS. (system info says the protocol is USB).
bll-mac:/Volumes/spare$ rm -f tt-out.txt; time $HOME/bdj4/src/tt & time $HOME/bdj4/src/tt &
real 0m4.223s
user 0m0.058s
sys 0m2.681s
real 0m4.241s
user 0m0.057s
sys 0m2.680s
(c) On the same external HDD on an APFS partition.
bll-mac:/Volumes/Avail-big$ rm -f tt-out.txt; time $HOME/bdj4/src/tt & time $HOME/bdj4/src/tt &
real 0m10.238s
user 0m0.136s
sys 0m11.497s
real 0m10.239s
user 0m0.203s
sys 0m17.234s
(d) Just for comparison, on Linux, on an SSD (SATA).
bll-g7:bll$ time ./tt & time ./tt &
real 0m2.213s
user 0m0.033s
sys 0m1.200s
real 0m2.227s
user 0m0.047s
sys 0m1.228s
(e) And on MacOS, the internal SSD with O_APPEND off: The speed here is more reasonable, though twice as slow as Linux.
bll-mac:/Volumes/Users/bll/bdj4/src$ rm -f tt-out.txt; time $HOME/bdj4/src/tt x & time $HOME/bdj4/src/tt x &
real 0m2.316s
user 0m0.039s
sys 0m1.119s
real 0m2.331s
user 0m0.118s
sys 0m3.339s
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
enum {
LCOUNT = 100000,
TCOUNT = 8,
};
int
fileSharedOpen (const char *fname, int appflag)
{
int fd;
int flags;
if (fname == NULL || ! *fname) {
return -1;
}
flags = O_WRONLY | O_CREAT;
if (appflag) {
flags |= O_APPEND;
}
fd = open (fname, flags, 0600);
return fd;
}
ssize_t
fileSharedWrite (int fd, const char *data, size_t len)
{
ssize_t rc;
rc = write (fd, data, len);
return rc;
}
void
fileSharedClose (int fd)
{
close (fd);
return;
}
void
process (int flag)
{
int fd;
char tdata [400];
size_t len;
strcpy (tdata, "aaaaaaaaaaaaa");
strcat (tdata, "bbbbbbbbbbbbb");
strcat (tdata, "ccccccccccccc");
strcat (tdata, "\n");
len = strlen (tdata);
fd = fileSharedOpen ("tt-out.txt", flag);
for (int i = 0; i < LCOUNT; ++i) {
fileSharedWrite (fd, tdata, len);
}
fileSharedClose (fd);
}
int
main (int argc, char *argv [])
{
int flag;
flag = true;
if (argc > 1) {
flag = false;
}
for (int i = 0; i < TCOUNT; ++i) {
pid_t pid;
pid = fork ();
if (pid != 0) {
process (flag);
exit (0);
}
}
process (flag);
return 0;
}