lib/stats: add history graphs for counters in debug browser.

- Use counters to record all sys stats.

- Show history graphs in counter's stat page.
  + Collect data from counter's three time series (1m, 10m, 1h).
  + Add javascript/css to render graphs with duration selectors.

- Minor improvements/fix:
  + Show stat name in all stat pages.
  + Add pretty print for TimeSeries data type.
  + Use the tail time (instead of the head time) for the start time of a time series.

It looks like this:
https://screenshot.googleplex.com/OyY3zCYekOn

Change-Id: I53b838c8470abe7ee76a3d460c4bea12cd1121e5
diff --git a/lib/stats/counter/counter.go b/lib/stats/counter/counter.go
index f99b3d3..e2b3dee 100644
--- a/lib/stats/counter/counter.go
+++ b/lib/stats/counter/counter.go
@@ -164,7 +164,7 @@
 	return stats.TimeSeries{
 		Values:     ts.values(),
 		Resolution: ts.resolution,
-		StartTime:  ts.time,
+		StartTime:  ts.tailTime(),
 	}
 }
 
diff --git a/lib/stats/stats_test.go b/lib/stats/stats_test.go
index fc67406..9e01f14 100644
--- a/lib/stats/stats_test.go
+++ b/lib/stats/stats_test.go
@@ -32,7 +32,7 @@
 }
 
 func TestStats(t *testing.T) {
-	now := time.Unix(1, 0)
+	now, start := time.Unix(1, 0), time.Unix(1, 0)
 	counter.TimeNow = func() time.Time { return now }
 
 	a := libstats.NewInteger("rpc/test/aaa")
@@ -112,17 +112,17 @@
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries10m", Value: s_stats.TimeSeries{
 			Values:     []int64{4},
 			Resolution: 10 * time.Second,
-			StartTime:  now.Truncate(10 * time.Second),
+			StartTime:  start.Truncate(10 * time.Second),
 		}},
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries1h", Value: s_stats.TimeSeries{
 			Values:     []int64{4},
 			Resolution: time.Minute,
-			StartTime:  now.Truncate(time.Minute),
+			StartTime:  start.Truncate(time.Minute),
 		}},
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries1m", Value: s_stats.TimeSeries{
 			Values:     []int64{4},
 			Resolution: time.Second,
-			StartTime:  now,
+			StartTime:  start,
 		}},
 	}
 	if !reflect.DeepEqual(result, expected) {
@@ -186,17 +186,17 @@
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries10m", Value: s_stats.TimeSeries{
 			Values:     []int64{4, 104},
 			Resolution: 10 * time.Second,
-			StartTime:  now.Truncate(10 * time.Second),
+			StartTime:  start.Truncate(10 * time.Second),
 		}},
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries1h", Value: s_stats.TimeSeries{
 			Values:     []int64{104},
 			Resolution: time.Minute,
