Closed Bug 922221 Opened 11 years ago Closed 9 years ago

Add console.timeStamp

Categories

(DevTools :: Console, enhancement, P2)

enhancement

Tracking

(firefox40 fixed)

RESOLVED FIXED
Firefox 40
Tracking Status
firefox40 --- fixed

People

(Reporter: fitzgen, Assigned: jsantell)

References

(Blocks 3 open bugs)

Details

(Keywords: dev-doc-complete, Whiteboard: [console-papercuts])

Attachments

(1 file, 5 obsolete files)

https://github.com/DeveloperToolsWG/console-object/blob/master/api.md#consoletimestamplabel

> This method adds an event to the Timeline during a recording session. This lets
> you visually correlate your code generated time stamp to other events, such as
> screen layout and paints, that are automatically added to the Timeline.
Priority: -- → P3
I construed that to be adding support to the netmonitor UI (as opposed to the profiler or console) while this one is for actually implementing the method on the console object. Updated the relationship to reflect this better.
Blocks: 884125
(In reply to Nick Fitzgerald [:fitzgen] from comment #2)
> I construed that to be adding support to the netmonitor UI (as opposed to
> the profiler or console) while this one is for actually implementing the
> method on the console object. Updated the relationship to reflect this
> better.

Oh, you’re right, my apologies.
Whiteboard: [console-papercuts]
Depends on: 1139794
Assignee: nobody → jsantell
Attached patch 899753-timestamp.patch (obsolete) — Splinter Review
Added console.timeStamp() to fire off TimelineMarkers.

Notes: 
* This is my first C++ patch so please tear apart and ensure I didn't do anything terrible.
* Tests for the TimelineMarker creation, as well as ConsoleEvent creation.
* Should this have its own ConsoleEvent struct like ConsoleTimerStart/ConsoleTimerEnd? The base object ConsoleEvent covers all necessary fields (arguments, timeStamp, level).
* This seems to be the first TimelineMarker of its kind to not really have a duration value, just a single point in time. Should probably consider maybe changing TimelineMarker to support that in the future? For now, just creates both a start and stop marker immediately after each other.
* time/timeEnd require an argument to label them (although, Chrome doesn't, and this may be a future bug), but timeStamp() should not. I have some weird logic in there to handle whether or not an argument is passed that I'm sure can be better, but not sure how that works.

What kind of tests should I run on try for this?
Attachment #8579492 - Flags: feedback?(ttromey)
Comment on attachment 8579492 [details] [diff] [review]
899753-timestamp.patch

Review of attachment 8579492 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/base/Console.cpp
@@ +788,5 @@
> +  Sequence<JS::Value> data;
> +  SequenceRooter<JS::Value> rooter(aCx, &data);
> +
> +  if (!aData.isUndefined()) {
> +    data.AppendElement(aData);

This looks right.

@@ +1079,5 @@
>        }
>  
> +      // 'timeStamp' recordings do not need an argument
> +      if (isTimelineRecording && aMethodName == MethodTimeStamp) {
> +        if (aData.Length() == 0) {

You say you're having issues with "undefined" when you call console.timeStamp() with no arguments. So is this condition never true for you? I'd think that conditionally adding the parameter to the sequence data behind `if (!data.isUndefined())` check above would handle this.

Can you verify that you aren't hitting this branch, and that the ToString call in the other branch is indeed the one giving you "undefined"?

It looks like you're handling this stuff properly, at a glance. I wouldn't be surprised if this bug was actually happening down the pipe in some JS code somewhere.

I guess you could always try `if (aData.Length() == 0 || aData[0].isUndefined())` but if that doesn't fix it, then the bug is definitely down the line.

@@ +1089,5 @@
> +            nsAutoJSString key;
> +            if (key.init(aCx, jsString)) {
> +              mozilla::UniquePtr<TimelineMarker> marker =
> +                MakeUnique<TimestampTimelineMarker>(docShell, TRACING_INTERVAL_START, key);
> +              docShell->AddProfileTimelineMarker(marker);

Aside/unrelated: it seems strange to me that AddProfileTimelineMarker doesn't take ownership of the marker... Need to read some code to figure out what's up here.
Comment on attachment 8579492 [details] [diff] [review]
899753-timestamp.patch

(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #4)
> Created attachment 8579492 [details] [diff] [review]
> 899753-timestamp.patch
> 
> Added console.timeStamp() to fire off TimelineMarkers.
> 
> Notes: 
> * This is my first C++ patch so please tear apart and ensure I didn't do
> anything terrible.

Nice!  I didn't see anything bad at all.

> * Should this have its own ConsoleEvent struct like
> ConsoleTimerStart/ConsoleTimerEnd? The base object ConsoleEvent covers all
> necessary fields (arguments, timeStamp, level).
> * This seems to be the first TimelineMarker of its kind to not really have a
> duration value, just a single point in time. Should probably consider maybe
> changing TimelineMarker to support that in the future? For now, just creates
> both a start and stop marker immediately after each other.

I think my ideal would be to keep TimestampTimelineMarker (as you have),
but use TRACING_EVENT rather than TRACING_INTERVAL_START, and only have
a single call to AddProfileTimelineMarker.

Then, nsDocShell::PopProfileTimelineMarkers would have to be updated to
handle TRACING_EVENT.  And since we push other TRACING_EVENTS that we don't
want to pop in isolation (see FrameLayerBuilder.cpp:LayerTimelineMarker),
another special case in there would be needed; like say some new virtual
method on TimelineMarker.

I'd check with smaug before embarking on this, perhaps, since last time around
he was concerned with the proliferation of special cases.  Though it's also
worth pointing out that this would be useful when we deal with emitting
console.time/timeEnd as separate events.

I guess this route would need more changes in js as well, to handle the new
case where a marker has a start time but no end time.

> * time/timeEnd require an argument to label them (although, Chrome doesn't,
> and this may be a future bug), but timeStamp() should not. I have some weird
> logic in there to handle whether or not an argument is passed that I'm sure
> can be better, but not sure how that works.

Me neither :}

> What kind of tests should I run on try for this?

Another thing I'd like to know myself.
Attachment #8579492 - Flags: feedback?(ttromey) → feedback+
Comment on attachment 8579492 [details] [diff] [review]
899753-timestamp.patch

Review of attachment 8579492 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/base/Console.cpp
@@ +1079,5 @@
>        }
>  
> +      // 'timeStamp' recordings do not need an argument
> +      if (isTimelineRecording && aMethodName == MethodTimeStamp) {
> +        if (aData.Length() == 0) {

Sorry, to clarify, I was having the issue of "undefined" string, but got around it with this in the patch -- just wasn't sure if there was a nicer way to do this. I definitely should check for the first element being undefined though, and test `console.timeStamp(undefined)` in that case
(In reply to Tom Tromey :tromey from comment #6)
> Comment on attachment 8579492 [details] [diff] [review]
> 899753-timestamp.patch
> 
> (In reply to Jordan Santell [:jsantell] [@jsantell] from comment #4)
> > Created attachment 8579492 [details] [diff] [review]
> > 899753-timestamp.patch
> > 
> > Added console.timeStamp() to fire off TimelineMarkers.
> > 
> > Notes: 
> > * This is my first C++ patch so please tear apart and ensure I didn't do
> > anything terrible.
> 
> Nice!  I didn't see anything bad at all.
> 
> > * Should this have its own ConsoleEvent struct like
> > ConsoleTimerStart/ConsoleTimerEnd? The base object ConsoleEvent covers all
> > necessary fields (arguments, timeStamp, level).
> > * This seems to be the first TimelineMarker of its kind to not really have a
> > duration value, just a single point in time. Should probably consider maybe
> > changing TimelineMarker to support that in the future? For now, just creates
> > both a start and stop marker immediately after each other.
> 
> I think my ideal would be to keep TimestampTimelineMarker (as you have),
> but use TRACING_EVENT rather than TRACING_INTERVAL_START, and only have
> a single call to AddProfileTimelineMarker.
> 
> Then, nsDocShell::PopProfileTimelineMarkers would have to be updated to
> handle TRACING_EVENT.  And since we push other TRACING_EVENTS that we don't
> want to pop in isolation (see FrameLayerBuilder.cpp:LayerTimelineMarker),
> another special case in there would be needed; like say some new virtual
> method on TimelineMarker.

> I'd check with smaug before embarking on this, perhaps, since last time
> around
> he was concerned with the proliferation of special cases.  Though it's also
> worth pointing out that this would be useful when we deal with emitting
> console.time/timeEnd as separate events.

I'd say that the layering is more of a special case than a marker that only has one time value. Outside of console methods, I can imagine other scenarios where we'd be interested in just a single value of an event occurring. If we have TimelineMarkers that consist only a name ("Timestamp"), metadata (TRACING_EVENT) and a cause (arbitrary string/undefined), that'd cover all the console scenarios atleast ("Timestamp", "TimeStart", "TimeEnd", etc), and we can check for is a marker TRACING_EVENT && aName != "Layer" in the marker loop, as that seems like the biggest special case, rather than the other way around.

> I guess this route would need more changes in js as well, to handle the new
> case where a marker has a start time but no end time.

That's true, but that's pretty straight forward -- more difficult part is having a special rule for TimeStart/TimeEnd when they're different markers, and correlating them, but still doable

> > * time/timeEnd require an argument to label them (although, Chrome doesn't,
> > and this may be a future bug), but timeStamp() should not. I have some weird
> > logic in there to handle whether or not an argument is passed that I'm sure
> > can be better, but not sure how that works.
> 
> Me neither :}
> 
> > What kind of tests should I run on try for this?
> 
> Another thing I'd like to know myself.

@smaug
Thoughts on using TRACING_EVENTS for TimelineMarkers that only have one time value? LayerTimelineMarkers can remain the special use case, but this would allow us to have multiple markers for console.time/timeEnd, as well as not having both TRACING_INTERVAL_START and TRACING_INTERVAL_END for a single-valued "timestamp"
Flags: needinfo?(bugs)
Hmm, I'm a bit lost how this all would work. Why does console API depend here on whether we're recording timeline? How would the setup work for iframes and such? I assume we usually record
only top level content docshells.
(I'm not familiar with Bug 1050502, which added some existing stuff there.)
Flags: needinfo?(bugs)
Looks like AddProfileTimelineMarkers checks to see if there's a timeline recording before adding the marker anyway, so that may be redundant. But without a recording timeline, there's no need for markers in the first place (as far as I know?)

Currently, console.time/timeEnd works with iframes (iframe emits console.time/timeEnd, and the console displays the timer messages, and if recording, the markers appear on the devtools timeline).
Ok, so we somehow mark also iframes to be recording. I guess the setup is fine then - assuming we
need the information only when recording.
And regarding TRACING_EVENTS use... whatever makes the code easiest to understand and maintain.
(this isn't particularly performance hot code)
(In reply to Olli Pettay [:smaug] from comment #9)
> Hmm, I'm a bit lost how this all would work. Why does console API depend
> here on whether we're recording timeline? 

It's normal for code using a subclass of TimelineMarker to check the docshell first,
to avoid an allocation in the case where the marker is simply going to be deleted.
I was mainly wondering how we deal with subframes.
Attached patch 922221-timestamp.patch (obsolete) — Splinter Review
Thanks all for the feedback!

Updating the PopProfileTimelineMarker method, if this is a TRACING_EVENT (and not Layer, as that's a special scenario), a new marker (in this case "Timestamp") is emitted, with identical start/end times, and also in this case, optional label. The front end can handle this fine (once it's updated to listen to Timestamp markers).

Kyle, I heard you might be a good person to review this; if not, let me know! The tests in this patch pass, but also if there are ideal try flags to run for these directories (platform newb here), I'll give those a go as well.

Thanks!
Attachment #8579492 - Attachment is obsolete: true
Attachment #8579765 - Flags: review?(khuey)
(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #14)

> Updating the PopProfileTimelineMarker method, if this is a TRACING_EVENT
> (and not Layer, as that's a special scenario), a new marker (in this case
> "Timestamp") is emitted, with identical start/end times, and also in this
> case, optional label. The front end can handle this fine (once it's updated
> to listen to Timestamp markers).

I think it would be good for TimestampTimelineMarker to try to capture a
stack trace in its constructor.  It can just call CaptureStack() unconditionally.
Then the new code in docshell could put the stack on the marker object.
Comment on attachment 8579765 [details] [diff] [review]
922221-timestamp.patch

Review of attachment 8579765 [details] [diff] [review]:
-----------------------------------------------------------------

You need to test this in workers too.  Look at dom/workers/test/test_console.html.  r- for that, but this looks pretty good otherwise.

::: dom/base/Console.cpp
@@ +1066,5 @@
>      }
>    }
>  
>    // Monotonic timer for 'time' and 'timeEnd'
> +  if ((aMethodName == MethodTime || aMethodName == MethodTimeEnd || aMethodName == MethodTimeStamp)) {

Wrap at 80 characters please.

@@ +1102,5 @@
> +                MakeUnique<TimestampTimelineMarker>(docShell, TRACING_EVENT, key);
> +              docShell->AddProfileTimelineMarker(marker);
> +            }
> +          }
> +        }

Why not write this as

 if (isTimelineRecording && aMethodName == MethodTimeStamp) {
   JS::Rooted<JS::Value> value(aCx, aData[0]);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));

   nsAutoJSString key;
   if (jsString) {
     key.init(aCx, jsString);
   }
           
   mozilla::UniquePtr<TimelineMarker> marker =
     MakeUnique<TimestampTimelineMarker>(docShell, TRACING_EVENT, key);
   docShell->AddProfileTimelineMarker(marker);
}
Attachment #8579765 - Flags: review?(khuey) → review-
Depends on: 1144820
(In reply to Kyle Huey [:khuey] (khuey@mozilla.com) from comment #16)
> Comment on attachment 8579765 [details] [diff] [review]
> 922221-timestamp.patch
> 
> Review of attachment 8579765 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> You need to test this in workers too.  Look at
> dom/workers/test/test_console.html.  r- for that, but this looks pretty good
> otherwise.

FWIW currently workers can't post markers to the timeline.
Attached patch 922221-timestamp.patch (obsolete) — Splinter Review
* Wrapped lines to <80
* TimestampTimelineMarker now only has one constructor
* Removed if/else logic for when there are no arguments (or undefined) given; using the snippet you wrote, Kyle, but using JS_GetEmptyStringValue, as otherwise the jsString would be cast to strings of "0" or "undefined"
* Added test in the worker to ensure this doesn't throw (but it doesn't/shouldn't do anything yet anyway in a worker)

Once bug 1144820 lands, this will need a 2 character fix or something. What's the desired try command to run tests touching all of these components?

Thanks!
Attachment #8579765 - Attachment is obsolete: true
Attachment #8580781 - Flags: review?(khuey)
Attached patch 922221-timestamp.patch (obsolete) — Splinter Review
Added the changes from bug 1144820 necessary, and changed MOZ_OVERRIDE to override.

https://treeherder.mozilla.org/#/jobs?repo=try&revision=521185667d64
Attachment #8580781 - Attachment is obsolete: true
Attachment #8584673 - Flags: review+
Moving dev-doc-needed to bug 1143004, as this doesn't do anything without the front end
Keywords: dev-doc-needed
Seeing weird AsyncShutdown failures on last try, trying again with a latest hg pull -u https://treeherder.mozilla.org/#/jobs?repo=try&revision=f87cd88a7564
Attached patch 922221-timestamp.patch (obsolete) — Splinter Review
Was failing a test on the timeline front end, as the Layer marker was being emitted. Changed to check to see if it's not Layer or Paint before emitting if its a TRACING_EVENT (meaning an event with one time, rather than two) -- not elegant, but wonder what a better way of indicating this marker does not have a matching pair.

https://treeherder.mozilla.org/#/jobs?repo=try&revision=df9218ad29af
Attachment #8584673 - Attachment is obsolete: true
Attachment #8585142 - Flags: review?(khuey)
Comment on attachment 8585142 [details] [diff] [review]
922221-timestamp.patch

Review of attachment 8585142 [details] [diff] [review]:
-----------------------------------------------------------------

Removing review -- strange failure on password manager?
https://treeherder.mozilla.org/#/jobs?repo=try&revision=df9218ad29af
Attachment #8585142 - Flags: review?(khuey)
(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #23)
> Created attachment 8585142 [details] [diff] [review]
> 922221-timestamp.patch
> 
> Was failing a test on the timeline front end, as the Layer marker was being
> emitted. Changed to check to see if it's not Layer or Paint before emitting
> if its a TRACING_EVENT (meaning an event with one time, rather than two) --
> not elegant, but wonder what a better way of indicating this marker does not
> have a matching pair.

FWIW I think you don't have to check !isPaint.  "Paint" markers should always
be paired.  Sorry I missed this earlier, I think I confused the Paint and Layer
cases.

Also, since you've added isLayer, I think it would be good to change the later
strcmp(endMarkerName, "Layer") == 0 to simply use isLayer as well.

One way to make this cleaner might be to have the TimelineMarker object decide
for itself whether it should be emitted.  This could be a new boolean member,
a virtual function, or perhaps even a new TRACING_* constant.
My original assumptions of TRACING_EVENT being a "one timestamp event with no pairing" was incorrect, because of the layer and paint events, hence the reason for all the checks, which isn't great, as future markers may also be added here, and if we want to make it easy for one-time events to be implemented by others, this makes it more confusing/difficult.

What is the connotation of the TRACING_EVENT/START/END properties? If it doesn't make sense for that to also mean "a one time event", then adding a bool memory/function is probably the best way to go
(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #26)
> My original assumptions of TRACING_EVENT being a "one timestamp event with
> no pairing" was incorrect, because of the layer and paint events, hence the
> reason for all the checks, which isn't great, as future markers may also be
> added here, and if we want to make it easy for one-time events to be
> implemented by others, this makes it more confusing/difficult.

Yeah.

> What is the connotation of the TRACING_EVENT/START/END properties? If it
> doesn't make sense for that to also mean "a one time event", then adding a
> bool memory/function is probably the best way to go

The enum constants were just reused from the profiling code and made to fit.
This also explains the name of some methods ("PopProfileTimelineMarkers" - it
doesn't really have anything to do with profiling per se) and some other old
stuff (no longer in tree).

Dropping the use of TracingMetadata in favor of a new enum solely for these
markers would be fine with me.  Then Layer could just have its own special constant.

I think the meaning of the constants is just as you assume; with the caveat that
there is this hack for Layer markers due to how the Paint/Layer markers interact.
Whiteboard: [console-papercuts] → [console-papercuts][devedition-40]
(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #21)
> Moving dev-doc-needed to bug 1143004, as this doesn't do anything without
> the front end

Setting dev-doc-needed back. As far as I understand the patch, this change a webidl that is exposed.
Keywords: dev-doc-needed
Blocks a P2, so I'm updating the priority to reflect that.
Status: NEW → ASSIGNED
Priority: P3 → P2
Created new TracingMetadata, TRACING_TIMESTAMP, for single time value markers
https://treeherder.mozilla.org/#/jobs?repo=try&revision=e212e3db45fd
Attachment #8585142 - Attachment is obsolete: true
Comment on attachment 8599476 [details] [diff] [review]
922221-timestamp.patch

Ok, switched to using TRACING_TIMESTAMP for the single-value marker, and doesn't conflict with the other markers using TRACING_EVENT. Kyle, can you give this one more look over? Tests looking good.
Attachment #8599476 - Flags: review?(khuey)
Kyle, any chance you could look at this next week?
Thanks, Kyle!
Landed: https://hg.mozilla.org/integration/fx-team/rev/641fcb51bd9a

Tom, pinging you here so you're aware of the TRACING_TIMESTAMP for a single value marker which could be useful elsewhere.
Flags: needinfo?(ttromey)
Whiteboard: [console-papercuts][devedition-40] → [console-papercuts][devedition-40][fixed-in-fx-team]
https://hg.mozilla.org/mozilla-central/rev/641fcb51bd9a
Status: ASSIGNED → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Whiteboard: [console-papercuts][devedition-40][fixed-in-fx-team] → [console-papercuts][devedition-40]
Target Milestone: --- → Firefox 40
(In reply to Jordan Santell [:jsantell] [@jsantell] from comment #33)
> Thanks, Kyle!
> Landed: https://hg.mozilla.org/integration/fx-team/rev/641fcb51bd9a
> 
> Tom, pinging you here so you're aware of the TRACING_TIMESTAMP for a single
> value marker which could be useful elsewhere.

Thanks for the heads up.
Flags: needinfo?(ttromey)
Blocks: firebug-gaps
Severity: normal → enhancement
OS: Mac OS X → All
Hardware: x86 → All
I've added:
- a page on this in the Console docs: https://developer.mozilla.org/en-US/docs/Web/API/Console/timeStamp
- a section in the Waterfall docs: https://developer.mozilla.org/en-US/docs/Tools/Performance/Waterfall#Timestamp_markers

Let me know if this works for you.
Flags: needinfo?(jsantell)
Looks great, Will; thanks!
Flags: needinfo?(jsantell)
Whiteboard: [console-papercuts][devedition-40] → [console-papercuts][polish-backlog]
Whiteboard: [console-papercuts][polish-backlog] → [console-papercuts]
Product: Firefox → DevTools
You need to log in before you can comment on or make changes to this bug.