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

cmd/snap: support for --ensure argument for snap debug timings #6793

Merged
merged 19 commits into from May 10, 2019

Conversation

stolowski
Copy link
Contributor

@stolowski stolowski commented Apr 29, 2019

Support for displaying timings related to the given "ensure"-activity, e.g.
snap debug timings --ensure=seed. Possible values for "ensure" currently are: "seed", "become-operational", "auto-refresh", "refresh-catalogs", "refresh-hints".

@pedronis pedronis self-requested a review May 1, 2019 10:22
Copy link
Collaborator

@pedronis pedronis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, some initial comments


// now combine with the other data about the change
chg, err := x.client.Change(chgid)
if err != nil {
return err
}

if len(timings.EnsureTimings) > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we want a single tabwriter and somehow make the two parts align more, or even use a single header and match concepts somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a nice idea, done. Here is sample result:

pawel@ubuntu:~/gocode/src/github.com/snapcore/snapd/cmd/snap$ ./snap debug timings --ensure=auto-refresh --verbose
ID      Status        Doing      Undoing  Label                   Summary
ensure  -             668ms            -  auto-refresh            query store and setup auto-refresh change
206     Done           13ms            -  prerequisites           Ensure prerequisites for "gnome-3-28-1804" are available
207     Done         1899ms            -  download-snap           Download snap "gnome-3-28-1804" (40) from channel "stable"
 ^                   1893ms            -  download                  download snap "gnome-3-28-1804"
208     Done          664ms            -  validate-snap           Fetch and check assertions for snap "gnome-3-28-1804" (40)
209     Done          949ms            -  mount-snap              Mount snap "gnome-3-28-1804" (40)
 ^                    568ms            -  check-snap                check snap "gnome-3-28-1804"
 ^                    348ms            -  setup-snap                setup snap "gnome-3-28-1804"
210     Done            8ms            -  run-hook                Run pre-refresh hook of "gnome-3-28-1804" snap if present

