github.com/kayoticsully/syncthing@v0.8.9-0.20140724133906-c45a2fdc03f8/cmd/syncthing/usage_report.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/json"
     8  	"net"
     9  	"net/http"
    10  	"runtime"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/calmh/syncthing/model"
    15  )
    16  
    17  // Current version number of the usage report, for acceptance purposes. If
    18  // fields are added or changed this integer must be incremented so that users
    19  // are prompted for acceptance of the new report.
    20  const usageReportVersion = 1
    21  
    22  var stopUsageReportingCh = make(chan struct{})
    23  
    24  func reportData(m *model.Model) map[string]interface{} {
    25  	res := make(map[string]interface{})
    26  	res["uniqueID"] = strings.ToLower(myID.String()[:6])
    27  	res["version"] = Version
    28  	res["longVersion"] = LongVersion
    29  	res["platform"] = runtime.GOOS + "-" + runtime.GOARCH
    30  	res["numRepos"] = len(cfg.Repositories)
    31  	res["numNodes"] = len(cfg.Nodes)
    32  
    33  	var totFiles, maxFiles int
    34  	var totBytes, maxBytes int64
    35  	for _, repo := range cfg.Repositories {
    36  		files, _, bytes := m.GlobalSize(repo.ID)
    37  		totFiles += files
    38  		totBytes += bytes
    39  		if files > maxFiles {
    40  			maxFiles = files
    41  		}
    42  		if bytes > maxBytes {
    43  			maxBytes = bytes
    44  		}
    45  	}
    46  
    47  	res["totFiles"] = totFiles
    48  	res["repoMaxFiles"] = maxFiles
    49  	res["totMiB"] = totBytes / 1024 / 1024
    50  	res["repoMaxMiB"] = maxBytes / 1024 / 1024
    51  
    52  	var mem runtime.MemStats
    53  	runtime.ReadMemStats(&mem)
    54  	res["memoryUsageMiB"] = mem.Sys / 1024 / 1024
    55  
    56  	var perf float64
    57  	for i := 0; i < 5; i++ {
    58  		p := cpuBench()
    59  		if p > perf {
    60  			perf = p
    61  		}
    62  	}
    63  	res["sha256Perf"] = perf
    64  
    65  	bytes, err := memorySize()
    66  	if err == nil {
    67  		res["memorySize"] = bytes / 1024 / 1024
    68  	}
    69  
    70  	return res
    71  }
    72  
    73  func sendUsageReport(m *model.Model) error {
    74  	d := reportData(m)
    75  	var b bytes.Buffer
    76  	json.NewEncoder(&b).Encode(d)
    77  
    78  	var client = http.DefaultClient
    79  	if BuildEnv == "android" {
    80  		// This works around the lack of DNS resolution on Android... :(
    81  		tr := &http.Transport{
    82  			Dial: func(network, addr string) (net.Conn, error) {
    83  				return net.Dial(network, "194.126.249.13:443")
    84  			},
    85  		}
    86  		client = &http.Client{Transport: tr}
    87  	}
    88  	_, err := client.Post("https://data.syncthing.net/newdata", "application/json", &b)
    89  	return err
    90  }
    91  
    92  func usageReportingLoop(m *model.Model) {
    93  	l.Infoln("Starting usage reporting")
    94  	t := time.NewTicker(86400 * time.Second)
    95  loop:
    96  	for {
    97  		select {
    98  		case <-stopUsageReportingCh:
    99  			break loop
   100  		case <-t.C:
   101  			err := sendUsageReport(m)
   102  			if err != nil {
   103  				l.Infoln("Usage report:", err)
   104  			}
   105  		}
   106  	}
   107  	l.Infoln("Stopping usage reporting")
   108  }
   109  
   110  func stopUsageReporting() {
   111  	select {
   112  	case stopUsageReportingCh <- struct{}{}:
   113  	default:
   114  	}
   115  }
   116  
   117  // Returns CPU performance as a measure of single threaded SHA-256 MiB/s
   118  func cpuBench() float64 {
   119  	chunkSize := 100 * 1 << 10
   120  	h := sha256.New()
   121  	bs := make([]byte, chunkSize)
   122  	rand.Reader.Read(bs)
   123  
   124  	t0 := time.Now()
   125  	b := 0
   126  	for time.Since(t0) < 125*time.Millisecond {
   127  		h.Write(bs)
   128  		b += chunkSize
   129  	}
   130  	h.Sum(nil)
   131  	d := time.Since(t0)
   132  	return float64(int(float64(b)/d.Seconds()/(1<<20)*100)) / 100
   133  }