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
Conversation
There was a problem hiding this 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
cmd/snap/cmd_debug_timings.go
Outdated
|
||
// 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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
cmd/snap/cmd_debug_timings.go
Outdated
@@ -32,7 +32,8 @@ import ( | |||
|
|||
type cmdChangeTimings struct { | |||
changeIDMixin | |||
Verbose bool `long:"verbose"` | |||
EnsureID string `long:"ensure"` |
There was a problem hiding this comment.
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?
cmd/snap/cmd_debug_timings.go
Outdated
} | ||
|
||
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ensure-id/ensure/ ?
daemon/api_debug.go
Outdated
} | ||
return BadRequest("multiple timings found for ensure %q, please specify change ID (%s)", ensureID, strings.Join(changes, ",")) | ||
} | ||
ensureChangeID := ensures[0].Tags["change-id"] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done.
daemon/api_debug.go
Outdated
if len(ensures) > 1 { | ||
var changes []string | ||
for _, ensure := range ensures { | ||
if chg, ok := ensure.Tags[""]; ok { |
There was a problem hiding this comment.
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" ?
There was a problem hiding this comment.
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!
daemon/api_debug.go
Outdated
@@ -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") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/-id//
cmd/snap/cmd_debug_timings.go
Outdated
@@ -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"), |
There was a problem hiding this comment.
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/ ?
… activities of given ensure, and use single tab writer.
There was a problem hiding this 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
Outdated
|
||
// 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 { |
There was a problem hiding this comment.
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()
}
daemon/api_debug.go
Outdated
// 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 { |
There was a problem hiding this comment.
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 Report
@@ 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
Continue to review full report at Codecov.
|
Looks like I broke --last, investigating |
…s when quering for ensure timings.
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
cmd/snap/cmd_debug_timings.go
Outdated
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
…use one print helper for all timings.
@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. |
There was a problem hiding this 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.
Unit tests for all snap debug timings functionality added in #6858 |
There was a problem hiding this 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)"), |
There was a problem hiding this comment.
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.
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".