Skip to content

Commit

Permalink
Fix the command-tree for commands that are recorded pre-MEC.
Browse files Browse the repository at this point in the history
This will create a virtual command when a subcommand is requested.
  • Loading branch information
AWoloszyn committed Jan 2, 2018
1 parent 7c0a029 commit 6f29790
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 6 deletions.
7 changes: 7 additions & 0 deletions gapis/api/gvr/gvr.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ func (API) FlattenSubcommandIdx(idx api.SubCmdIdx, data *sync.Data, unused bool)
return api.CmdID(0), false
}

// RecoverMidExecutionCommand returns a virtual command, used to describe the
// a subcommand that was created before the start of the trace
// GVR has no subcommands of this type, so this should never be called
func (API) RecoverMidExecutionCommand(ctx context.Context, c *path.Capture, i interface{}) (api.Cmd, error) {
return nil, sync.NoMECSubcommandsError{}
}

// MutateSubcommands mutates the given Cmd and calls callbacks for subcommands
// called before and after executing each subcommand callback.
func (API) MutateSubcommands(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState,
Expand Down
7 changes: 6 additions & 1 deletion gapis/api/sync/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ type ExecutionRanges struct {
// SubcommandReference contains a subcommand index as well as an api.CmdID that
// references the command that generated this subcommand.
type SubcommandReference struct {
Index api.SubCmdIdx
Index api.SubCmdIdx
// If api.CmdID is api.CmdNoID then the generating command came from before
// the start of the trace.
GeneratingCmd api.CmdID
// If GeneratingCmd is nil, then MidExecutionCommandData contains the data
// that the API needs in order to reconstruct this command.
MidExecutionCommandData interface{}
// IsCalledGroup is true if the reference is to a nested call, otherwise
// the reference belongs to a command-list.
IsCallerGroup bool
Expand Down
13 changes: 13 additions & 0 deletions gapis/api/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import (
"github.com/google/gapid/gapis/service/path"
)

// NoMECSubcommandsError is used to notify the caller that this API does not
// support MEC subcomands.
type NoMECSubcommandsError struct{}

func (e NoMECSubcommandsError) Error() string {
return "This api does not have MEC subcommands"
}

// SynchronizedAPI defines an API that explicitly has multiple threads of
// execution. This means that replays are not necessarily linear in terms
// of commands.
Expand All @@ -53,6 +61,11 @@ type SynchronizedAPI interface {
// command id and true will be returned, otherwise, zero and false will be
// returned.
FlattenSubcommandIdx(idx api.SubCmdIdx, d *Data, initialCall bool) (api.CmdID, bool)

// RecoverMidExecutionCommand returns a virtual command, used to describe the
// a subcommand that was created before the start of the trace.
// If the api does not have mid-execution commands, NoMECSubcommandsError should be returned.
RecoverMidExecutionCommand(ctx context.Context, c *path.Capture, data interface{}) (api.Cmd, error)
}

type writer struct {
Expand Down
37 changes: 35 additions & 2 deletions gapis/api/vulkan/vulkan.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ func (c *State) SetupInitialState(ctx context.Context) {
cmd := b.CommandReferences.Get(v)
commandFunction := GetCommandFunction(cmd)
commandArgs := GetCommandArgs(ctx, cmd, c)
cmd.QueuedCommandData = QueuedCommand{
initialCall: nil,
submit: nil,
submissionIndex: []uint64(nil),
actualSubmission: true,
}
b.Commands = append(b.Commands, CommandBufferCommand{
func(ctx context.Context, cmd api.Cmd, id api.CmdID, s *api.GlobalState, b *builder.Builder) {
CallReflectedCommand(ctx, cmd, id, s, b, commandFunction, commandArgs)
Expand Down Expand Up @@ -298,13 +304,17 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
}
// No way for this to not exist, we put it in up there
k := submissionMap[s.CurrentSubmission]
id := api.CmdNoID
if data.QueuedCommandData.initialCall != nil {
id = commandMap[data.QueuedCommandData.initialCall]
}
if v, ok := d.SubcommandReferences[k]; ok {
v = append(v,
sync.SubcommandReference{append(api.SubCmdIdx(nil), s.SubCmdIdx...), commandMap[data.QueuedCommandData.initialCall], false})
sync.SubcommandReference{append(api.SubCmdIdx(nil), s.SubCmdIdx...), id, &data, false})
d.SubcommandReferences[k] = v
} else {
d.SubcommandReferences[k] = []sync.SubcommandReference{
sync.SubcommandReference{append(api.SubCmdIdx(nil), s.SubCmdIdx...), commandMap[data.QueuedCommandData.initialCall], false}}
sync.SubcommandReference{append(api.SubCmdIdx(nil), s.SubCmdIdx...), id, &data, false}}
}

fullSubCmdIdx := api.SubCmdIdx(append([]uint64{uint64(k)}, s.SubCmdIdx...))
Expand Down Expand Up @@ -388,6 +398,29 @@ func (API) FlattenSubcommandIdx(idx api.SubCmdIdx, data *sync.Data, initialCall
return api.CmdID(0), false
}

// RecoverMidExecutionCommand returns a virtual command, used to describe the
// a subcommand that was created before the start of the trace
func (API) RecoverMidExecutionCommand(ctx context.Context, c *path.Capture, dat interface{}) (api.Cmd, error) {
cr, ok := dat.(*CommandReference)
if !ok {
return nil, fmt.Errorf("Not a command reference")
}

ctx = capture.Put(ctx, c)
st, err := capture.NewState(ctx)
if err != nil {
return nil, err
}
s := GetState(st)

cb := CommandBuilder{Thread: 0}
_, a, err := AddCommand(ctx, cb, cr.Buffer, st, GetCommandArgs(ctx, *cr, s))
if err != nil {
return nil, log.Errf(ctx, err, "Invalid Command")
}
return a, nil
}

// Interface check
var _ sync.SynchronizedAPI = &API{}

Expand Down
21 changes: 21 additions & 0 deletions gapis/resolve/atoms.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/google/gapid/core/log"
"github.com/google/gapid/gapis/api"
"github.com/google/gapid/gapis/api/sync"
"github.com/google/gapid/gapis/capture"
"github.com/google/gapid/gapis/messages"
"github.com/google/gapid/gapis/service"
Expand Down Expand Up @@ -67,6 +68,26 @@ func Cmd(ctx context.Context, p *path.Command) (api.Cmd, error) {
if v.Index.Equals(idx) {
found = true
atomIdx = uint64(v.GeneratingCmd)
if atomIdx == uint64(api.CmdNoID) {
capture, err := capture.ResolveFromPath(ctx, p.Capture)
if err != nil {
return nil, err
}

for _, api := range capture.APIs {
if snc, ok := api.(sync.SynchronizedAPI); ok {
a, err := snc.RecoverMidExecutionCommand(ctx, p.Capture, v.MidExecutionCommandData)
if err != nil {
if _, ok := err.(sync.NoMECSubcommandsError); !ok {
return nil, err
}
} else {
return a, nil
}
}
}
atomIdx = 0
}
break
}
}
Expand Down
7 changes: 4 additions & 3 deletions gapis/resolve/synchronization_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ func addCallerGroups(ctx context.Context, d *sync.Data, c *path.Capture) error {
l := d.SubcommandReferences[caller]
idx := api.SubCmdIdx{uint64(len(l))}
l = append(l, sync.SubcommandReference{
Index: idx,
GeneratingCmd: id,
IsCallerGroup: true,
Index: idx,
GeneratingCmd: id,
MidExecutionCommandData: nil,
IsCallerGroup: true,
})
d.SubcommandReferences[caller] = l
d.SubcommandGroups[caller] = []api.SubCmdIdx{idx}
Expand Down

0 comments on commit 6f29790

Please sign in to comment.