client/android: instrument memory usage.

also try to GC and return memory to OS every 5 seconds, but
that barely makes a dent in the real problem.

more later.

Change-Id: I2979e099121bdcb8578124b1c45714313cc2ec09
This commit is contained in:
Brad Fitzpatrick 2014-01-26 22:05:02 -08:00
parent f4d9fab966
commit 0072a5b325
2 changed files with 52 additions and 4 deletions

View File

@ -33,11 +33,15 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"runtime/debug"
"strconv" "strconv"
"sync" "sync"
"time"
"camlistore.org/pkg/blob" "camlistore.org/pkg/blob"
"camlistore.org/pkg/blobserver" "camlistore.org/pkg/blobserver"
"camlistore.org/pkg/osutil"
"camlistore.org/pkg/schema" "camlistore.org/pkg/schema"
) )
@ -48,6 +52,7 @@ var androidOutput, _ = strconv.ParseBool(os.Getenv("CAMPUT_ANDROID_OUTPUT"))
// child process and should report its output in the form that the // child process and should report its output in the form that the
// Android uploader app expects. // Android uploader app expects.
func IsChild() bool { func IsChild() bool {
memOnce.Do(startMemGoroutine)
return androidOutput return androidOutput
} }
@ -93,6 +98,17 @@ func (ni *namedInt) Incr(delta int64) {
Printf("STAT %s %d\n", ni.name, nv) Printf("STAT %s %d\n", ni.name, nv)
} }
func (ni *namedInt) Set(v int64) {
ni.Lock()
if v == ni.val {
ni.Unlock()
return
}
ni.val = v
ni.Unlock()
Printf("STAT %s %d\n", ni.name, v)
}
var ( var (
statDNSStart = &namedInt{name: "dns_start"} statDNSStart = &namedInt{name: "dns_start"}
statDNSDone = &namedInt{name: "dns_done"} statDNSDone = &namedInt{name: "dns_done"}
@ -109,6 +125,9 @@ var (
statBlobExisted = &namedInt{name: "blob_existed"} statBlobExisted = &namedInt{name: "blob_existed"}
statFileUploaded = &namedInt{name: "file_uploaded"} statFileUploaded = &namedInt{name: "file_uploaded"}
statFileExisted = &namedInt{name: "file_existed"} statFileExisted = &namedInt{name: "file_existed"}
statMemReleased = &namedInt{name: "mem_heap_released"}
statMemAlloc = &namedInt{name: "mem_alloc"}
statMemRSS = &namedInt{name: "mem_rss"}
) )
type statTrackingConn struct { type statTrackingConn struct {
@ -212,7 +231,13 @@ func Dial(network, addr string) (net.Conn, error) {
statTCPFail.Incr(1) statTCPFail.Incr(1)
return nil, fmt.Errorf("couldn't split %q", addr) return nil, fmt.Errorf("couldn't split %q", addr)
} }
c, err := net.Dial(network, net.JoinHostPort(androidLookupHost(host), port)) if OnAndroid() {
// Only do the Android DNS lookups when actually
// running on a device. We also run in "Android mode"
// (IsChild) in tests and interactive debugging.
host = androidLookupHost(host)
}
c, err := net.Dial(network, net.JoinHostPort(host, port))
if err != nil { if err != nil {
statTCPFail.Incr(1) statTCPFail.Incr(1)
return nil, err return nil, err
@ -323,3 +348,26 @@ func (w writeUntilSliceFull) Write(p []byte) (n int, err error) {
*w.s = s *w.s = s
return len(p), nil return len(p), nil
} }
var memOnce sync.Once
func startMemGoroutine() {
if !androidOutput {
return
}
go func() {
var ms runtime.MemStats
n := 0
for {
runtime.ReadMemStats(&ms)
statMemReleased.Set(int64(ms.HeapReleased))
statMemAlloc.Set(int64(ms.Alloc))
statMemRSS.Set(osutil.MemUsage())
time.Sleep(1 * time.Second)
n++
if n%5 == 0 {
debug.FreeOSMemory()
}
}
}()
}

View File

@ -188,7 +188,7 @@ func (c *Client) TransportForConfig(tc *TransportConfig) http.RoundTripper {
httpStats.VerboseLog = tc.Verbose httpStats.VerboseLog = tc.Verbose
} }
transport = httpStats transport = httpStats
if android.OnAndroid() { if android.IsChild() {
transport = &android.StatsTransport{transport} transport = &android.StatsTransport{transport}
} }
return transport return transport
@ -816,7 +816,7 @@ func (c *Client) DialFunc() func(network, addr string) (net.Conn, error) {
trustedCerts := c.getTrustedCerts() trustedCerts := c.getTrustedCerts()
if !c.useTLS() || (!c.InsecureTLS && len(trustedCerts) == 0) { if !c.useTLS() || (!c.InsecureTLS && len(trustedCerts) == 0) {
// No TLS, or TLS with normal/full verification // No TLS, or TLS with normal/full verification
if android.OnAndroid() { if android.IsChild() {
return func(network, addr string) (net.Conn, error) { return func(network, addr string) (net.Conn, error) {
return android.Dial(network, addr) return android.Dial(network, addr)
} }
@ -827,7 +827,7 @@ func (c *Client) DialFunc() func(network, addr string) (net.Conn, error) {
return func(network, addr string) (net.Conn, error) { return func(network, addr string) (net.Conn, error) {
var conn *tls.Conn var conn *tls.Conn
var err error var err error
if android.OnAndroid() { if android.IsChild() {
con, err := android.Dial(network, addr) con, err := android.Dial(network, addr)
if err != nil { if err != nil {
return nil, err return nil, err