blob: 788ab26a146b0865457281c4699a69991223821b [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package replay
import (
"fmt"
"sync"
"android.googlesource.com/platform/tools/gpu/client/gapir"
"android.googlesource.com/platform/tools/gpu/framework/log"
"android.googlesource.com/platform/tools/gpu/gapid/database"
"android.googlesource.com/platform/tools/gpu/gapid/service"
"android.googlesource.com/platform/tools/gpu/gapid/service/path"
)
// Manager is used discover replay devices and to send replay requests to those
// discovered devices.
type Manager struct {
database database.Database
discovery *gapir.Discovery
batchers map[batcherContext]*batcher
mutex sync.Mutex // guards batchers
}
func (m *Manager) getBatchStream(ctx log.Context, bContext batcherContext) (chan<- job, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
pc := &path.Capture{ID: bContext.Capture}
ctx = service.WithCaptureAndDatabase(ctx, pc, m.database)
// TODO: This accumulates batchers with running go-routines forever.
// Rework to free the batcher after execution.
b, found := m.batchers[bContext]
if !found {
ctx.Info().V("capture", bContext.Capture).Log("New batch stream")
device := m.discovery.Device(bContext.Device)
if device == nil {
return nil, fmt.Errorf("Unknown device %v", bContext.Device)
}
b = &batcher{
feed: make(chan job, 64),
context: bContext,
database: m.database,
device: device,
}
m.batchers[bContext] = b
go b.run(ctx)
}
return b.feed, nil
}
// New returns a new Manager instance using the database db.
func New(ctx log.Context, d database.Database) *Manager {
return &Manager{
database: d,
discovery: &gapir.Discovery{},
batchers: make(map[batcherContext]*batcher),
}
}
// Replay requests that req is to be performed on the device described by intent,
// using the capture described by intent. Replay requests made with configs that
// have equality (==) will likely be batched into the same replay pass.
func (m *Manager) Replay(ctx log.Context, intent Intent, cfg Config, req Request, generator Generator) error {
ctx.Info().Log("Replay request")
batch, err := m.getBatchStream(ctx, batcherContext{
Intent: intent,
Generator: generator,
Config: cfg,
})
if err != nil {
return err
}
res := make(chan error, 1)
batch <- job{request: req, result: res}
return <-res
}
// Discovery returns the device discovery being used by this manager.
func (m *Manager) Discovery() *gapir.Discovery {
return m.discovery
}