Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the server status in the UI. #2585

Merged
merged 2 commits into from
Feb 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 130 additions & 144 deletions cmd/gapit/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"time"

"github.com/google/gapid/core/app"
"github.com/google/gapid/core/app/crash"
"github.com/google/gapid/core/event/task"
"github.com/google/gapid/core/log"
"github.com/google/gapid/gapis/service"
Expand Down Expand Up @@ -75,6 +76,26 @@ func readableBytes(nBytes uint64) string {
}
}

func newTask(id, parent uint64, name string, background bool) *tsk {
return &tsk{
id: id,
parentID: parent,
name: name,
background: background,
children: map[uint64]*tsk{},
}
}

type tsk struct {
id uint64
parentID uint64
name string
background bool
progress int32
blocked bool
children map[uint64]*tsk
}

func (verb *statusVerb) Run(ctx context.Context, flags flag.FlagSet) error {
client, err := getGapis(ctx, verb.Gapis, GapirFlags{})
if err != nil {
Expand All @@ -88,16 +109,6 @@ func (verb *statusVerb) Run(ctx context.Context, flags flag.FlagSet) error {

statusMutex := sync.Mutex{}

type tsk struct {
id uint64
parentID uint64
name string
background bool
progress int32
blocked bool
children map[uint64]*tsk
}

ancestors := make(map[uint64][]uint64)
activeTasks := make(map[uint64]*tsk)
totalBlocked := 0
Expand Down Expand Up @@ -171,163 +182,138 @@ func (verb *statusVerb) Run(ctx context.Context, flags flag.FlagSet) error {
})
defer stopPolling()

endStat, err := client.Status(ctx,
time.Duration(verb.MemoryUpdateInterval/2)*time.Millisecond,
time.Duration(verb.StatusUpdateInterval/2)*time.Millisecond,
func(tu *service.TaskUpdate) {
statusMutex.Lock()
defer statusMutex.Unlock()
ec := make(chan error)
ctx, cancel := context.WithCancel(ctx)
crash.Go(func() {
err := client.Status(ctx,
time.Duration(verb.MemoryUpdateInterval/2)*time.Millisecond,
time.Duration(verb.StatusUpdateInterval/2)*time.Millisecond,
func(tu *service.TaskUpdate) {
statusMutex.Lock()
defer statusMutex.Unlock()

if tu.Status == service.TaskStatus_STARTING {
// If this is a top-level task, add it to our list of top-level tasks.
if tu.Parent == 0 {
activeTasks[tu.Id] = &tsk{
tu.Id,
0,
tu.Name,
tu.Background,
0,
false,
make(map[uint64]*tsk),
}
} else {
if p, ok := ancestors[tu.Parent]; ok {
// If we can find this tasks parent, then add it in the tree
if a := findTask(activeTasks, append(p, tu.Parent)); a != nil {
a.children[tu.Id] = &tsk{
if tu.Status == service.TaskStatus_STARTING {
// If this is a top-level task, add it to our list of top-level tasks.
if tu.Parent == 0 {
activeTasks[tu.Id] = newTask(tu.Id, 0, tu.Name, tu.Background)
} else {
if p, ok := ancestors[tu.Parent]; ok {
// If we can find this tasks parent, then add it in the tree
if a := findTask(activeTasks, append(p, tu.Parent)); a != nil {
a.children[tu.Id] = newTask(tu.Id, tu.Parent, tu.Name, tu.Background || a.background)
ans := append([]uint64{}, ancestors[tu.Parent]...)
ancestors[tu.Id] = append(ans, tu.Parent)
} else {
// If we don't have the parent for whatever reason,
// treat this as a top-level task.
activeTasks[tu.Id] = newTask(
tu.Id,
0,
tu.Name,
tu.Background)
}
} else if a, ok := activeTasks[tu.Parent]; ok {
// If the parent of this task is a top level task,
// then add it there.
a.children[tu.Id] = newTask(
tu.Id,
tu.Parent,
tu.Name,
tu.Background || a.background,
0,
false,
make(map[uint64]*tsk),
}
tu.Background || a.background)
ans := append([]uint64{}, ancestors[tu.Parent]...)
ancestors[tu.Id] = append(ans, tu.Parent)
} else {
// If we don't have the parent for whatever reason,
// treat this as a top-level task.
activeTasks[tu.Id] = &tsk{
// Fallback to adding this as its own top-level task.
activeTasks[tu.Id] = newTask(
tu.Id,
0,
tu.Name,
tu.Background,
0,
false,
make(map[uint64]*tsk),
tu.Background)
}
}
} else if tu.Status == service.TaskStatus_FINISHED {
// Remove this from all parents.
// Make sure to fix up our "totalBlocked" if our
// blocked task finished.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
if t.blocked {
if totalBlocked > 0 {
totalBlocked--
}
}
} else if a, ok := activeTasks[tu.Parent]; ok {
// If the parent of this task is a top level task,
// then add it there.
a.children[tu.Id] = &tsk{
tu.Id,
tu.Parent,
tu.Name,
tu.Background || a.background,
0,
false,
make(map[uint64]*tsk),
})
if len(loc) > 1 {
// Find the parent, and remove us
if t := findTask(activeTasks, loc[:len(loc)-1]); t != nil {
delete(t.children, tu.Id)
}
ans := append([]uint64{}, ancestors[tu.Parent]...)
ancestors[tu.Id] = append(ans, tu.Parent)
} else {
// Fallback to adding this as its own top-level task.
activeTasks[tu.Id] = &tsk{
tu.Id,
0,
tu.Name,
tu.Background,
0,
false,
make(map[uint64]*tsk),
}
delete(activeTasks, tu.Id)
}
}
} else if tu.Status == service.TaskStatus_FINISHED {
// Remove this from all parents.
// Make sure to fix up our "totalBlocked" if our
// blocked task finished.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
if t.blocked {
} else if tu.Status == service.TaskStatus_PROGRESS {
// Simply update the progress for our task
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
if a := findTask(activeTasks, loc); a != nil {
a.progress = tu.CompletePercent
}
} else if tu.Status == service.TaskStatus_BLOCKED {
// If a task becomes blocked, then we should block
// it and all of its ancestors.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
totalBlocked++
t.blocked = true
})
} else if tu.Status == service.TaskStatus_UNBLOCKED {
// If a task becomes unblocked, then we should unblock
// it and all of its ancestors.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
if totalBlocked > 0 {
totalBlocked--
}
}
})
if len(loc) > 1 {
// Find the parent, and remove us
if t := findTask(activeTasks, loc[:len(loc)-1]); t != nil {
delete(t.children, tu.Id)
}
} else {
delete(activeTasks, tu.Id)
}
} else if tu.Status == service.TaskStatus_PROGRESS {
// Simply update the progress for our task
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
if a := findTask(activeTasks, loc); a != nil {
a.progress = tu.CompletePercent
t.blocked = false
})
} else if tu.Status == service.TaskStatus_EVENT {
fmt.Printf("EVENT--> %+v\n", tu.Event)
}
} else if tu.Status == service.TaskStatus_BLOCKED {
// If a task becomes blocked, then we should block
// it and all of its ancestors.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}, func(tu *service.MemoryStatus) {
if tu.TotalHeap > maxMemoryUsage {
maxMemoryUsage = tu.TotalHeap
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
totalBlocked++
t.blocked = true
})
} else if tu.Status == service.TaskStatus_UNBLOCKED {
// If a task becomes unblocked, then we should unblock
// it and all of its ancestors.
loc := []uint64{}
if a, ok := ancestors[tu.Id]; ok {
loc = a
}
loc = append(loc, tu.Id)
forLineage(activeTasks, loc, func(t *tsk) {
if totalBlocked > 0 {
totalBlocked--
}
t.blocked = false
})
} else if tu.Status == service.TaskStatus_EVENT {
fmt.Printf("EVENT--> %+v\n", tu.Event)
}
}, func(tu *service.MemoryStatus) {
if tu.TotalHeap > maxMemoryUsage {
maxMemoryUsage = tu.TotalHeap
}
currentMemoryUsage = tu.TotalHeap
})
if err != nil {
return log.Err(ctx, err, "Failed to connect to the GAPIS status stream")
}
defer endStat()
currentMemoryUsage = tu.TotalHeap
})
ec <- err
})

