Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File IO fsync(os.File.Sync) extremely slow on macOS Big Sur #43342

Closed
ideawu opened this issue Dec 23, 2020 · 3 comments
Closed

File IO fsync(os.File.Sync) extremely slow on macOS Big Sur #43342

ideawu opened this issue Dec 23, 2020 · 3 comments

Comments

@ideawu
Copy link

ideawu commented Dec 23, 2020

What version of Go are you using (go version)?

$ go version
go version go1.15.6 darwin/amd64

MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/xxx/Library/Caches/go-build"
GOENV="/Users/xxx/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/xxx/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/xxx/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/yf/8xz2qnj133b64kgnk5qhh8vw0000gn/T/go-build497324902=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Write codes to test fsync() with Golang and C.

file: bench-fsync.go

package main

import (
	"os"
	"fmt"
)

func main() {
	filename := "go.txt"
	os.Remove(filename)
	fp, err := os.OpenFile(filename, os.O_CREATE | os.O_APPEND | os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}
	count := 1000
	for i:=0; i<count; i++ {
		var err error
		s := fmt.Sprintf("%010d\n", i)
		_, err = fp.WriteString(s)
		if err != nil {
			panic(err)
		}
		err = fp.Sync()
		if err != nil {
			panic(err)
		}
	}
	fp.Close()

	fmt.Printf("%d fsync\n", count)
}

file: bench-fsync.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main(int argc, char** argv) {
	const char *filename = "c.txt";
	if(unlink(filename) != 0 && errno != ENOENT){
		printf("%d error: %s\n", __LINE__, strerror(errno));
		exit(1);
	}
	int fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0644);
	if(fd == -1){
		printf("%d error: %s\n", __LINE__, strerror(errno));
		exit(1);
	}

	int SIZE = 1000;

	for(int i=0; i<SIZE; i++){
		char buf[16];
		snprintf(buf, sizeof(buf), "%010d\n", i);

		int ret;
		ret = write(fd, buf, strlen(buf));
		if(ret == -1){
			printf("%d error: %s\n", __LINE__, strerror(errno));
			exit(1);
		}
		ret = fsync(fd);
		if(ret == -1){
			printf("%d error: %s\n", __LINE__, strerror(errno));
			exit(1);
		}
	}

	printf("%d fync\n", SIZE);

	return 0;
}

Run:

$ go build bench-fsync.go
$ time ./bench-fsync 
1000 fsync

real	0m22.768s
user	0m0.405s
sys	0m0.808s

$ time ./bench-fsync 
1000 fsync

real	0m22.297s
user	0m0.159s
sys	0m0.571s

$ gcc -O2 bench-fsync.c 
$ time ./a.out 
1000 fync

real	0m0.580s
user	0m0.003s
sys	0m0.022s

$ time ./a.out 
1000 fync

real	0m0.074s
user	0m0.004s
sys	0m0.030s

What did you expect to see?

Golang File IO fsync is not so slow.

What did you see instead?

Golang File IO fsync is extremely slow, compare with C.

  • Golang - 1000 fsync in 22 seconds
  • C - 1000 fsync in 0.074s seconds
@ideawu ideawu changed the title File IO fsyn(os.File.Sync) extremely slow on macOS Big Sur File IO fsync(os.File.Sync) extremely slow on macOS Big Sur Dec 23, 2020
@shmsr
Copy link
Contributor

shmsr commented Dec 23, 2020

MacBook Pro (15-inch, Mid 2015)
OS: MacOS Catalina 10.15.4

You can use bufio package for buffered write:

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	filename := "go.txt"
	os.Remove(filename)
	fp, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}

	count := 1000
	b := bufio.NewWriter(fp)
	for i := 0; i < count; i++ {
		_, err = b.WriteString(fmt.Sprintf("%010d\n", i))
		if err != nil {
			panic(err)
		}
		err = b.Flush()
		if err != nil {
			panic(err)
		}
	}
	fp.Close()

	fmt.Printf("%d fsync\n", count)
}

Benchmarks:

Not using bufio (Original Program):

$ /usr/bin/time ./bench_non_bufio
1000 fsync
       11.00 real         0.07 user         0.24 sys

Using bufio:

$ /usr/bin/time ./bench_with_bufio
1000 fsync
        0.38 real         0.00 user         0.00 sys

@ideawu
Copy link
Author

ideawu commented Dec 23, 2020

Well, it seems on macOS fsync() doesn't really persist data to disk according to this issue: #26650 so the comparison doesn't make sense then.

@ideawu ideawu closed this as completed Dec 23, 2020
@shmsr
Copy link
Contributor

shmsr commented Dec 23, 2020

Ah, okay! Maybe we can close this issue, then!

@golang golang locked and limited conversation to collaborators Dec 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants