mirror of
https://github.com/octoleo/syncthing.git
synced 2025-01-03 15:17:25 +00:00
Simple reproducible syncing benchmark
This commit is contained in:
parent
9af586d4ac
commit
7bc4589d4d
@ -8,14 +8,12 @@ package integration_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
mr "math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -23,6 +21,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(42)
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
id1 = "I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"
|
id1 = "I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"
|
||||||
id2 = "JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"
|
id2 = "JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"
|
||||||
@ -34,6 +36,7 @@ var env = []string{
|
|||||||
"STTRACE=model",
|
"STTRACE=model",
|
||||||
"STGUIAPIKEY=" + apiKey,
|
"STGUIAPIKEY=" + apiKey,
|
||||||
"STNORESTART=1",
|
"STNORESTART=1",
|
||||||
|
"STPERFSTATS=1",
|
||||||
}
|
}
|
||||||
|
|
||||||
type syncthingProcess struct {
|
type syncthingProcess struct {
|
||||||
@ -42,6 +45,7 @@ type syncthingProcess struct {
|
|||||||
port int
|
port int
|
||||||
apiKey string
|
apiKey string
|
||||||
csrfToken string
|
csrfToken string
|
||||||
|
lastEvent int
|
||||||
|
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
logfd *os.File
|
logfd *os.File
|
||||||
@ -114,17 +118,46 @@ func (p *syncthingProcess) peerCompletion() (map[string]int, error) {
|
|||||||
return comp, err
|
return comp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type event struct {
|
||||||
|
ID int
|
||||||
|
Time time.Time
|
||||||
|
Type string
|
||||||
|
Data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *syncthingProcess) events() ([]event, error) {
|
||||||
|
resp, err := p.get(fmt.Sprintf("/rest/events?since=%d", p.lastEvent))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var evs []event
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&evs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p.lastEvent = evs[len(evs)-1].ID
|
||||||
|
return evs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type versionResp struct {
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
func (p *syncthingProcess) version() (string, error) {
|
func (p *syncthingProcess) version() (string, error) {
|
||||||
resp, err := p.get("/rest/version")
|
resp, err := p.get("/rest/version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
bs, err := ioutil.ReadAll(resp.Body)
|
defer resp.Body.Close()
|
||||||
resp.Body.Close()
|
|
||||||
|
var v versionResp
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(bs), nil
|
return v.Version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileGenerator struct {
|
type fileGenerator struct {
|
||||||
@ -147,12 +180,12 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := 1 << uint(mr.Intn(maxexp))
|
s := 1 << uint(rand.Intn(maxexp))
|
||||||
a := 128 * 1024
|
a := 128 * 1024
|
||||||
if a > s {
|
if a > s {
|
||||||
a = s
|
a = s
|
||||||
}
|
}
|
||||||
s += mr.Intn(a)
|
s += rand.Intn(a)
|
||||||
|
|
||||||
src := io.LimitReader(&inifiteReader{fd}, int64(s))
|
src := io.LimitReader(&inifiteReader{fd}, int64(s))
|
||||||
|
|
||||||
@ -172,12 +205,12 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Chmod(p1, os.FileMode(mr.Intn(0777)|0400))
|
err = os.Chmod(p1, os.FileMode(rand.Intn(0777)|0400))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.Now().Add(-time.Duration(mr.Intn(30*86400)) * time.Second)
|
t := time.Now().Add(-time.Duration(rand.Intn(30*86400)) * time.Second)
|
||||||
err = os.Chtimes(p1, t, t)
|
err = os.Chtimes(p1, t, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -187,9 +220,20 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadRand(bs []byte) (int, error) {
|
||||||
|
var r uint32
|
||||||
|
for i := range bs {
|
||||||
|
if i%4 == 0 {
|
||||||
|
r = uint32(rand.Int63())
|
||||||
|
}
|
||||||
|
bs[i] = byte(r >> uint((i%4)*8))
|
||||||
|
}
|
||||||
|
return len(bs), nil
|
||||||
|
}
|
||||||
|
|
||||||
func randomName() string {
|
func randomName() string {
|
||||||
var b [16]byte
|
var b [16]byte
|
||||||
rand.Reader.Read(b[:])
|
ReadRand(b[:])
|
||||||
return fmt.Sprintf("%x", b[:])
|
return fmt.Sprintf("%x", b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,20 +7,34 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
mr "math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadRand(bs []byte) (int, error) {
|
||||||
|
var r uint32
|
||||||
|
for i := range bs {
|
||||||
|
if i%4 == 0 {
|
||||||
|
r = uint32(rand.Int63())
|
||||||
|
}
|
||||||
|
bs[i] = byte(r >> uint((i%4)*8))
|
||||||
|
}
|
||||||
|
return len(bs), nil
|
||||||
|
}
|
||||||
|
|
||||||
func name() string {
|
func name() string {
|
||||||
var b [16]byte
|
var b [16]byte
|
||||||
rand.Reader.Read(b[:])
|
ReadRand(b[:])
|
||||||
return fmt.Sprintf("%x", b[:])
|
return fmt.Sprintf("%x", b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,12 +61,12 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := 1 << uint(mr.Intn(maxexp))
|
s := 1 << uint(rand.Intn(maxexp))
|
||||||
a := 128 * 1024
|
a := 128 * 1024
|
||||||
if a > s {
|
if a > s {
|
||||||
a = s
|
a = s
|
||||||
}
|
}
|
||||||
s += mr.Intn(a)
|
s += rand.Intn(a)
|
||||||
|
|
||||||
src := io.LimitReader(&inifiteReader{fd}, int64(s))
|
src := io.LimitReader(&inifiteReader{fd}, int64(s))
|
||||||
|
|
||||||
@ -72,12 +86,12 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Chmod(p1, os.FileMode(mr.Intn(0777)|0400))
|
err = os.Chmod(p1, os.FileMode(rand.Intn(0777)|0400))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.Now().Add(-time.Duration(mr.Intn(30*86400)) * time.Second)
|
t := time.Now().Add(-time.Duration(rand.Intn(30*86400)) * time.Second)
|
||||||
err = os.Chtimes(p1, t, t)
|
err = os.Chtimes(p1, t, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -36,8 +36,8 @@
|
|||||||
<localAnnouncePort>21025</localAnnouncePort>
|
<localAnnouncePort>21025</localAnnouncePort>
|
||||||
<localAnnounceMCAddr>[ff32::5222]:21026</localAnnounceMCAddr>
|
<localAnnounceMCAddr>[ff32::5222]:21026</localAnnounceMCAddr>
|
||||||
<parallelRequests>16</parallelRequests>
|
<parallelRequests>16</parallelRequests>
|
||||||
<maxSendKbps>0</maxSendKbps>
|
<maxSendKbps>50000</maxSendKbps>
|
||||||
<maxRecvKbps>0</maxRecvKbps>
|
<maxRecvKbps>50000</maxRecvKbps>
|
||||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||||
<startBrowser>false</startBrowser>
|
<startBrowser>false</startBrowser>
|
||||||
<upnpEnabled>true</upnpEnabled>
|
<upnpEnabled>true</upnpEnabled>
|
||||||
|
90
test/transfer-bench_test.go
Normal file
90
test/transfer-bench_test.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||||
|
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build integration
|
||||||
|
|
||||||
|
package integration_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBenchmarkTransfer(t *testing.T) {
|
||||||
|
log.Println("Cleaning...")
|
||||||
|
err := removeAll("s1", "s2", "h1/index", "h2/index")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Generating files...")
|
||||||
|
err = generateFiles("s1", 10000, 22, "../bin/syncthing")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Starting up...")
|
||||||
|
sender := syncthingProcess{ // id1
|
||||||
|
log: "1.out",
|
||||||
|
argv: []string{"-home", "h1"},
|
||||||
|
port: 8081,
|
||||||
|
apiKey: apiKey,
|
||||||
|
}
|
||||||
|
ver, err := sender.start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println(ver)
|
||||||
|
|
||||||
|
receiver := syncthingProcess{ // id2
|
||||||
|
log: "2.out",
|
||||||
|
argv: []string{"-home", "h2"},
|
||||||
|
port: 8082,
|
||||||
|
apiKey: apiKey,
|
||||||
|
}
|
||||||
|
ver, err = receiver.start()
|
||||||
|
if err != nil {
|
||||||
|
sender.stop()
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println(ver)
|
||||||
|
|
||||||
|
var t0 time.Time
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
evs, err := receiver.events()
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
|
log.Println("...")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sender.stop()
|
||||||
|
receiver.stop()
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range evs {
|
||||||
|
if ev.Type == "StateChanged" {
|
||||||
|
data := ev.Data.(map[string]interface{})
|
||||||
|
if data["repo"].(string) != "default" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Println(ev)
|
||||||
|
if data["to"].(string) == "syncing" {
|
||||||
|
t0 = ev.Time
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if t0 != (time.Time{}) && data["to"].(string) == "idle" {
|
||||||
|
log.Println("Sync took", ev.Time.Sub(t0))
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.stop()
|
||||||
|
receiver.stop()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user