Skip to content

Commit

Permalink
Add export_replay for standalone replay with gapir.
Browse files Browse the repository at this point in the history
  • Loading branch information
hysw committed Aug 24, 2018
1 parent 93d2fcb commit 0ce2181
Show file tree
Hide file tree
Showing 20 changed files with 507 additions and 1 deletion.
24 changes: 23 additions & 1 deletion cmd/gapir/cc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "gapir/cc/context.h"
#include "gapir/cc/crash_uploader.h"
#include "gapir/cc/memory_manager.h"
#include "gapir/cc/replay_archive.h"
#include "gapir/cc/replay_connection.h"
#include "gapir/cc/resource_disk_cache.h"
#include "gapir/cc/resource_in_memory_cache.h"
Expand Down Expand Up @@ -210,9 +211,12 @@ int main(int argc, const char* argv[]) {
const char* portArgStr = "0";
const char* authTokenFile = nullptr;
int idleTimeoutSec = 0;
const char* replayArchive = nullptr;

for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--auth-token-file") == 0) {
if (strcmp(argv[i], "--replay-archive") == 0) {
replayArchive = argv[++i];
} else if (strcmp(argv[i], "--auth-token-file") == 0) {
if (i + 1 >= argc) {
GAPID_FATAL("Usage: --auth-token-file <token-string>");
}
Expand Down Expand Up @@ -283,6 +287,24 @@ int main(int argc, const char* argv[]) {
core::Debugger::waitForAttach();
}

if (replayArchive) {
core::CrashHandler crashHandler;
GAPID_LOGGER_INIT(logLevel, "gapir", logPath);
MemoryManager memoryManager(memorySizes);
std::string payloadPath = std::string(replayArchive) + "/payload.bin";
gapir::ReplayArchive conn(payloadPath);
std::unique_ptr<ResourceProvider> resourceProvider =
ResourceDiskCache::create(nullptr, replayArchive);
std::unique_ptr<Context> context = Context::create(
&conn, crashHandler, resourceProvider.get(), &memoryManager);

GAPID_INFO("Replay started");
bool ok = context->interpret();
GAPID_INFO("Replay %s", ok ? "finished successfully" : "failed");

return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}

core::CrashHandler crashHandler;

GAPID_LOGGER_INIT(logLevel, "gapir", logPath);
Expand Down
1 change: 1 addition & 0 deletions cmd/gapit/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ go_library(
"dump.go",
"dump_pipeline.go",
"dump_shaders.go",
"export_replay.go",
"flags.go",
"inputs.go",
"main.go",
Expand Down
68 changes: 68 additions & 0 deletions cmd/gapit/export_replay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2017 Google Inc.
//
// 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 main

import (
"context"
"flag"
"path/filepath"

"github.com/google/gapid/core/app"
"github.com/google/gapid/core/log"
)

type exportReplayVerb struct{ ExportReplayFlags }

func init() {
verb := &exportReplayVerb{}
app.AddVerb(&app.Verb{
Name: "export_replay",
ShortHelp: "Export replay vm instruction and assets.",
Action: verb,
})
}

func (verb *exportReplayVerb) Run(ctx context.Context, flags flag.FlagSet) error {
if flags.NArg() != 1 {
app.Usage(ctx, "Exactly one gfx trace file expected, got %d", flags.NArg())
return nil
}

capture, err := filepath.Abs(flags.Arg(0))
if err != nil {
log.Errf(ctx, err, "Could not find capture file: %v", flags.Arg(0))
}

client, err := getGapis(ctx, verb.Gapis, verb.Gapir)
if err != nil {
return log.Err(ctx, err, "Failed to connect to the GAPIS server")
}
defer client.Close()

capturePath, err := client.LoadCapture(ctx, capture)
if err != nil {
return log.Err(ctx, err, "Failed to load the capture file")
}

device, err := getDevice(ctx, client, capturePath, verb.Gapir)
if err != nil {
return err
}

if err := client.ExportReplay(ctx, capturePath, device, verb.Out); err != nil {
return log.Err(ctx, err, "Failed to export replay")
}
return nil
}
5 changes: 5 additions & 0 deletions cmd/gapit/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ type (
DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"`
CommandFilterFlags
}
ExportReplayFlags struct {
Gapis GapisFlags
Gapir GapirFlags
Out string `help:"output directory for commands and assets"`
}
VideoFlags struct {
Gapis GapisFlags
Gapir GapirFlags
Expand Down
26 changes: 26 additions & 0 deletions core/archive/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (C) 2018 Google Inc.
#
# 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.

load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["archive.go"],
cdeps = ["//core/cc"],
cgo = True,
clinkopts = [], # keep
importpath = "github.com/google/gapid/core/archive",
visibility = ["//visibility:public"],
deps = [],
)
45 changes: 45 additions & 0 deletions core/archive/archive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2018 Google Inc.
//
// 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 archive

/*
#include <stdlib.h>
#include "core/cc/archive.h"
*/
import "C"
import "unsafe"

// Archive contains assets.
type Archive = *C.archive

// New creates an archive.
func New(name string) Archive {
cstr := C.CString(name)
defer C.free(unsafe.Pointer(cstr))
return C.archive_create(cstr)
}

// Dispose flush and close the underlying archive.
func (a Archive) Dispose() {
C.archive_destroy(a)
}

// Write writes key-value pair to the archive.
func (a Archive) Write(key string, value []byte) bool {
cstr := C.CString(key)
defer C.free(unsafe.Pointer(cstr))
csize := C.size_t(len(value))
return C.archive_write(a, cstr, unsafe.Pointer(&value[0]), csize) != 0
}
14 changes: 14 additions & 0 deletions core/cc/archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,17 @@ bool Archive::write(const std::string& id, const void* buffer, uint32_t size) {
}

} // namespace core

extern "C" {

archive* archive_create(const char* archiveName) {
return reinterpret_cast<archive*>(new core::Archive(archiveName));
}

void archive_destroy(archive* a) { delete reinterpret_cast<core::Archive*>(a); }

int archive_write(archive* a, const char* id, const void* buffer, size_t size) {
return reinterpret_cast<core::Archive*>(a)->write(id, buffer, size) ? 1 : 0;
}

} // extern "C"
12 changes: 12 additions & 0 deletions core/cc/archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef CORE_ARCHIVE_H
#define CORE_ARCHIVE_H

#ifdef __cplusplus

#include "id.h"

#include <string>
Expand Down Expand Up @@ -57,4 +59,14 @@ class Archive {

} // namespace core

extern "C" {
#endif
typedef struct archive_t archive;
archive* archive_create(const char* archiveName);
void archive_destroy(archive* a);
int archive_write(archive* a, const char* id, const void* buffer, size_t size);
#ifdef __cplusplus
} // extern "C"
#endif

#endif // CORE_ARCHIVE_H
50 changes: 50 additions & 0 deletions gapir/cc/replay_archive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2018 Google Inc.
*
* 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.
*/

#include "replay_archive.h"

#include <grpc++/grpc++.h>
#include <fstream>
#include <memory>

#include "gapir/replay_service/service.grpc.pb.h"

namespace gapir {

std::unique_ptr<ReplayArchive::Payload> ReplayArchive::getPayload() {
std::fstream input(mFileprefix, std::ios::in | std::ios::binary);
std::unique_ptr<replay_service::Payload> payload(new replay_service::Payload);
payload->ParseFromIstream(&input);
return std::unique_ptr<Payload>(new Payload(std::move(payload)));
}

std::unique_ptr<ReplayArchive::Resources> ReplayArchive::getResources(
std::unique_ptr<ResourceRequest> req) {
return nullptr;
}
bool ReplayArchive::sendReplayFinished() { return true; }
bool ReplayArchive::sendCrashDump(const std::string& filepath,
const void* crash_data, uint32_t crash_size) {
return true;
}
bool ReplayArchive::sendPostData(std::unique_ptr<Posts> posts) { return true; }
bool ReplayArchive::sendNotification(uint64_t id, uint32_t severity,
uint32_t api_index, uint64_t label,
const std::string& msg, const void* data,
uint32_t data_size) {
return true;
}
} // namespace gapir
51 changes: 51 additions & 0 deletions gapir/cc/replay_archive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 Google Inc.
*
* 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.
*/

#ifndef GAPIR_REPLAY_ARCHIVE_H
#define GAPIR_REPLAY_ARCHIVE_H

#include "core/cc/archive.h"
#include "replay_connection.h"
namespace gapir {

// ReplayArchive implements ReplayConnection for exported replays.
class ReplayArchive : public ReplayConnection {
public:
ReplayArchive(const std::string& fileprefix)
: ReplayConnection(nullptr), mFileprefix(fileprefix) {}
// Read payload from disk.
virtual std::unique_ptr<Payload> getPayload() override;

// We are reading from disk, so the following methods are not implemented.
virtual std::unique_ptr<Resources> getResources(
std::unique_ptr<ResourceRequest> req) override;
virtual bool sendReplayFinished() override;
virtual bool sendCrashDump(const std::string& filepath,
const void* crash_data,
uint32_t crash_size) override;
virtual bool sendPostData(std::unique_ptr<Posts> posts) override;
virtual bool sendNotification(uint64_t id, uint32_t severity,
uint32_t api_index, uint64_t label,
const std::string& msg, const void* data,
uint32_t data_size) override;

private:
std::string mFileprefix;
};

} // namespace gapir

#endif // GAPIR_REPLAY_ARCHIVE_H
3 changes: 3 additions & 0 deletions gapir/cc/resource_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ bool ResourceCache::Batch::flush(ResourceCache& cache, ReplayConnection* conn) {
if (count == 0) {
return true;
}
if (!cache.mFallbackProvider) {
return false;
}
if (!cache.mFallbackProvider->get(mResources.data(), count, conn, ptr,
mSize)) {
return false;
Expand Down
5 changes: 5 additions & 0 deletions gapis/api/vulkan/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -781,3 +781,8 @@ func (a API) QueryIssues(
}
return res.([]replay.Issue), nil
}

// ExportReplayRequest returns request type for standalone replay.
func (a API) ExportReplayRequest() replay.Request {
return issuesRequest{}
}
15 changes: 15 additions & 0 deletions gapis/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,21 @@ func (c *client) SaveCapture(ctx context.Context, capture *path.Capture, path st
return nil
}

func (c *client) ExportReplay(ctx context.Context, capture *path.Capture, device *path.Device, path string) error {
res, err := c.client.ExportReplay(ctx, &service.ExportReplayRequest{
Capture: capture,
Path: path,
Device: device,
})
if err != nil {
return err
}
if err := res.GetError(); err != nil {
return err.Get()
}
return nil
}

func (c *client) GetDevices(ctx context.Context) ([]*path.Device, error) {
res, err := c.client.GetDevices(ctx, &service.GetDevicesRequest{})
if err != nil {
Expand Down
Loading

0 comments on commit 0ce2181

Please sign in to comment.