blob: c0082f7e5406e39b96089cca3398d04740dd5297 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package platform
import (
"context"
"io/ioutil"
"path/filepath"
"time"
"android.googlesource.com/platform/external/perfetto/protos/perfetto/trace"
"github.com/golang/protobuf/proto"
"chromiumos/tast/ctxutil"
"chromiumos/tast/local/bundles/cros/platform/perfetto"
"chromiumos/tast/local/chrome"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: PerfettoChromeConsumer,
Desc: "Tests Chrome DevTools protocol for collecting a system-wide trace via the system tracing service",
Contacts: []string{"chinglinyu@chromium.org", "chenghaoyang@chromium.org"},
SoftwareDeps: []string{"chrome"},
Data: []string{perfetto.TraceConfigFile},
Attr: []string{"group:mainline", "informational"}, // TODO(crbug/1194540) remove "informational" after the test is stable.
})
}
// PerfettoChromeConsumer tests Chrome as a perfetto trace consumer.
// The test enables the "EnablePerfettoSystemTracing" feature flag for Chrome and then collects a system-wide trace using the system backend connected to traced, the system tracing service daemon.
func PerfettoChromeConsumer(ctx context.Context, s *testing.State) {
const (
traceDataFile = "trace.data.gz"
traceCollectionDuration = time.Second
)
cleanupCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 10*time.Second)
defer cancel()
// Start Chrome with the "EnablePerfettoSystemTracing" feature flag.
// TODO(crbug/1194540, b/191235714): remove this after the feature is enabled by default.
cr, err := chrome.New(
ctx,
chrome.ExtraArgs("--enable-features=EnablePerfettoSystemTracing"))
if err != nil {
s.Fatal("Failed to enable Perfetto system tracing for Chrome: ", err)
}
defer cr.Close(cleanupCtx)
// Create the binary protobuf TraceConfig: unmarshal from pbtxt and then marshal to binary protobuf.
traceConfigPath := s.DataPath(perfetto.TraceConfigFile)
configTxt, err := ioutil.ReadFile(traceConfigPath)
if err != nil {
s.Fatal("Failed to read the trace config: ", err)
}
// Unmarshall the pbtxt and then marshall to binary protobuf.
config := &trace.TraceConfig{}
if err := proto.UnmarshalText(string(configTxt), config); err != nil {
s.Fatal("Failed to unmarshal perfetto config: ", err)
}
configPb, err := proto.Marshal(config)
if err != nil {
s.Fatal("Failed to marshal perfetto config: err")
}
// triedToStopTracing means that cr.StopTracing(cleanupCtx) was already done, with or without success (if it failed then we have no reason to try again with the same timeout.)
triedToStopTracing := false
defer func() {
if triedToStopTracing {
return
}
if _, err := cr.StopTracing(cleanupCtx); err != nil {
s.Error("Failed to stop tracing in cleanup phase: ", err)
}
}()
if err := cr.StartSystemTracing(ctx, configPb); err != nil {
s.Fatal("Failed to start tracing: ", err)
}
// The trace config contains a longer trace collection duration, but we explicitly stop tracing before the trace duration elapses.
if err := testing.Sleep(ctx, traceCollectionDuration); err != nil {
s.Fatalf("Failed to wait %v: %v", traceCollectionDuration, err)
}
// Set triedToStopTracing to true so we don't redo in the deferred cleanup phase.
triedToStopTracing = true
tr, err := cr.StopTracing(cleanupCtx)
if err != nil {
s.Fatal("Failed to stop tracing: ", err)
}
if tr == nil || len(tr.Packet) == 0 {
s.Fatal("No trace data is collected")
}
// TODO(crbug/1194540): in addition to checking the number of trace packets, post-process the collected trace using trace_processor_shell to verify the trace data.
if err := chrome.SaveTraceToFile(ctx, tr, filepath.Join(s.OutDir(), traceDataFile)); err != nil {
s.Fatal("Failed to save trace to file: ", err)
}
}