Exemplo n.º 1
0
// getTraceDBEntries returns a map of tracedb.Entry instances.
func (b *BenchData) getTraceDBEntries() map[string]*tracedb.Entry {
	ret := make(map[string]*tracedb.Entry, len(b.Results))
	keyPrefix := b.keyPrefix()
	for testName, allConfigs := range b.Results {
		for configName, result := range allConfigs {
			key := fmt.Sprintf("%s:%s:%s", keyPrefix, testName, configName)

			// Construct the Traces params from all the options.
			params := util.CopyStringMap(b.Key)
			params["test"] = testName
			params["config"] = configName
			util.AddParams(params, b.Options)

			// If there is an options map inside the result add it to the params.
			if resultOptions, ok := result["options"]; ok {
				if opts, ok := resultOptions.(map[string]interface{}); ok {
					for k, vi := range opts {
						if s, ok := vi.(string); ok {
							params[k] = s
						}
					}
				}
			}

			// We used to just pick out only "min_ms" as the only result of a bunch
			// of key, value pairs in the result, such as max_ms, mean_ms, etc. Now
			// nanobench uploads only the metrics we are interested in, so we need to
			// use all the values there, except 'options'.
			for k, vi := range result {
				if k == "options" {
					continue
				}

				floatVal, ok := vi.(float64)
				if !ok {
					glog.Errorf("Found a non-float64 in %s", key)
					continue
				}

				params["sub_result"] = k
				perResultKey := key
				if k != "min_ms" {
					perResultKey = fmt.Sprintf("%s:%s", perResultKey, k)
				}
				paramsCopy := util.CopyStringMap(params)
				ret[perResultKey] = &tracedb.Entry{
					Params: paramsCopy,
					Value:  types.BytesFromFloat64(floatVal),
				}
			}
		}
	}
	return ret
}
Exemplo n.º 2
0
func _main(tile *tiling.Tile, ts db.DB) {
	commits := []*db.CommitID{}
	for i, commit := range tile.Commits {
		cid := &db.CommitID{
			Timestamp: time.Unix(commit.CommitTime, 0),
			ID:        commit.Hash,
			Source:    "master",
		}
		commits = append(commits, cid)
		values := map[string]*db.Entry{}
		if !*skip {
			for traceid, tr := range tile.Traces {
				if !tr.IsMissing(i) {
					values[traceid] = &db.Entry{
						Params: tr.Params(),
					}
					if *gold {
						values[traceid].Value = []byte(tr.(*types.GoldenTrace).Values[i])
					} else {
						values[traceid].Value = ptypes.BytesFromFloat64(tr.(*ptypes.PerfTrace).Values[i])
					}
				}
			}
			glog.Infof("Adding: %d", i)
			if err := ts.Add(cid, values); err != nil {
				glog.Errorf("Failed to add data: %s", err)
			}
		}
	}
	begin := time.Now()
	if len(commits) > 50 {
		commits = commits[:50]
	}
	_, err := ts.TileFromCommits(commits)
	if err != nil {
		glog.Fatalf("Failed to scan Tile: %s", err)
	}
	glog.Infof("Time to load tile: %v", time.Now().Sub(begin))
}
Exemplo n.º 3
0
func TestAdd(t *testing.T) {
	ts, cleanup := setupClientServerForTesting(t.Fatalf)
	defer cleanup()

	now := time.Unix(100, 0)

	commitIDs := []*CommitID{
		&CommitID{
			Timestamp: now.Unix(),
			ID:        "abc123",
			Source:    "master",
		},
		&CommitID{
			Timestamp: now.Add(time.Hour).Unix(),
			ID:        "xyz789",
			Source:    "master",
		},
	}

	entries := map[string]*Entry{
		"key:8888:android": &Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.01),
		},
		"key:gpu:win8": &Entry{
			Params: map[string]string{
				"config":   "gpu",
				"platform": "win8",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(1.234),
		},
	}

	err := ts.Add(commitIDs[0], entries)

	assert.NoError(t, err)
	tile, hashes, err := ts.TileFromCommits(commitIDs)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(tile.Traces))
	assert.Equal(t, 2, len(tile.Commits))
	assert.Equal(t, 2, len(hashes))
	assert.True(t, util.In("d41d8cd98f00b204e9800998ecf8427e", hashes))
	assert.NotEqual(t, hashes[0], hashes[1])

	hashes, err = ts.ListMD5(commitIDs)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(hashes))
	assert.True(t, util.In("d41d8cd98f00b204e9800998ecf8427e", hashes))
	assert.NotEqual(t, hashes[0], hashes[1])

	tr := tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, tr.Values[0])
	assert.True(t, tr.IsMissing(1))
	assert.Equal(t, "8888", tr.Params()["config"])

	tr = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, tr.Values[0])
	assert.True(t, tr.IsMissing(1))

	assert.Equal(t, "abc123", tile.Commits[0].Hash)
	assert.Equal(t, "xyz789", tile.Commits[1].Hash)

	foundCommits, err := ts.List(now, now.Add(time.Hour))
	assert.NoError(t, err)
	assert.Equal(t, 1, len(foundCommits))
}
func TestNewTraceDBBuilder(t *testing.T) {
	defer cleanup()

	// First spin up a traceservice server that we wil talk to.
	server, err := traceservice.NewTraceServiceServer(FILENAME)
	if err != nil {
		t.Fatalf("Failed to initialize the tracestore server: %s", err)
	}

	// Start the server on an open port.
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to listen: %v", err)
	}
	port := lis.Addr().String()
	s := grpc.NewServer()
	traceservice.RegisterTraceServiceServer(s, server)
	go func() {
		t.Fatalf("Failed while serving: %s", s.Serve(lis))
	}()

	// Get a Git repo.
	tr := util.NewTempRepo()
	defer tr.Cleanup()

	// Set up a connection to the server.
	conn, err := grpc.Dial(port, grpc.WithInsecure())
	if err != nil {
		t.Fatalf("did not connect: %v", err)
	}
	ts, err := db.NewTraceServiceDB(conn, types.PerfTraceBuilder)
	if err != nil {
		t.Fatalf("Failed to create tracedb.DB: %s", err)
	}
	defer util.Close(ts)

	git, err := gitinfo.NewGitInfo(filepath.Join(tr.Dir, "testrepo"), false, false)
	if err != nil {
		t.Fatal(err)
	}
	hashes := git.LastN(50)
	assert.Equal(t, 50, len(hashes))

	// Populate the tracedb with some data.
	commitID := &db.CommitID{
		Timestamp: git.Timestamp(hashes[1]).Unix(),
		ID:        hashes[1],
		Source:    "master",
	}

	entries := map[string]*db.Entry{
		"key:8888:android": &db.Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.01),
		},
		"key:gpu:win8": &db.Entry{
			Params: map[string]string{
				"config":   "gpu",
				"platform": "win8",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(1.234),
		},
	}

	err = ts.Add(commitID, entries)
	if err != nil {
		t.Fatalf("Failed to add data to traceservice: %s", err)
	}

	evt := eventbus.New(nil)
	traceDB, err := db.NewTraceServiceDBFromAddress(port, types.PerfTraceBuilder)
	assert.Nil(t, err)

	builder, err := db.NewMasterTileBuilder(traceDB, git, 50, evt)
	if err != nil {
		t.Fatalf("Failed to construct TraceStore: %s", err)
	}
	tile := builder.GetTile()
	assert.Equal(t, 50, len(tile.Commits))
	assert.Equal(t, 2, len(tile.Traces))
	assert.Equal(t, commitID.ID, tile.Commits[1].Hash)
	assert.Equal(t, "Joe Gregorio ([email protected])", tile.Commits[1].Author)

	ptrace := tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	ptrace = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	// Now add more data to the tracestore, trigger LoadTile() and check the results.
	commitID = &db.CommitID{
		Timestamp: git.Timestamp(hashes[2]).Unix(),
		ID:        hashes[2],
		Source:    "master",
	}

	entries = map[string]*db.Entry{
		"key:8888:android": &db.Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.02),
		},
		"key:565:ubuntu": &db.Entry{
			Params: map[string]string{
				"config":   "565",
				"platform": "ubuntu",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(2.345),
		},
	}

	err = ts.Add(commitID, entries)
	if err != nil {
		t.Fatalf("Failed to add data to traceservice: %s", err)
	}

	// Access the LoadTile method without exposing it in the MasterBuilder interface.
	type hasLoadTile interface {
		LoadTile() error
	}
	masterBuilder := builder.(hasLoadTile)
	if err := masterBuilder.LoadTile(); err != nil {
		t.Fatalf("Failed to force load Tile: %s", err)
	}

	tile = builder.GetTile()
	assert.Equal(t, 50, len(tile.Commits))
	assert.Equal(t, 3, len(tile.Traces))
	assert.Equal(t, commitID.ID, tile.Commits[2].Hash)

	ptrace = tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, ptrace.Values[1])
	assert.Equal(t, 0.02, ptrace.Values[2])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[3])

	ptrace = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, ptrace.Values[1])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[0])

	ptrace = tile.Traces["key:565:ubuntu"].(*types.PerfTrace)
	assert.Equal(t, 2.345, ptrace.Values[2])
	assert.Equal(t, config.MISSING_DATA_SENTINEL, ptrace.Values[3])
}
Exemplo n.º 5
0
func TestImpl(t *testing.T) {
	ts, err := NewTraceServiceServer(FILENAME)
	assert.NoError(t, err)
	defer util.Close(ts)
	defer cleanup()

	now := time.Now()

	first := now.Unix()
	second := now.Add(time.Minute).Unix()

	commitIDs := []*CommitID{
		&CommitID{
			Timestamp: first,
			Id:        "abc123",
			Source:    "master",
		},
		&CommitID{
			Timestamp: second,
			Id:        "xyz789",
			Source:    "master",
		},
	}

	params := &AddParamsRequest{
		Params: []*ParamsPair{
			&ParamsPair{
				Key: "key:8888:android",
				Params: map[string]string{
					"config":   "8888",
					"platform": "android",
					"type":     "skp",
				},
			},
			&ParamsPair{
				Key: "key:gpu:win8",
				Params: map[string]string{
					"config":   "gpu",
					"platform": "win8",
					"type":     "skp",
				},
			},
		},
	}

	ctx := context.Background()

	// First confirm that Ping() works.
	_, err = ts.Ping(ctx, &Empty{})
	assert.Nil(t, err)

	// Confirm that these traceids don't have Params stored in the db yet.
	missingRequest := &MissingParamsRequest{
		Traceids: []string{"key:8888:android", "key:gpu:win8"},
	}
	missingResp, err := ts.MissingParams(ctx, missingRequest)
	assert.NoError(t, err)
	assert.Equal(t, missingResp.Traceids, missingRequest.Traceids)

	// Now add the Params for them.
	_, err = ts.AddParams(ctx, params)
	assert.NoError(t, err)

	// Confirm the missing list is now empty.
	nowMissing, err := ts.MissingParams(ctx, missingRequest)
	assert.Equal(t, []string{}, nowMissing.Traceids)

	addReq := &AddRequest{
		Commitid: commitIDs[0],
		Values: []*ValuePair{
			&ValuePair{
				Key:   "key:gpu:win8",
				Value: types.BytesFromFloat64(1.234),
			},
			&ValuePair{
				Key:   "key:8888:android",
				Value: types.BytesFromFloat64(0.01),
			},
		},
	}

	// Add a commit.
	_, err = ts.Add(ctx, addReq)
	assert.NoError(t, err)

	// List, GetValues, and GetParams for the added commit.
	listReq := &ListRequest{
		Begin: first,
		End:   second,
	}
	listResp, err := ts.List(ctx, listReq)
	assert.NoError(t, err)
	assert.Equal(t, 1, len(listResp.Commitids))
	assert.Equal(t, "abc123", listResp.Commitids[0].Id)

	valuesReq := &GetValuesRequest{
		Commitid: commitIDs[0],
	}
	valuesResp, err := ts.GetValues(ctx, valuesReq)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(valuesResp.Values))
	expected := map[string]float64{
		"key:gpu:win8":     1.234,
		"key:8888:android": 0.01,
	}
	for _, v := range valuesResp.Values {
		assert.Equal(t, expected[v.Key], math.Float64frombits(binary.LittleEndian.Uint64(v.Value)))
	}

	paramsReq := &GetParamsRequest{
		Traceids: []string{"key:8888:android", "key:gpu:win8"},
	}
	paramsResp, err := ts.GetParams(ctx, paramsReq)
	assert.NoError(t, err)
	assert.Equal(t, "8888", paramsResp.Params[0].Params["config"])
	assert.Equal(t, "win8", paramsResp.Params[1].Params["platform"])

	// Remove the commit.
	removeRequest := &RemoveRequest{
		Commitid: commitIDs[0],
	}
	_, err = ts.Remove(ctx, removeRequest)
	assert.NoError(t, err)

	listResp, err = ts.List(ctx, listReq)
	assert.NoError(t, err)
	assert.Equal(t, 0, len(listResp.Commitids))
}
Exemplo n.º 6
0
func TestAdd(t *testing.T) {
	defer cleanup()

	// First spin up a traceservice server that we wil talk to.
	server, err := traceservice.NewTraceServiceServer(FILENAME)
	if err != nil {
		t.Fatalf("Failed to initialize the tracestore server: %s", err)
	}

	// Start the server on an open port.
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to listen: %v", err)
	}
	port := lis.Addr().String()
	s := grpc.NewServer()
	traceservice.RegisterTraceServiceServer(s, server)
	go func() {
		t.Fatalf("Failed while serving: %s", s.Serve(lis))
	}()

	// Set up a connection to the server.
	conn, err := grpc.Dial(port, grpc.WithInsecure())
	if err != nil {
		t.Fatalf("did not connect: %v", err)
	}
	defer util.Close(conn)
	ts, err := NewTraceServiceDB(conn, types.PerfTraceBuilder)
	if err != nil {
		t.Fatalf("Failed to create tracedb.DB: %s", err)
	}
	defer util.Close(ts)

	now := time.Now()

	commitIDs := []*CommitID{
		&CommitID{
			Timestamp: now,
			ID:        "abc123",
			Source:    "master",
		},
		&CommitID{
			Timestamp: now.Add(time.Minute),
			ID:        "xyz789",
			Source:    "master",
		},
	}

	entries := map[string]*Entry{
		"key:8888:android": &Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.01),
		},
		"key:gpu:win8": &Entry{
			Params: map[string]string{
				"config":   "gpu",
				"platform": "win8",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(1.234),
		},
	}

	err = ts.Add(commitIDs[0], entries)

	assert.NoError(t, err)
	tile, err := ts.TileFromCommits(commitIDs)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(tile.Traces))
	assert.Equal(t, 2, len(tile.Commits))

	tr := tile.Traces["key:8888:android"].(*types.PerfTrace)
	assert.Equal(t, 0.01, tr.Values[0])
	assert.True(t, tr.IsMissing(1))
	assert.Equal(t, "8888", tr.Params()["config"])

	tr = tile.Traces["key:gpu:win8"].(*types.PerfTrace)
	assert.Equal(t, 1.234, tr.Values[0])
	assert.True(t, tr.IsMissing(1))

	assert.Equal(t, "abc123", tile.Commits[0].Hash)
	assert.Equal(t, "xyz789", tile.Commits[1].Hash)

	foundCommits, err := ts.List(now, now.Add(time.Hour))
	assert.NoError(t, err)
	assert.Equal(t, 1, len(foundCommits))
}
func TestImpl(t *testing.T) {
	ts, err := NewTraceServiceServer(FILENAME)
	assert.NoError(t, err)
	defer util.Close(ts)
	defer cleanup()

	now := time.Unix(100, 0)

	first := now.Unix()
	second := now.Add(time.Minute).Unix()

	commitIDs := []*CommitID{
		&CommitID{
			Timestamp: first,
			Id:        "abc123",
			Source:    "master",
		},
		&CommitID{
			Timestamp: second,
			Id:        "xyz789",
			Source:    "master",
		},
	}

	params := &AddParamsRequest{
		Params: []*ParamsPair{
			&ParamsPair{
				Key: "key:8888:android",
				Params: map[string]string{
					"config":   "8888",
					"platform": "android",
					"type":     "skp",
				},
			},
			&ParamsPair{
				Key: "key:gpu:win8",
				Params: map[string]string{
					"config":   "gpu",
					"platform": "win8",
					"type":     "skp",
				},
			},
		},
	}

	ctx := context.Background()

	// First confirm that Ping() works.
	_, err = ts.Ping(ctx, &Empty{})
	assert.Nil(t, err)

	// Confirm that these traceids don't have Params stored in the db yet.
	missingRequest := &MissingParamsRequest{
		Traceids: []string{"key:8888:android", "key:gpu:win8"},
	}
	missingResp, err := ts.MissingParams(ctx, missingRequest)
	assert.NoError(t, err)
	assert.Equal(t, missingResp.Traceids, missingRequest.Traceids)

	// Now add the Params for them.
	_, err = ts.AddParams(ctx, params)
	assert.NoError(t, err)

	// Confirm the missing list is now empty.
	nowMissing, err := ts.MissingParams(ctx, missingRequest)
	assert.Equal(t, []string{}, nowMissing.Traceids)

	addReq := &AddRequest{
		Commitid: commitIDs[0],
		Values: []*ValuePair{
			&ValuePair{
				Key:   "key:gpu:win8",
				Value: types.BytesFromFloat64(1.234),
			},
			&ValuePair{
				Key:   "key:8888:android",
				Value: types.BytesFromFloat64(0.01),
			},
		},
	}

	// Add a commit.
	_, err = ts.Add(ctx, addReq)
	assert.NoError(t, err)

	// List, GetValues, and GetParams for the added commit.
	listReq := &ListRequest{
		Begin: first,
		End:   second,
	}
	listResp, err := ts.List(ctx, listReq)
	assert.NoError(t, err)
	assert.Equal(t, 1, len(listResp.Commitids))
	assert.Equal(t, "abc123", listResp.Commitids[0].Id)

	valuesReq := &GetValuesRequest{
		Commitid: commitIDs[0],
	}
	valuesResp, err := ts.GetValues(ctx, valuesReq)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(valuesResp.Values))
	expected := map[string]float64{
		"key:gpu:win8":     1.234,
		"key:8888:android": 0.01,
	}
	for _, v := range valuesResp.Values {
		assert.Equal(t, expected[v.Key], math.Float64frombits(binary.LittleEndian.Uint64(v.Value)))
	}
	assert.NotEqual(t, "", valuesResp.Md5)

	paramsReq := &GetParamsRequest{
		Traceids: []string{"key:8888:android", "key:gpu:win8"},
	}
	paramsResp, err := ts.GetParams(ctx, paramsReq)
	assert.NoError(t, err)
	assert.Equal(t, "8888", paramsResp.Params[0].Params["config"])
	assert.Equal(t, "win8", paramsResp.Params[1].Params["platform"])

	// Request the raw data for the commit.
	rawRequest := &GetValuesRequest{
		Commitid: commitIDs[0],
	}
	rawResp, err := ts.GetValuesRaw(ctx, rawRequest)
	assert.NoError(t, err)
	assert.Equal(t, 34, len(rawResp.Value))
	assert.Equal(t, valuesResp.Md5, rawResp.Md5, "Should get the same md5 regardless of how you request the data.")
	// Confirm that we can decode the info on the client side.
	ci, err := NewCommitInfo(rawResp.Value)
	assert.NoError(t, err)

	// The keys are trace64ids, so test that we can convert them to traceids,
	// i.e. from uint64's to strings.
	keys64 := []uint64{}
	for k, _ := range ci.Values {
		keys64 = append(keys64, k)
	}
	assert.Equal(t, 2, len(keys64))
	traceidsRequest := &GetTraceIDsRequest{
		Id: keys64,
	}
	traceids, err := ts.GetTraceIDs(ctx, traceidsRequest)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(traceids.Ids))
	assert.True(t, util.In(traceids.Ids[0].Id, paramsReq.Traceids))
	assert.True(t, util.In(traceids.Ids[1].Id, paramsReq.Traceids))

	// List the md5s.
	listMD5Request := &ListMD5Request{
		Commitid: commitIDs,
	}
	listMD5Response, err := ts.ListMD5(ctx, listMD5Request)
	assert.NoError(t, err)
	assert.Equal(t, 2, len(listMD5Response.Commitmd5))
	hashes := []string{listMD5Response.Commitmd5[0].Md5, listMD5Response.Commitmd5[1].Md5}
	assert.True(t, util.In("d41d8cd98f00b204e9800998ecf8427e", hashes))
	assert.NotEqual(t, hashes[0], hashes[1])

	// Remove the commit.
	removeRequest := &RemoveRequest{
		Commitid: commitIDs[0],
	}
	_, err = ts.Remove(ctx, removeRequest)
	assert.NoError(t, err)

	listResp, err = ts.List(ctx, listReq)
	assert.NoError(t, err)
	assert.Equal(t, 0, len(listResp.Commitids))
}
Exemplo n.º 8
0
func TestTileFromCommits(t *testing.T) {
	ts, cleanup := setupClientServerForTesting(t.Fatalf)
	defer cleanup()

	now := time.Unix(100, 0)

	commitIDs := []*CommitID{
		&CommitID{
			Timestamp: now.Unix(),
			ID:        "foofoofoo",
			Source:    "master",
		},
	}

	vcsCommits := []*vcsinfo.LongCommit{
		&vcsinfo.LongCommit{
			ShortCommit: &vcsinfo.ShortCommit{
				Hash:    "foofoofoo",
				Author:  "*****@*****.**",
				Subject: "some commit",
			},
		},
	}
	vcs := ingestion.MockVCS(vcsCommits)

	entries := map[string]*Entry{
		"key:8888:android": &Entry{
			Params: map[string]string{
				"config":   "8888",
				"platform": "android",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.01),
		},
		"key:gpu:win8": &Entry{
			Params: map[string]string{
				"config":   "gpu",
				"platform": "win8",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(1.234),
		},
	}

	// Populate the tile with some data.
	err := ts.Add(commitIDs[0], entries)
	assert.NoError(t, err)

	// Now test tileBuilder.
	builder := &tileBuilder{
		db:     ts,
		vcs:    vcs,
		tcache: lru.New(2),
		cache:  lru.New(2),
	}
	tile, err := builder.CachedTileFromCommits(commitIDs)
	assert.NoError(t, err)
	assert.Equal(t, 1, len(tile.Commits))
	assert.Equal(t, 2, len(tile.Traces))
	assert.Equal(t, 1, builder.tcache.Len(), "The tile should have been added to the cache.")

	entries = map[string]*Entry{
		"key:565:linux": &Entry{
			Params: map[string]string{
				"config":   "565",
				"platform": "linux",
				"type":     "skp",
			},
			Value: types.BytesFromFloat64(0.05),
		},
	}

	// Add more data and be sure that the new data is returned when we
	// call CachedTileFromCommits again.
	err = ts.Add(commitIDs[0], entries)
	assert.NoError(t, err)
	tile, err = builder.CachedTileFromCommits(commitIDs)
	assert.NoError(t, err)
	assert.Equal(t, 1, len(tile.Commits))
	assert.Equal(t, 3, len(tile.Traces), "The new data should appear in the tile.")
	assert.Equal(t, 1, builder.tcache.Len(), "The new tile should have replaced the old tile in the cache.")
}