-			StartTime:  now.Truncate(time.Minute),
+			StartTime:  start.Truncate(time.Minute),
 		}},
 		libstats.KeyValue{Key: "rpc/test/ddd/timeseries1m", Value: s_stats.TimeSeries{
 			Values:     []int64{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 104},
 			Resolution: time.Second,
-			StartTime:  now,
+			StartTime:  start,
 		}},
 	}
 	if !reflect.DeepEqual(result, expected) {
diff --git a/lib/stats/sysstats/sysstats.go b/lib/stats/sysstats/sysstats.go
index 434e0b7..e9d6a53 100644
--- a/lib/stats/sysstats/sysstats.go
+++ b/lib/stats/sysstats/sysstats.go
@@ -13,6 +13,7 @@
 	"reflect"
 	"runtime"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/shirou/gopsutil/cpu"
@@ -23,6 +24,12 @@
 	"v.io/x/lib/metadata"
 	"v.io/x/ref"
 	"v.io/x/ref/lib/stats"
+	"v.io/x/ref/lib/stats/counter"
+)
+
+var (
+	counters     = map[string]*counter.Counter{}
+	countersLock sync.Mutex
 )
 
 func init() {
@@ -60,15 +67,13 @@
 }
 
 func exportMemStats() {
-	mstats := stats.NewMap("system/memstats")
-
 	// Get field names to export.
 	var memstats runtime.MemStats
 	fieldNames := getFieldNames(memstats)
 	updateStats := func() {
 		var memstats runtime.MemStats
 		runtime.ReadMemStats(&memstats)
-		updateStatsMap(mstats, memstats, fieldNames)
+		updateStats("system/memstats", memstats, fieldNames)
 	}
 	// Update stats now and every 10 seconds afterwards.
 	updateStats()
@@ -92,8 +97,6 @@
 }
 
 func exportSysMem() {
-	sysMemStats := stats.NewMap("system/sysmem")
-
 	// Get field names to export.
 	var s mem.VirtualMemoryStat
 	fieldNames := getFieldNames(s)
@@ -101,7 +104,7 @@
 	// Update stats now and every 10 seconds afterwards.
 	updateStats := func() {
 		if s, err := mem.VirtualMemory(); err == nil {
-			updateStatsMap(sysMemStats, *s, fieldNames)
+			updateStats("system/sysmem", *s, fieldNames)
 		}
 	}
 	go func() {
@@ -113,8 +116,6 @@
 }
 
 func exportSysCpu() {
-	sysCpuStats := stats.NewMap("system/syscpu")
-
 	// Get field names to export.
 	type cpuStat struct {
 		Percent   float64
@@ -158,7 +159,7 @@
 			GuestNice: t.GuestNice,
 			Stolen:    t.Stolen,
 		}
-		updateStatsMap(sysCpuStats, s, fieldNames)
+		updateStats("system/syscpu", s, fieldNames)
 	}
 	go func() {
 		for {
@@ -174,8 +175,6 @@
 		return
 	}
 	for _, path := range strings.Split(strPaths, ",") {
-		sysDiskStats := stats.NewMap(fmt.Sprintf("system/sysdisk/%s", naming.EncodeAsNameElement(path)))
-
 		// Get field names to export.
 		var s disk.UsageStat
 		fieldNames := getFieldNames(s)
@@ -184,7 +183,7 @@
 		curPath := path
 		updateStats := func() {
 			if s, err := disk.Usage(curPath); err == nil {
-				updateStatsMap(sysDiskStats, *s, fieldNames)
+				updateStats(fmt.Sprintf("system/sysdisk/%s/%s", naming.EncodeAsNameElement(path)), *s, fieldNames)
 			}
 		}
 		go func() {
@@ -209,14 +208,55 @@
 	return fieldNames
 }
 
-func updateStatsMap(m *stats.Map, s interface{}, fieldNames []string) {
+func updateStats(rootName string, s interface{}, fieldNames []string) {
 	v := reflect.ValueOf(s)
-	kv := make([]stats.KeyValue, len(fieldNames))
-	for i, name := range fieldNames {
-		kv[i] = stats.KeyValue{
-			Key:   name,
-			Value: v.FieldByName(name).Interface(),
+	for _, name := range fieldNames {
+		counterName := fmt.Sprintf("%s/%s", rootName, name)
+		c := getCounter(counterName)
+		i := v.FieldByName(name).Interface()
+		v := int64(0)
+		switch t := i.(type) {
+		case bool:
+			if t {
+				v = 1
+			}
+		case int:
+			v = int64(t)
+		case int8:
+			v = int64(t)
+		case int16:
+			v = int64(t)
+		case int32:
+			v = int64(t)
+		case int64:
+			v = int64(t)
+		case uint:
+			v = int64(t)
+		case uint8:
+			v = int64(t)
+		case uint16:
+			v = int64(t)
+		case uint32:
+			v = int64(t)
+		case uint64:
+			v = int64(t)
+		case float32:
+			v = int64(t)
+		case float64:
+			v = int64(t)
+		default:
+			fmt.Fprintf(os.Stderr, "not exporting %q (type %T not supported)", name, t)
+			continue
 		}
+		c.Set(v)
 	}
-	m.Set(kv)
+}
+
+func getCounter(counterName string) *counter.Counter {
+	countersLock.Lock()
+	defer countersLock.Unlock()
+	if _, ok := counters[counterName]; !ok {
+		counters[counterName] = stats.NewCounter(counterName)
+	}
+	return counters[counterName]
 }
diff --git a/services/debug/debug/browseserver/assets.go b/services/debug/debug/browseserver/assets.go
index 8d6fc1b..edf4ccc 100644
--- a/services/debug/debug/browseserver/assets.go
+++ b/services/debug/debug/browseserver/assets.go
@@ -123,7 +123,7 @@
 	return a, nil
 }
 
-var _chromeHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x57\x4f\x6f\xdb\xb8\x13\xbd\xfb\x53\x4c\xf4\xc3\xef\xd2\x2d\xa5\xa4\x45\x8b\x26\x2b\xbb\x48\x93\xec\x6e\x81\x34\x5b\x20\xd9\x2e\xf6\x64\xd0\xd2\x58\x62\x43\x91\x06\x49\x5b\x31\x0c\x7f\xf7\x1d\x4a\xb2\x6b\xcb\xf2\xa1\xd0\x5a\x17\x53\xfc\xf3\x66\xde\x70\xde\x68\xbc\x5a\x45\xaf\x06\x40\xcf\x8d\x9e\x2d\x8d\xc8\x72\x07\x6f\xce\x2f\xde\xc3\x53\x8e\xf0\x8d\x2b\x9e\x8a\x79\x01\xd7\x73\x97\x6b\x63\x43\xb8\x96\x12\xaa\x4d\x16\x0c\x5a\x34\x0b\x4c\xc3\xea\xf4\x5f\x16\x41\x4f\xc1\xe5\xc2\x82\xd5\x73\x93\x20\x24\x3a\x45\xa0\xd7\x4c\x2f\xd0\x28\x4c\x61\xb2\x04\x0e\x9f\x1e\x6f\x99\x75\x4b\x89\xd5\x31\x29\x12\x54\x74\xd4\xe5\xdc\x41\xc2\x15\x4c\x10\xa6\x7a\xae\x52\x10\x8a\x26\x11\xee\x3f\xdf\xdc\x3d\x3c\xde\xc1\x54\x48\x0c\x07\xaf\xa2\xf5\x7a\x30\x88\xcf\x6e\xff\xbc\x79\xfa\xe7\xeb\x1d\xe4\xae\x90\xa3\x41\xec\x7f\xe0\xa5\x90\xca\x0e\x83\xdc\xb9\xd9\x55\x14\x95\x65\x19\x96\x6f\x43\x6d\xb2\xe8\xe2\xf2\xf2\x32\x7a\xf1\x7b\x82\x11\x1d\xce\x91\xa7\xa3\xca\x78\xec\x84\x93\x38\xba\xc5\xc9\x3c\xcb\x84\xca\x60\xb5\x0a\x1f\x3d\x27\xf3\xc0\x0b\x5c\xaf\xe3\xa8\xde\x50\x6f\x2e\xd0\x71\x50\xb4\x30\x0c\x16\x02\xcb\x99\x36\x2e\x20\x8e\xca\xa1\x72\xc3\xa0\x14\xa9\xcb\x87\x29\x2e\x88\x10\xab\x5e\x5e\x13\x05\xe1\x04\x97\xcc\x26\x5c\xe2\xf0\x22\x3c\x0f\x1a\x28\x29\xd4\x33\xc5\x4f\x0e\x83\x2a\x12\x36\x47\x24\xac\xdc\xe0\xb4\xf6\xdf\x12\x01\xeb\xb4\xe1\x19\x86\x99\xd6\x99\x44\x3e\x13\x36\x4c\x74\x11\xf9\xa0\x86\x19\xba\x22\x95\xa1\xd0\x11\x81\x86\xef\xa3\x82\x3b\x34\x64\x29\x74\x48\xe6\x26\x72\x8e\x61\x21\x54\x98\x58\xbb\xb1\x68\x13\x23\x66\x0e\xac\x49\x7a\x5a\xf0\xb8\xdf\x09\x36\x8e\x6a\xc8\x9f\x60\x34\xa5\x58\xd9\xb6\x35\x41\x11\xfc\x38\xe5\x85\x90\xcb\xe1\x97\xc6\xc8\x2f\x9f\x69\xf2\x87\xeb\x1e\xb0\x1e\xfb\x27\x9c\x8a\x17\x4c\xeb\x10\xc3\x6a\x3b\xed\x1f\x6f\x80\xd5\x58\x57\x50\x68\xa5\xed\x8c\x27\xf8\xeb\x76\x0f\xa5\xce\x66\x38\xd1\xe9\x12\x7c\x26\xa0\x69\x81\x4c\x78\xf2\x9c\x19\x9f\x82\x2c\xd1\x52\x9b\x2b\xf8\xdf\xf9\xf9\x87\xb7\x1f\x7e\x83\x33\x51\xf8\x4b\xe7\xca\xed\x42\x56\x3e\x46\x8d\x93\x71\x54\x67\xd7\x20\xf6\x06\x1a\x02\x67\x8c\x91\x6e\x4a\xbe\x24\x65\xe4\xba\xb4\x24\x82\xda\xf2\x6b\xc0\x05\x2a\x9f\xe9\xb6\xe0\x52\x92\x2b\x14\x53\x24\x3d\x84\xc0\x58\x73\x38\x15\x0b\x48\x24\xb7\x94\xd9\x74\x21\x4c\xf2\xa5\x9e\x3b\xf0\xc3\xef\x76\xf7\xad\x1e\x32\x56\x47\xa7\xc6\x0f\x7e\x44\x2d\x6e\xb8\x1e\x40\x8d\xc7\x07\x7b\x8f\xdb\xdd\x6c\x66\x46\x97\xad\x03\x5b\xa6\x4f\x5e\x32\x5b\xff\xf7\x96\xe9\x3a\xd4\x21\x28\xab\x44\x16\xd4\x32\xa4\x48\xd2\xa6\x23\xd0\xd7\x69\x0a\xd5\x95\x52\xe4\x9c\x06\x2e\x45\xa6\x48\x91\x0b\x91\x71\x27\xb4\xf2\x73\xbe\x64\xd4\x45\xac\xd3\x83\x4e\x56\xac\xc6\xf4\x39\x4d\xeb\x47\x6c\x3f\x6c\xcd\x84\xf0\x37\x42\x2e\x7c\x6d\x73\xdb\xbb\x3b\xbc\xb9\x3d\x04\x72\x72\xd7\xee\x8e\xcf\xbb\x77\x27\xb9\xc9\x90\xd5\x48\x4c\x2b\xb9\xec\x88\x71\x05\xc7\xbb\xc1\xc6\x63\x2f\xc3\x8d\xec\x7c\xa9\xfa\xa8\x86\xad\x9a\x16\x8c\xfc\x6f\x1c\xf1\x3e\xd0\x13\x52\xb8\xa5\x82\x69\xbb\xf0\x3f\x6d\x16\x7b\x1a\xb1\x8e\xbb\x4e\x03\x8f\x7e\xa1\x27\xb8\xd4\xdd\xce\xdf\xeb\xde\x7e\x67\x52\x4f\xba\xa0\x7f\xa7\xf9\x9e\xd0\x33\xa3\xfd\x77\xb0\xd3\xf3\xaf\xcd\x5a\x4f\x13\x0b\x67\x48\x0c\x9d\x16\x9e\xaa\x95\xbe\xb7\xba\x54\xc9\x84\xdb\xce\xcc\x7c\x6c\xd6\x3a\x4d\xc4\x11\x41\xb6\x8a\xd4\xbe\x5e\xeb\xe2\x8b\x66\x67\xe6\x48\x15\x4b\x0d\x2f\x0f\x4b\xde\x51\x91\x76\x95\xba\xd3\x48\xf0\xe4\xf2\x3b\x99\xf4\x4e\x24\xbb\x13\x49\xee\xc4\x72\x3b\xa5\xd4\x4e\x28\xb3\x96\xc4\xda\xf2\x2a\xb8\xe8\xf8\x7c\x8f\xc7\x4d\x0f\xdc\x96\x93\xc5\xa4\xfa\xc2\x35\x27\x9a\x57\xc6\xa8\xe1\xa7\x36\xaf\xfa\xf0\x65\x46\xa4\x5d\xe2\xca\xdf\x6d\x4e\xed\x34\x7b\xc1\xe8\xa0\x3d\xcf\xdf\xb5\x09\x34\x56\xf6\xa7\x57\xab\x89\xd4\xc9\x33\x04\x1b\x4f\x21\x5c\xaf\xbf\x78\x36\x37\xf5\x04\xfc\x81\x06\x57\x2b\x54\xe9\x7a\xbd\x0f\x98\x9b\x68\x44\xe7\x4b\x41\xcd\x66\x78\xa3\x8b\x82\xab\xf4\x5e\x28\x6c\xef\xeb\x45\x76\xb4\x03\x7c\x48\xaa\xda\xd4\x2a\x64\x09\x52\xcb\xb1\x19\x30\x76\xf1\xc6\xf7\xaa\xd0\x0e\x96\x0f\xd1\x41\x47\x73\x34\x46\x15\xfb\x0d\xd7\x99\x11\xca\x4d\x21\xf8\xff\x82\x82\xf5\xad\x4a\xd4\xff\x96\x72\x95\xe1\x3d\xc8\x52\xb7\x36\x33\xb8\x61\xe9\x87\x3f\xcd\x75\x27\xd1\x7d\x6a\x37\x0d\x77\x8d\x12\x47\x75\x03\x4f\x1e\x56\x7f\x31\xff\x0d\x00\x00\xff\xff\x20\x24\x2d\x10\x26\x0f\x00\x00")
+var _chromeHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x59\x6d\x6f\xe3\xb8\x11\xfe\x9e\x5f\xc1\x73\x51\xd8\xde\x8b\x24\x67\xef\x05\xbb\x5e\x3b\x87\x9c\x37\xbd\xdb\x36\x97\x3d\x34\xe9\x15\x45\x10\x04\xb4\x44\x4b\x5c\x53\xa4\x40\xd2\x76\x5c\xc3\xff\xbd\x43\x4a\xb2\x25\x5a\xca\x26\xe7\x26\xc0\xae\x25\x71\xf8\xcc\x0b\x67\x1e\x8e\xa8\xcd\x26\x78\x73\x82\xe0\x6f\x22\xb2\xb5\xa4\x71\xa2\xd1\xdb\xc1\xd9\x8f\xe8\x36\x21\xe8\x0f\xcc\x71\x44\x17\x29\xba\x58\xe8\x44\x48\xe5\xa3\x0b\xc6\x90\x15\x52\x48\x12\x45\xe4\x92\x44\xbe\x9d\xfd\x2f\x45\x90\x98\x21\x9d\x50\x85\x94\x58\xc8\x90\xa0\x50\x44\x04\xc1\x6d\x2c\x96\x44\x72\x12\xa1\xe9\x1a\x61\xf4\xf3\xcd\x47\x4f\xe9\x35\x23\x76\x1a\xa3\x21\xe1\x30\x55\x27\x58\xa3\x10\x73\x34\x25\x68\x26\x16\x3c\x42\x94\xc3\x43\x82\xae\x3e\x4d\x2e\xaf\x6f\x2e\xd1\x8c\x32\xe2\x9f\xbc\x09\xb6\xdb\x93\x93\xd1\x37\x1f\x3f\x4f\x6e\xff\xf3\xfb\x25\x4a\x74\xca\xce\x4f\x46\xe6\x07\x3d\xa6\x8c\xab\x71\x27\xd1\x3a\x1b\x06\xc1\x6a\xb5\xf2\x57\xdf\xf9\x42\xc6\xc1\xd9\xfb\xf7\xef\x83\x47\x23\xd3\x39\x87\xc9\x09\xc1\xd1\xb9\x55\x3e\xd2\x54\x33\x72\xfe\x91\x4c\x17\x71\x4c\x79\x8c\x36\x1b\xff\xc6\xf8\x24\xaf\x71\x4a\xb6\xdb\x51\x90\x0b\xe4\xc2\x29\xd1\x18\x71\x18\x18\x77\x96\x94\xac\x32\x21\x75\x07\x7c\xe4\x9a\x70\x3d\xee\xac\x68\xa4\x93\x71\x44\x96\xe0\x90\x67\x6f\x4e\xc1\x05\xaa\x29\x66\x9e\x0a\x31\x23\xe3\x33\x7f\xd0\x29\xa0\x18\xe5\x73\x88\x1f\x1b\x77\x6c\x24\x54\x42\x08\x60\x25\x92\xcc\x72\xfb\x15\x38\xa0\xb4\x90\x38\x26\x7e\x2c\x44\xcc\x08\xce\xa8\xf2\x43\x91\x06\x26\xa8\x7e\x4c\x74\x1a\x31\x9f\x8a\x00\x40\xfd\x1f\x83\x14\x6b\x22\x41\x93\xaf\x09\xa8\x9b\xb2\x05\xf1\x53\xca\xfd\x50\xa9\x52\xa3\x0a\x25\xcd\x34\x52\x32\x3c\x52\x83\xc1\xfd\x02\xb0\xa3\x20\x87\x7c\x81\x47\x33\x88\x95\x72\xb5\x51\x88\xe0\x4f\x33\x9c\x52\xb6\x1e\xff\x56\x28\xf9\xf6\x13\x3c\xdc\x9b\x6e\x00\xf3\x6b\xf3\xe7\xcf\xe8\x23\x89\xf2\x10\xa3\xcd\xee\xb1\xf9\x33\x0a\xbc\x1c\x6b\x88\x52\xc1\x85\xca\x70\x48\x3e\xec\x64\x20\x75\xca\xcb\xa9\x88\xd6\xc8\x64\x02\x91\x0e\xc8\x14\x87\xf3\x58\x9a\x14\xf4\x42\xc1\x84\x1c\xa2\xbf\x0c\x06\xef\xbe\x7b\xf7\x37\xf4\x0d\x4d\xcd\xa2\x63\xae\x1b\x21\x7d\x08\x98\x17\x61\x8d\x3d\x8d\xa7\x8c\x3c\x3c\x84\x84\x31\xcf\xe3\x82\x7b\x7c\x91\x82\x63\x21\xca\x24\x71\xb4\xa5\x58\x42\xe6\x0d\xd1\x20\x7b\xfc\x50\x1b\x58\x25\x54\x13\xcf\x3a\x30\x34\xf3\xbc\x95\xc4\x59\xb3\xde\x30\xc1\x52\x7b\x26\x13\x31\xe5\x8e\x3f\x99\x50\x90\x83\x02\x34\xc0\xe2\x60\x4d\x97\xa4\xaa\xc6\x06\x71\x88\xde\x0d\x1c\xf5\x09\x31\x25\x3e\x44\xdf\xd7\x07\xaa\x4a\xb1\x24\xd8\xb3\x9a\x5b\xf4\xe1\xa9\x12\x6c\xa1\x6b\xfa\x22\xaa\x32\x86\x61\x71\x20\x28\xcd\xeb\x52\xc1\xf5\x15\x61\x24\xd4\xc0\x1b\x9b\x26\x88\x29\x13\xe1\xbc\x19\x23\x5a\x48\x6c\x8c\xf0\x72\x04\x21\x5b\x82\x33\x15\x5a\x8b\x14\xfc\xaf\x7b\x2f\x73\xe7\xdf\x3a\x41\x79\xa6\x6b\x33\x46\x6a\xd3\xa0\x32\x88\x57\x06\xd4\xc5\x6c\x7e\xfe\xa4\x2f\x35\x0f\xc2\x85\x54\x26\x45\x33\x41\x81\x87\x64\xcd\x5c\x1c\x45\xc0\x69\x36\xb5\xd0\xf7\xf0\xaf\xf8\x7d\xa6\x9a\x21\x17\xba\xb7\x5b\x82\xfe\x30\x31\x24\x5e\x8f\xde\x61\xa1\x4c\x26\x93\x67\xc2\x37\x2f\x6e\x5b\xed\xcd\xaa\x8e\x15\x23\xb6\x40\xaa\xda\xcc\xff\xc0\x4a\x7b\xb6\x28\x49\x4f\xaf\x33\xe0\x6c\x4d\x1e\x75\xf0\x05\x2f\x71\xfe\xb4\x53\xe7\x42\xb3\x5d\xc4\x4a\x83\x91\x61\x4e\x82\x26\x03\x55\xc0\x84\x61\x88\x26\xc2\x7b\x12\xbb\x64\xab\xd9\x82\x87\xc6\x6d\x14\x49\xbc\xfa\x95\x1a\xc2\x5d\xff\x02\x75\x9c\xa8\x5e\xd4\xaf\x78\x1e\x04\xb0\xfb\x72\x08\xb0\x46\x86\x40\xfc\xdd\xc0\x12\x4b\xfb\x04\x8d\xd1\xdf\x6f\x3e\x5f\xfb\x19\x96\x8a\xc0\xdc\x0f\x35\x89\x39\x59\x2b\x90\xb8\xeb\x9e\xa5\xdd\x53\xd4\x3d\x1b\xe4\x3f\x49\xf7\x7e\x2f\x67\x64\xfc\x99\x90\x97\x38\x4c\x7a\xa5\x5d\xbd\x79\xbf\x5e\x5c\xa0\xea\x6e\x7e\x0f\x58\xc5\x95\x9f\xe2\x6c\x2f\x0d\x4b\xd6\x77\xf8\x4b\x12\xbd\x90\x1c\xdd\x71\xb2\x42\x1f\x81\xbe\x7b\xd6\xc2\x4f\x5c\x1b\xe1\xbb\xc1\x3d\x7a\x83\xce\x06\x83\x41\xbf\x7f\x8a\x6a\x23\x67\xf7\xfd\xfb\xea\xa2\x6e\x2b\x2e\x6d\x1d\xf7\x22\x32\xc3\x0b\xa6\x3f\x16\x39\x04\xd6\x19\xdf\x3e\x9c\xd4\xc2\x07\xb4\xa1\x09\xc2\xd0\x38\x28\x30\x29\x43\xb1\x0d\xb3\x7d\x50\x26\x1f\x2a\x93\x4f\xd5\x03\xbc\x27\x07\xf0\x5b\x84\xc0\xd5\x5c\xfb\x50\x59\x12\x7e\x6f\xec\x82\x9a\xb8\xc3\xcd\x35\xec\x8c\x7b\xd3\xf2\x8d\x2c\x67\x5f\xe5\x9b\x4c\xe9\x75\x8a\x59\x9d\x53\xb4\x01\xe6\x9e\xc3\xee\xaa\x86\x77\x9d\x50\x48\x62\xc5\x3a\xf7\x55\xdf\xea\x00\x60\xf6\x67\x7e\x05\x28\x13\xcc\x98\x29\x84\x7d\xdc\xeb\x41\xdf\x7b\xbb\x37\x1c\x16\x16\x15\x38\x15\x49\xeb\x9c\x79\x3a\x69\xf4\xd0\x82\x5c\x32\x62\xee\x7a\xdd\x88\x2e\xbb\xfd\x5a\x9d\xd5\x66\xfa\x21\xc3\x4a\x99\xbe\xc8\xc4\xdf\xd9\x72\xba\xf5\xfa\x2c\xa7\xe0\x2c\x23\x3c\x9a\x24\x94\x45\xbd\x3a\x5a\xbf\xb2\x7a\xed\x1e\x3d\xb5\x70\x45\x6a\x14\x12\x37\x85\xc0\x9f\x72\xb4\x15\xa4\xee\xf3\x13\xbb\xca\x33\xfc\x6f\x55\xd2\x16\x8a\x67\x26\x70\x1e\x87\x42\x78\x8c\x36\xdb\x0f\xce\xd0\x6e\xce\xc1\xe8\xb3\x28\xe1\xc0\x24\xbf\x36\xb8\x53\xfe\x92\x80\xa3\xc2\xde\x9c\x6a\xec\x75\xc3\x70\x3d\xfa\xfb\xbe\xa0\x5b\x97\xa5\x33\xd4\x9b\xa3\xf1\x78\xec\xf2\x84\xeb\xc7\x21\xec\xb7\x80\x8b\xca\x8d\xc8\x81\xdd\xd6\xee\x9c\x5a\xa8\x2e\xac\x05\x75\xdc\xb3\xa9\xa9\xc1\x6c\x43\x8b\x45\x99\x2f\xa9\x5a\x60\x46\xff\x6b\x6d\xf3\x81\x2b\xf1\xad\x69\x13\x7b\xce\xd4\x48\xfb\xb0\x71\x4f\xa0\xbf\x48\x39\x84\x0e\xe2\xa8\x69\x4a\x0c\x9f\xbb\x31\xac\x4b\x42\x8b\x39\x85\x44\x6c\x95\xfb\xa7\x58\xc1\xa6\x93\xb3\x7a\x83\xb5\x22\x33\x66\xd9\x1c\x71\x82\xb6\xef\x11\x4f\x9d\x91\x4a\x97\xe8\x0e\x31\x12\x43\x80\x86\x07\x60\xd5\x2e\xaa\x6b\x9a\xc0\xae\x23\xb0\x75\x91\xe0\x1d\x93\x02\x89\x36\x20\x0d\x9a\x1e\xee\xda\x83\x6e\xd1\xb5\xbb\x0a\xdc\x95\x6d\x50\xb9\xbc\x78\xa4\x8d\x1a\xa1\x56\xe0\x3d\x08\xb0\x15\xbc\x0c\xeb\xaf\x9a\x9e\xb3\xe4\x05\x24\x6e\xb7\x09\x8d\x91\x99\x36\x71\xfd\x1a\xcc\xbe\x29\x9a\xe4\xae\x6d\xe0\x5d\x98\x81\x15\x5a\x62\xae\xf2\x9d\xa9\xeb\xcc\xda\x1e\xae\x70\xde\xab\x3f\x91\x92\xc6\xd0\x89\x11\x6a\x4c\xe9\xbc\x25\x37\x7d\x4c\x2f\xd2\xa7\x65\xbe\xd4\xc9\xab\xca\x15\x07\x9c\x65\x19\xdd\x1e\x0f\xb4\xd0\x48\x29\xf8\x22\x22\xd9\xb1\x5b\xce\x25\xe5\x6d\xb3\xd0\x57\xf8\xfc\xcf\x13\x4b\x83\x82\xe7\x73\x4b\xd5\xf7\x5b\x68\x24\x0f\x99\xd4\x3c\x35\xbd\x07\x70\x73\x8b\x63\x55\x42\xaa\x62\xb9\x54\xd0\xba\xd3\x35\x01\xf4\xdd\x06\xad\xbe\x4f\x5d\x44\x11\x0a\x19\x0d\xe7\x28\x81\x4d\x8a\x15\x7b\x36\x81\xcd\x64\x6f\xd7\xcb\x77\x1b\x9b\xaa\x0b\xf9\x0f\xb2\x86\x38\xcc\xdb\x17\xdb\x70\xda\xe5\x12\x62\x74\x05\x6d\x35\x01\x17\x7a\x5d\x6b\x0c\x30\x60\x4b\xdf\xf4\x02\x23\xaa\xcb\x5f\x58\xd3\x24\x52\xd9\xc7\xda\x36\xab\xb6\x14\x68\x70\xe8\xe9\xe4\x7c\x0a\x68\x8b\x08\x53\xee\xc9\xc2\x33\x0d\x3c\xe4\xc7\x17\x99\xd5\x64\x8d\x4b\x68\x4e\x12\x6e\x0f\xf2\xea\xf0\x7a\xf7\x36\x57\xbc\x72\x8d\x82\xfc\xd4\xee\x64\x64\x0e\x6e\x8a\x57\xb0\x6f\x3c\x0f\x5d\xb0\x15\x86\x97\x1f\x20\xe4\x15\xf4\x4a\xc5\x89\xce\x29\x22\x90\x19\xe6\x04\x51\xa5\xd0\x4c\x43\x66\x02\x0e\x21\x5c\xf9\xc8\xf3\x8a\xc9\xc0\x25\xc8\xba\x36\xee\x98\x73\x1b\x78\x75\x17\x0b\x8d\xcc\xe5\x17\x55\xbd\xcb\x2f\x3d\x2f\x3f\x75\xca\xf1\x3b\xfb\xd3\xa8\x51\x71\x86\x74\x00\xf5\xf0\x70\x20\xdb\xae\xb7\x14\xf6\xa4\x58\x39\x13\x76\x9e\xde\x9a\xa3\xc8\x9d\xfd\xb5\x61\xd8\x04\xf8\x21\xa8\x67\x0f\x2f\x3b\xf9\xf1\x26\x84\x12\x84\x5a\xa0\x4d\x25\xdb\x93\x26\x88\x9c\x16\x08\xb6\x84\x98\x23\x8e\x97\x34\xce\x29\x1c\x9e\x99\xa3\xd8\xfc\x70\xb8\xd1\x82\x46\xaf\xf2\xd3\x2b\x69\x5e\x9d\x61\xbc\x45\xf7\xf5\x4e\x8d\x8f\xfe\x4d\x50\x42\xcd\x99\xb1\xde\xad\xdd\xe1\xca\xd5\x10\xc0\xc8\xaa\xde\x8a\xcd\xd5\xb5\x63\x58\xc6\xc4\xcb\x91\x3c\xc1\xd9\xba\x21\xc6\x16\x0e\x37\x83\x3d\x3c\x98\xe3\xcd\xf2\x38\xd3\x1c\x01\xff\xc4\xc7\xce\x59\x71\xe7\xdc\xfc\x8e\x02\x7c\x0c\x34\xf4\x83\x4a\x51\x1e\xab\x26\xfc\x9f\xcb\xc1\x23\x95\x98\x53\x8e\x46\x05\x37\x66\xe0\x48\x70\x26\x9a\x8d\xbf\x12\x47\xdb\x1d\x33\x31\x6d\x82\xfe\x05\x9e\x1f\x09\x9d\x49\x61\xbe\x2f\x34\x5a\xfe\x7b\x31\x76\xa4\x8a\x25\x74\x6b\x61\xb3\x86\x5b\x3b\x72\xec\xaa\xae\x79\x38\xc5\xaa\x31\x33\x6f\x8a\xb1\x46\x15\xa3\x00\x20\x1d\x92\xaa\xd7\x6b\x4e\xbe\x44\x56\x9e\xb4\xb0\x98\x69\x0f\x0f\x29\xaf\xb5\x48\x9b\xa8\xee\x75\x4a\xf0\xd5\xcb\xef\xd5\x4a\xef\x95\xca\xee\x95\x4a\xee\x95\xcb\xed\x35\x4b\xed\x15\xcb\xcc\x29\x31\xb7\xbc\x52\x68\xc1\x9b\xaa\xa9\xf8\xb6\xe8\x96\x93\x22\xf9\x99\x72\x31\xa3\xb8\xf5\xbc\x90\x98\x4f\x00\x76\xe3\x8b\x25\x8d\x9a\x8a\x2b\xf9\xa1\x9c\x55\xf9\x88\xd6\x39\x3f\xf8\xec\x99\xfc\xe0\x3a\x50\x68\xa9\x3f\xde\x6c\xec\x47\x18\xd4\x29\x2d\x45\xfe\x76\xfb\x9b\xf1\x66\x92\x3f\x40\xbf\x12\x49\x36\x1b\x78\xb3\xd8\xd6\xbb\xc2\x51\x22\x83\x73\x98\xbf\xa2\x3a\x41\xfe\x44\xa4\x29\xbc\x42\x5c\xc1\x9b\x88\x2b\x77\x94\xb3\xe7\x15\xe0\x43\xa7\xac\x90\x43\x64\xe6\x93\x1d\x2a\x2f\x3c\xef\xec\xad\xf9\x0e\x81\xdc\x60\x99\x10\x1d\x74\x34\xad\x31\xb2\xde\x97\xbe\x66\x92\x72\x3d\x43\x9d\xbf\x2e\x21\x58\x7f\xd8\x44\xfd\xff\xba\x6c\x33\xfc\x08\x67\xa1\x5b\xcb\x24\x29\xbd\x34\x97\x2f\xf6\xb5\x92\xe8\x26\xb5\x8b\x86\x3b\x47\x19\x05\x79\x03\x0f\x16\xda\x4f\xf7\xff\x0b\x00\x00\xff\xff\xad\x22\xf5\x5d\x7e\x20\x00\x00")
 
 func chromeHtmlBytes() ([]byte, error) {
 	return bindataRead(
@@ -263,7 +263,7 @@
 	return a, nil
 }
 
-var _statsHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x55\x5f\x4f\xdb\x30\x10\x7f\xcf\xa7\x38\x45\x6c\x02\x24\x27\x03\x69\x7b\x40\x21\x13\x83\x0e\x21\x31\x90\x80\xf5\x15\xb9\xf1\xa5\xf1\xe4\xda\x9d\xed\xc0\x2a\x2b\xdf\x7d\x97\xa4\x85\x02\x45\xfc\x11\xed\x4b\x7d\xe7\xfb\xf7\xfb\xdd\xe5\x1c\x42\xba\x1d\x01\xfd\x0e\xcd\x74\x66\xe5\xb8\xf2\xb0\xfb\x65\xe7\x1b\x5c\x55\x08\x43\xae\xb9\x90\xf5\x04\x0e\x6a\x5f\x19\xeb\x12\x38\x50\x0a\x3a\x23\x07\x16\x1d\xda\x1b\x14\x49\xe7\xfd\xdb\x21\x98\x12\x7c\x25\x1d\x38\x53\xdb\x02\xa1\x30\x02\x81\xc4\xb1\xb9\x41\xab\x51\xc0\x68\x06\x1c\x7e\x5c\x1e\x31\xe7\x67\x0a\x3b\x37\x25\x0b\xd4\xe4\xea\x2b\xee\xa1\xe0\x1a\x46\x08\xa5\xa9\xb5\x00\xa9\x49\x89\x70\x7a\x72\x38\x38\xbb\x1c\x40\x29\x15\x26\xd1\x76\xda\x34\x51\x14\x82\xc0\x52\x6a\x84\xb8\x30\xda\xa3\xf6\x71\xd3\x40\x08\xb2\x84\x64\xc8\x55\x8d\x64\x93\x39\x2c\xbc\x34\x1a\x0a\xc5\x9d\xdb\x8f\xe7\x22\x63\x94\xce\xa3\x85\x89\x50\x6c\x6c\xa5\x88\xf3\xae\x8c\x4c\xc8\x9b\x85\x69\x7b\x55\x20\xe1\x5c\x1c\x18\xdb\xd9\x65\x85\x51\x73\xdb\xce\xde\xf3\x91\xc2\x65\x0f\xc1\x3d\x67\xbd\xb6\x15\xff\xb8\xc7\x9a\x7b\x91\x31\x87\x8a\xea\xb9\xbb\x72\x15\x17\xe6\x96\xb1\x5d\x31\x5d\xca\xd1\xe7\x19\x19\x31\x7b\xa8\x6b\x7f\x21\xdc\x4a\x5f\xc1\xc6\xd8\x10\x60\xd8\xdb\x87\xee\x50\xe3\x4f\x6b\x26\xc3\xf3\x5f\xf7\x3c\x3c\x76\xcc\xbc\x7d\x1a\xad\xbf\x10\xab\xe1\x5c\x5f\xf7\x1c\x68\x62\x4f\xd7\x13\xb4\xb2\x88\xf3\x2e\x3c\x6c\x1e\x9b\xad\x2c\xf5\xe2\x23\x22\x66\x53\x8b\x79\x08\x3d\xa2\xa6\xc9\xd2\x56\x5e\x1d\x9c\xb4\x2b\x40\x7c\x10\xb2\xab\xd9\xf4\x23\x81\xd1\xdc\xfe\x43\xc1\x6e\xa5\xf0\x55\x4c\xf8\xa6\x56\x6a\x5f\x42\xfc\xe9\x2a\x86\x7b\xac\xaf\x47\x19\x02\x2a\xb7\xfe\xc6\x0e\x8f\x4e\xd7\x44\xc0\x62\x32\xdf\x08\x5a\x8b\xf5\x61\xee\x5b\xbe\x6e\xc8\x49\x9b\xe6\xf5\xb8\x49\xf3\xf0\xd3\x27\x45\x9b\x6f\xbe\xaf\x52\x5a\x58\x79\x94\xa5\xf3\xbd\x96\x47\x0b\x8e\xfa\x35\x78\xac\xcc\x68\x84\xe2\x1d\x8b\xb0\xfa\x9a\xb7\xce\x59\x4a\x87\xf7\xad\xc6\x5a\x3d\x44\x12\x82\xe5\x7a\x8c\x90\x1c\x56\x52\x09\x8b\xfa\x51\x27\x33\x25\xf3\x8c\x43\x65\xb1\xa4\xf2\x3c\xf7\xee\xbb\xde\x0f\xa1\xb6\xea\x6f\x8d\x76\x06\x1b\xc9\x65\xfb\xce\xd8\x33\x3e\x21\xfe\x3e\xbb\xe5\xbb\xa4\x69\x3a\x86\x5b\x5e\x39\xad\x0b\x0a\x15\xbd\x34\x39\x4f\xea\x19\x58\x4b\x6f\xdb\x8a\xaa\x06\x17\x17\xe7\x17\x9b\x21\x50\x72\xb2\x38\x39\x6a\xd3\x6d\xed\xc1\x3c\xdf\x4b\xb9\xb2\x74\xc1\xc4\xca\x6e\xf5\x9f\xf1\x7c\x91\x27\x5d\x0d\xef\x6b\x57\x26\xef\xda\xc3\xc9\x44\x72\xc5\x24\xbd\x8b\x2e\xce\xa5\x2e\x4d\x96\x3e\x83\xe3\x8d\x1d\x7e\x32\xd4\x2d\x05\xcf\x0c\x21\x2c\x4d\x63\xff\xff\x3f\x00\x00\xff\xff\xd3\x1e\x4b\xd1\x65\x08\x00\x00")
+var _statsHtml = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x56\x5f\x4f\xe3\x38\x10\x7f\xef\xa7\x18\x45\xdc\xf1\x47\x4a\x72\x20\xdd\x3d\xa0\x90\x13\x47\x7b\x2c\x12\x0b\x12\xed\xf6\x15\xb9\xf1\xa4\xf1\xca\xb5\xbb\xb6\x43\xb7\xb2\xf2\xdd\x77\x92\xb4\x50\xa0\x08\xb5\xdb\xf6\xa5\xf6\x78\xfe\xfd\x7e\x33\xce\xd8\xfb\xf8\xa4\x03\xf4\xbb\xd2\xd3\xb9\x11\xe3\xc2\xc1\xd9\x5f\xa7\xff\xc0\xa0\x40\x18\x32\xc5\xb8\x28\x27\x70\x59\xba\x42\x1b\x1b\xc1\xa5\x94\xd0\x28\x59\x30\x68\xd1\x3c\x21\x8f\x1a\xeb\x6f\x16\x41\xe7\xe0\x0a\x61\xc1\xea\xd2\x64\x08\x99\xe6\x08\xb4\x1d\xeb\x27\x34\x0a\x39\x8c\xe6\xc0\xe0\xbf\x7e\x37\xb4\x6e\x2e\xb1\x31\x93\x22\x43\x45\xa6\xae\x60\x0e\x32\xa6\x60\x84\x90\xeb\x52\x71\x10\x8a\x84\x08\xb7\x37\x57\xbd\xbb\x7e\x0f\x72\x21\x31\xea\x9c\xc4\x55\xd5\xe9\x78\xcf\x31\x17\x0a\x21\xc8\xb4\x72\xa8\x5c\x50\x55\xe0\xbd\xc8\x21\x1a\x32\x59\x22\xe9\x24\x16\x33\x27\xb4\x82\x4c\x32\x6b\x2f\x82\xc5\x36\x0c\x29\x9c\x43\x03\x13\x2e\xc3\xb1\x11\x3c\x48\x9b\x34\x12\x2e\x9e\x96\xaa\xf5\x51\x86\x84\x73\xb9\x08\xc3\xd3\xb3\x30\xd3\x72\xa1\xdb\xe8\x3b\x36\x92\xb8\x6a\xc1\x99\x63\x61\x2b\xad\xb7\xdf\xed\x5b\xc9\xcb\x36\x0c\x2d\x4a\xca\xe7\xf9\xc8\x16\x8c\xeb\x59\x18\x9e\xf1\xe9\x4a\x8c\x36\xce\x48\xf3\xf9\x6b\x59\x2b\x37\xef\x85\xed\x01\x5f\x9f\xd5\xe3\x63\x0b\x45\x11\x09\xaa\x9c\xa0\x11\x59\x90\xf6\x1d\xb1\x7e\xc7\x26\x98\xc4\x8e\xef\xc2\x61\x32\x35\x98\x7a\x1f\xd5\x8e\x6b\xbf\x55\x95\xc4\xb5\x68\xbd\x7f\x92\xae\x81\xe1\xfd\x4c\xb8\x02\x0e\xc6\x9a\x8a\x09\xe7\x17\xd0\x2c\x4a\xfc\xdf\xe8\xc9\xf0\xfe\xeb\x4b\x8d\xf7\x44\x4a\xe3\x1e\x8e\xae\xf5\xf1\x8e\x59\x69\x11\x6d\x43\xc9\x8e\x90\x0d\xe6\xd3\x5d\x02\xa3\x3b\xf9\x13\x79\x38\x13\xdc\x15\x01\xe1\x9b\x1a\xa1\x5c\x0e\xc1\x1f\x83\x00\x5e\xb0\x6e\x52\x78\x94\x76\xff\x85\x1d\x76\x6f\xf7\x44\xc0\xb2\x33\x37\x04\xad\xf8\xfe\x30\xb7\x25\xdf\x37\xe4\xa8\x0e\xb3\x29\xee\xe6\x96\x47\x03\x31\xc1\x3e\x79\x46\xdb\xa5\xb8\xfb\x23\xe2\x8b\xb0\x4e\x9b\xf9\xce\xae\xb4\xcd\x8c\x98\xba\x94\x1b\x36\x5b\xb8\xbe\x36\x6c\x5a\xd8\xa3\x43\x22\xa5\xaa\x0e\x89\xef\x85\xca\xef\x76\x03\x69\xbe\x1e\x02\x24\xa8\xf3\x5a\x4c\xae\x98\x46\x57\xda\xa1\x68\xed\x84\x4b\x3b\x4b\x1f\xed\x40\xbc\x96\x7a\x34\x42\xbe\xc5\x48\x2c\xfe\x4e\x6b\xe3\x24\xa6\xc5\x76\x43\xb2\x94\xaf\x11\x7a\x6f\x98\x1a\x23\x44\x57\x85\x90\xdc\xa0\x7a\x8b\x54\x8a\x34\x61\x50\x18\xcc\x29\x3d\x1a\x21\xf6\x5f\x75\xe1\x7d\x69\xe4\x8f\x12\xcd\x1c\x0e\xa2\x7e\xfd\xe2\x30\xed\x64\xf9\xd3\xae\x9e\x11\xe7\x4d\x3f\xd6\x5d\xc8\x88\x73\x72\xd5\xf9\x8c\xd9\x77\xf9\xf4\x8c\xa1\x57\xce\x9a\xac\x7a\x0f\x0f\xf7\x0f\x47\xde\x53\x70\xd2\xb8\xe9\xd6\xe1\x8e\xcf\x61\x11\xef\xb3\x58\x49\xbc\x64\x62\x6d\xb5\xda\x8f\xde\xf2\x42\x34\x39\x6c\x57\xae\x44\x3c\x97\x87\x91\x8a\x60\x32\x14\xf4\x42\xb2\x41\x2a\x54\xae\x93\xf8\x03\x1c\x1b\x56\xf8\xdd\x27\xa0\xa6\xe0\x83\x26\x84\x95\x6e\x6c\xff\x7f\x05\x00\x00\xff\xff\x1e\x32\xaf\xc4\x6f\x0a\x00\x00")
 
 func statsHtmlBytes() ([]byte, error) {
 	return bindataRead(
diff --git a/services/debug/debug/browseserver/assets/chrome.html b/services/debug/debug/browseserver/assets/chrome.html
index 8b00949..53c8f23 100644
--- a/services/debug/debug/browseserver/assets/chrome.html
+++ b/services/debug/debug/browseserver/assets/chrome.html
@@ -21,7 +21,145 @@
         body header {
             background-color: #00838F !important;
         }
+
+        .mdl-data-table__cell--non-numeric pre {
+            margin: 0px;
+            white-space: pre-wrap;
+        }
+
+        .chart-container {
+          position: relative;
+          width: 800px;
+          height: 400px;
+        }
+
+        .area-chart {
+          position: absolute;
+          display: none;
+        }
+
+        .area-chart.selected {
+          display: block;
+        }
+
+        .duration-selector-container {
+          bottom: 8px;
+          right: 20px;
+          position: absolute;
+          display: flex;
+          line-height: 20px;
+          height: 20px;
+        }
+
+        .duration-selector {
+          cursor: pointer;
+          padding: 0px 4px 0px 4px;
+        }
+
+        .duration-selector:not(.selected):hover {
+          background-color: #CCC;
+        }
+
+        .duration-selector.selected {
+          background-color: #00838f;
+          color: white;
+        }
     </style>
+    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
+    <script type="text/javascript">
+      function drawHistoryGraphs(d) {
+        // Convert data.
+        var data = JSON.parse(d);
+        var keys = ['1m', '10m', '1h'];
+        keys.forEach(function(k) {
+          data[k] = data[k].map(function(ele) {
+            return [new Date(parseInt(ele[0] * 1000)), parseInt(ele[1])];
+          });
+        });
+        var defaultDuration = '1h';
+
+        // Create and setup graphs and duration selectors.
+        var container = document.currentScript.parentNode;
+        google.charts.load("current", {packages:["corechart"]});
+        google.charts.setOnLoadCallback(function() {
+          // Create container for charts.
+          var chartContainer = document.createElement('div');
+          chartContainer.className = 'chart-container';
+          container.appendChild(chartContainer);
+
+          // Create container for duration selectors.
+          var durationSelectorContainer = document.createElement('div');
+          durationSelectorContainer.className = 'duration-selector-container';
+          container.appendChild(durationSelectorContainer);
+
+          // Create graphs and duration selectors.
+          var graphs = {};
+          var selectors = {};
+          keys.forEach(function(k) {
+            // Create graph.
+            var graph = document.createElement('div');
+            graphs[k] = graph;
+            graph.className = 'area-chart';
+            if (k === defaultDuration) {
+              graph.className += ' selected';
+            }
+            chartContainer.appendChild(graph);
+            var dt = new google.visualization.DataTable();
+            dt.addColumn('datetime', '');
+            dt.addColumn('number', '');
+            dt.addRows(data[k]);
+            var options = {
+              width: 800,
+              height: 400,
+              legend: {
+                position: 'none'
+              },
+              series: {
+                0: {
+                  color: '#00838F'
+                }
+              },
+              vAxis: {
+                format: 'short'
+              },
+              'chartArea': {
+                left: 80
+              },
+              backgroundColor: {fill: 'transparent'},
+            };
+            var chart = new google.visualization.AreaChart(graph);
+            chart.draw(dt, options);
+
+            // Create duration selector for this graph.
+            var selector= document.createElement('div');
+            selectors[k] = selector;
+            selector.className = 'duration-selector';
+            if (k === defaultDuration) {
+              selector.className += ' selected';
+            }
+            var selectorText = document.createTextNode(k);
+            selector.appendChild(selectorText);
+            durationSelectorContainer.appendChild(selector);
+          });
+
+          // Add click handler for each selector.
+          keys.forEach(function(k) {
+            var curKey = k;
+            selectors[k].addEventListener('click', function() {
+              keys.forEach(function(k) {
+                if (k == curKey) {
+                  graphs[k].className = 'area-chart selected';
+                  selectors[k].className = 'duration-selector selected';
+                } else {
+                  graphs[k].className = 'area-chart'
+                  selectors[k].className = 'duration-selector';
+                }
+              });
+            });
+          });
+        });
+      }
+    </script>
 </head>
 
 <body>
diff --git a/services/debug/debug/browseserver/assets/stats.html b/services/debug/debug/browseserver/assets/stats.html
index 8131230..462b6a7 100644
--- a/services/debug/debug/browseserver/assets/stats.html
+++ b/services/debug/debug/browseserver/assets/stats.html
@@ -9,6 +9,10 @@
     <div class="mdl-cell mdl-cell--12-col">
         <table class="mdl-data-table mdl-js-data-table mdl-data-table--selectable mdl-shadow--2dp">
             <tbody>
+                <tr>
+                    <td class="mdl-data-table__cell--non-numeric">Stat Name</td>
+                    <td class="mdl-data-table__cell--non-numeric"><pre>{{.StatName}}</pre></td>
+                </tr>
                 {{with $goVal := goValueFromVOM .Value}}
                 <tr>
                     <td class="mdl-data-table__cell--non-numeric">Value (Go)</td>
@@ -28,6 +32,12 @@
                     <td class="mdl-data-table__cell--non-numeric">Type (VDL)</td>
                     <td class="mdl-data-table__cell--non-numeric fixed-width">{{.Value.Type}}</td>
                 </tr>
+                {{with .TimeSeriesData}}
+                <tr>
+                    <td class="mdl-data-table__cell--non-numeric">History</td>
+                    <td class="mdl-data-table__cell--non-numeric"><script>drawHistoryGraphs('{{.}}')</script></td>
+                </tr>
+                {{end}}
             </tbody>
         </table>
     </div>
diff --git a/services/debug/debug/browseserver/browseserver.go b/services/debug/debug/browseserver/browseserver.go
index 7f63607..8a0fcad 100644
--- a/services/debug/debug/browseserver/browseserver.go
+++ b/services/debug/debug/browseserver/browseserver.go
@@ -8,6 +8,7 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"html"
@@ -38,6 +39,7 @@
 	"v.io/v23/vtrace"
 	"v.io/x/ref/services/debug/debug/browseserver/sbtree"
 	"v.io/x/ref/services/internal/pproflib"
+	s_stats "v.io/x/ref/services/stats"
 	"v.io/x/ref/services/syncbase/fake"
 )
 
@@ -337,6 +339,11 @@
 	} else if err == nil {
 		err = globErr
 	}
+	timeSeriesData, tsErr := h.GetTimeSeriesData(server, children, timeoutCtx)
+	if tsErr != nil {
+		err = tsErr
+	}
+
 	args := struct {
 		ServerName     string
 		CommandLine    string
@@ -346,15 +353,17 @@
 		Children       []string
 		ChildrenErrors []error
 		Globbed        bool
+		TimeSeriesData string
 		Error          error
 	}{
 		ServerName:     server,
 		Vtrace:         tracer,
-		StatName:       stat,
+		StatName:       strings.TrimPrefix(stat, "/"),
 		Value:          v,
 		Error:          err,
 		Children:       children,
 		ChildrenErrors: childrenErrors,
+		TimeSeriesData: timeSeriesData,
 		Globbed:        len(children)+len(childrenErrors) > 0,
 	}
 	if hasValue {
@@ -365,6 +374,47 @@
 	h.execute(h.ctx, w, r, "stats.html", args)
 }
 
+func (h *statsHandler) GetTimeSeriesData(server string, children []string, ctx *context.T) (string, error) {
+	// duration -> [[t0, v0], [t1, v1], ... , [tn, vn]]
+	timeSeriesData := map[string][][]string{}
+	for _, child := range children {
+		// Read data from time series related children.
+		if strings.Contains(child, "/timeseries") {
+			n := fmt.Sprintf("%s%s", naming.Join(server, "__debug", "stats"), child)
+			v, err := stats.StatsClient(n).Value(ctx)
+			if err != nil && verror.ErrorID(err) != verror.ErrNoExist.ID {
+				return "", err
+			}
+			var value interface{}
+			if err := v.ToValue(&value); err != nil {
+				return "", err
+			}
+			ts, ok := value.(s_stats.TimeSeries)
+			if !ok {
+				return "", fmt.Errorf("%q doesn't contain time series data", child)
+			}
+			d := [][]string{}
+			startTime := ts.StartTime.Unix()
+			resolutionInSeconds := int64(ts.Resolution / time.Second)
+			for i, v := range ts.Values {
+				curTime := startTime + int64(i)*resolutionInSeconds
+				d = append(d, []string{fmt.Sprintf("%d", curTime), fmt.Sprintf("%d", v)})
+			}
+			parts := strings.Split(child, "/")
+			duration := strings.TrimPrefix(parts[len(parts)-1], "timeseries")
+			timeSeriesData[duration] = d
+		}
+	}
+	if len(timeSeriesData) == 0 {
+		return "", nil
+	}
+	b, err := json.Marshal(timeSeriesData)
+	if err != nil {
+		return "", err
+	}
+	return string(b), nil
+}
+
 type logsHandler struct{ *handler }
 
 func (h *logsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
diff --git a/services/stats/types.go b/services/stats/types.go
index ccb6b52..215fdc8 100644
--- a/services/stats/types.go
+++ b/services/stats/types.go
@@ -53,3 +53,15 @@
 	v.Print(&b)
 	return b.String()
 }
+
+// Print writes textual output of the TimeSeries values.
+func (ts TimeSeries) Print(w io.Writer) {
+	fmt.Fprintf(w, "Start time: %v\nResolution: %v\nValues: %v", ts.StartTime, ts.Resolution, ts.Values)
+}
+
+// String returns the textual output of the TimeSeries values as string.
+func (ts TimeSeries) String() string {
+	var b bytes.Buffer
+	ts.Print(&b)
+	return b.String()
+}