var wait sync.WaitGroup
wait.Add(1)
var sigChan chan os.Signal
sigChan = make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
go func() {
<-sigChan
wait.Done()
}()
wait.Wait()

select {
case <-sigChan:
cancel()
case err := <-ec:
if err != nil {
return log.Err(ctx, err, "Failed to connect to the GAPIS status stream")
}
}
return nil
}
28 changes: 26 additions & 2 deletions gapic/src/main/com/google/gapid/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.google.gapid.util.MacApplication;
import com.google.gapid.util.Messages;
import com.google.gapid.util.OS;
import com.google.gapid.util.StatusWatcher;
import com.google.gapid.util.UpdateWatcher;
import com.google.gapid.views.StatusBar;
import com.google.gapid.widgets.CopyPaste;
Expand Down Expand Up @@ -76,7 +77,7 @@ public class MainWindow extends ApplicationWindow {
private final Theme theme;
private Composite mainArea;
private LoadingScreen loadingScreen;
private StatusBar statusBar;
protected StatusBar statusBar;

public MainWindow(Settings settings, Theme theme) {
super(null);
Expand All @@ -94,6 +95,7 @@ public void showLoadingMessage(String status) {
public void initMainUi(Client client, Models models, Widgets widgets) {
Shell shell = getShell();

showLoadingMessage("Setting up UI...");
initMenus(client, models, widgets);

LoadablePanel<GraphicsTraceView> mainUi = new LoadablePanel<GraphicsTraceView>(
Expand Down Expand Up @@ -125,8 +127,16 @@ public void onCaptureLoaded(Message error) {
file -> models.capture.loadCapture(new File(file)));
}

if (settings.autoCheckForUpdates) {
// Only show the status message if we're actually checking for updates. watchForUpdates only
//schedules a periodic check to see if we should check for updates and if so, checks.
showLoadingMessage("Watching for updates...");
}
watchForUpdates(client, models);

showLoadingMessage("Tracking server status...");
trackServerStatus(client);

showLoadingMessage("Ready! Please open or capture a trace file.");
}

Expand All @@ -140,6 +150,20 @@ private void watchForUpdates(Client client, Models models) {
});
}

private void trackServerStatus(Client client) {
new StatusWatcher(client, new StatusWatcher.Listener() {
@Override
public void onStatus(String status) {
scheduleIfNotDisposed(statusBar, () -> statusBar.setServerStatus(status));
}

@Override
public void onHeap(long heap) {
scheduleIfNotDisposed(statusBar, () -> statusBar.setServerHeapSize(heap));
}
});
}

@Override
protected void configureShell(Shell shell) {
shell.setText(Messages.WINDOW_TITLE);
Expand All @@ -160,7 +184,7 @@ protected Control createContents(Composite shell) {
loadingScreen = new LoadingScreen(mainArea, theme);
setTopControl(loadingScreen);

statusBar = new StatusBar(parent);
statusBar = new StatusBar(parent, theme);
statusBar.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
return parent;
}
Expand Down
Loading