@@ -32,7 +32,8 @@ import (

type cmdChangeTimings struct {
changeIDMixin
Verbose bool `long:"verbose"`
EnsureID string `long:"ensure"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ID/Tag/ perhaps? also in the rest?

}

if err := x.client.DebugGet("change-timings", &timings, map[string]string{"change-id": chgid}); err != nil {
if err := x.client.DebugGet("change-timings", &timings, map[string]string{"change-id": chgid, "ensure-id": x.EnsureID}); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ensure-id/ensure/ ?

}
return BadRequest("multiple timings found for ensure %q, please specify change ID (%s)", ensureID, strings.Join(changes, ","))
}
ensureChangeID := ensures[0].Tags["change-id"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think we want the latest one, no? not the first

EDIT: AH, we fail if we have more than one, as I said probably we just want to return the latest instead. And have a --all version that shows all the known ensures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

if len(ensures) > 1 {
var changes []string
for _, ensure := range ensures {
if chg, ok := ensure.Tags[""]; ok {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this line, what is Tag "" ? is this code tested? was it meant to be "change-id" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, a bad edit, and I haven't tested this error path. Debug timings client currently has no tests at all, so I only test this manually. Will add some tests soon. Thanks for catching!

@@ -152,7 +194,8 @@ func getDebug(c *Command, r *http.Request, user *auth.UserState) Response {
}, nil)
case "change-timings":
chgID := query.Get("change-id")
return getChangeTimings(st, chgID)
ensureID := query.Get("ensure-id")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/-id//

@@ -42,6 +43,7 @@ func init() {
func() flags.Commander {
return &cmdChangeTimings{}
}, changeIDMixinOptDesc.also(map[string]string{
"ensure": i18n.G("Show timings for a change related to the given Ensure"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what we are looking for are really subpart of Ensure and changes triggered from those, so maybe s/Ensure/Ensure activity/ ?

Copy link
Collaborator

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nitpicks & suggestions. The PR seems to be missing tests?

cmd/snap/cmd_debug_timings.go Show resolved Hide resolved

// If a specific change was requested, we expect exactly one timingsData element.
// If "ensure" activity was requested, we may get multiple elements (for multiple executions of the ensure)
for _, td := range timings {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: naybe it'd be worthwhile to split this into 2 separate helpers:

func printChangeTimings(out io.Writer, timings *timingsData, verbose bool) {
...
}

func printEnsureTimings(out io.Writer, timings []timingsData, verbose bool) {
    ...
    for _, td := range timings {
        if td.ChangeID != "" {
            printChangeTimings(out, &td, verbose)
        }
    }
}

func (x *cmdChangeTimings) Execute(args []string) error {
    ...
    if chgid != "" && len(timings) > 0 {
        printChangeTimings(w, &timings[0], x.Verbose)
    } else {
       printChangeTimings(w, timings, x.Verbose)
    }
    ...
    w.Flush()
}

// If ensure tag was passed by the client, find its related changes;
// we can have many ensure executions and their changes in the responseData array.
if ensureTag != "" {
ensures, err := timings.Get(st, -1, func(tags map[string]string) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: this could be captured in func collectEnsureTimings(st *state.State, ensureTag string) ([]*debugTimings, error) helper

@codecov-io
Copy link

Codecov Report

Merging #6793 into master will decrease coverage by 0.02%.
The diff coverage is 65.19%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #6793      +/-   ##
==========================================
- Coverage    79.5%   79.48%   -0.03%     
==========================================
  Files         608      609       +1     
  Lines       46910    46991      +81     
==========================================
+ Hits        37298    37353      +55     
- Misses       6634     6653      +19     
- Partials     2978     2985       +7
Impacted Files Coverage Δ
overlord/snapstate/snapstate.go 82.29% <ø> (ø) ⬆️
cmd/snap/cmd_debug_timings.go 7.77% <0%> (-3.16%) ⬇️
overlord/devicestate/handlers.go 72.84% <100%> (ø) ⬆️
overlord/devicestate/helpers.go 100% <100%> (ø) ⬆️
overlord/ifacestate/helpers.go 75.46% <100%> (+0.28%) ⬆️
daemon/api_model.go 72.41% <100%> (ø) ⬆️
overlord/devicestate/firstboot.go 80.64% <100%> (ø) ⬆️
overlord/devicestate/devicectx.go 69.23% <100%> (ø) ⬆️
overlord/devicestate/devicestate.go 80% <100%> (+0.63%) ⬆️
gadget/gadget.go 95.52% <100%> (+0.02%) ⬆️
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7e37021...043ade4. Read the comment docs.

@stolowski
Copy link
Contributor Author

Looks like I broke --last, investigating

@pedronis pedronis self-requested a review May 7, 2019 15:38
bboozzoo
bboozzoo previously approved these changes May 8, 2019
Copy link
Collaborator

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Left one open question.

}

func collectEnsureTimings(st *state.State, ensureTag string, allEnsures bool) ([]*debugTimings, error) {
ensures, err := timings.Get(st, -1, func(tags map[string]string) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at timings.Get, wondering about the case when allEnsures == false, when we grab/unmarshal/filter all the entries, but only push the last one out. Given that there will always be quite a bit of timings data, must of the work is being discarded. OTOH, maybe it's not a problem after all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think performance it's a concern as this is a debug interface, also I'm not sure this can be avoided given that we need to look into tags. FWTW we currently keep up to 100 "root-level" timings (but yes, they can have a few nested timings each).

if len(td.EnsureTimings) > 0 {
for _, t := range td.EnsureTimings {
if x.Verbose {
fmt.Fprintf(w, "%s\t%s\t%11s\t%11s\t%s\t%s\n", "ensure", "-", formatDuration(t.Duration), "-", t.Label, t.Summary)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused, what do we do with level/nesting here, the timings from Ensure itself can be nested, no?

Copy link
Contributor Author

@stolowski stolowski May 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I forgot about nesting indicator here, thanks for catching.

It's now added, plus some refactoring to have one printing helper for all timings. Note though, we won't see any nesting for current ensure timings (unless I missed something) as are all level 0; for the "refresh-catalogs" ensure discussed on IRC, we have "refresh-catalogs" root timing node (with tags), and two level-0 measurements under it. So the output is:

pawel@ubuntu:~/gocode/src/github.com/snapcore/snapd/cmd/snap$ ./snap debug timings --ensure=refresh-catalogs --all --verbose
ID      Status        Doing      Undoing  Label           Summary
ensure                 34ms            -  get-sections    query store for sections
ensure               1835ms            -  write-catalogs  query store for catalogs
ensure                209ms            -  get-sections    query store for sections
ensure                374ms            -  write-catalogs  query store for catalogs

This is different for task timings, because we nest them visually even for level 0 as they are displayed under task info line coming from Task. Maybe we should add artifical line for ensure timings (with just the requested ensure tag name) and nest everything with level 0 under it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, as we discussed the latter seems maybe a good idea (for clarity mostly), but as we also discussed can be a follow up

@pedronis
Copy link
Collaborator

pedronis commented May 8, 2019

@stolowski This is looking good from my POV but don't have time to do another deep review. It has changed also quite a bit, it just needs any 2 reviews now assuming no more output changes for this round.

@pedronis pedronis dismissed bboozzoo’s stale review May 8, 2019 11:26

changed quite a bit since

Copy link
Contributor

@mvo5 mvo5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I would love to have a small unit test for cmd_debug_timings.go - but given that we did not have one before this should not block things I think.

@stolowski
Copy link
Contributor Author

Unit tests for all snap debug timings functionality added in #6858

Copy link
Collaborator

@bboozzoo bboozzoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -42,6 +44,8 @@ func init() {
func() flags.Commander {
return &cmdChangeTimings{}
}, changeIDMixinOptDesc.also(map[string]string{
"ensure": i18n.G("Show timings for a change related to the given Ensure activity (one of: auto-refresh, become-operational, refresh-catalogs, refresh-hints, seed)"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a debug command, so not a high priority, but I wonder whether we could take some steps to make sure the list gets updated when new ensure tags are added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants