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

Custom UserTiming Payloads #3

Closed
nicjansma opened this issue Apr 8, 2015 · 21 comments
Closed

Custom UserTiming Payloads #3

nicjansma opened this issue Apr 8, 2015 · 21 comments

Comments

@nicjansma
Copy link

Forked from w3c/performance-timeline#2 and relevant for w3c/performance-timeline#9 (comment).

It might be useful to be able to specify a payload that would be stored along with your marks or measures.

The new method signature might be:

void mark(DOMString markName, object data);

data could be whatever, say {taskid: 1, widgets: 100}

This data attribute would be persisted along with that mark and attached to the PerformanceMark interface:

interface PerformanceMark : PerformanceEntry {
    object data;
};

(I don't know the correct IDL).

data could also be a DOMString. If so, I think there should be a specified string length limit, so people don't just JSON.stringify() a huge payload into it (which would be a lot less efficient than a native object).

This may help with w3c/performance-timeline#9, which discusses a "group" concept useful for any PerformanceEntry in the PerformanceTimeline. @igrigorik mentions being able to query for any entries that share an attribute via a new getEntries(DOMString attributeName, optional DOMString attributeValue) method, but a lone data attribute on UserTiming might not then be useful, unless its properties were automatically attached to the base PerformanceEntry (which I'm sure would introduce headaches with naming collisions).

@stevesouders
Copy link

I need a way to specify a mark's startTime that is NOT the current time.

It's counter-intuitive to create a mark (which results in a startTime value of the current time), and then setting the startTime value to my desired time value. I also don't think that's a preferred approach. (We probably want to make startTime readonly, altho it's currently not in Chrome.)

Would there be a way to set the startTime property with the approach suggested here? If not, how can I do that?

Possible use case, I want a user timing mark for when the first image request above-the-fold started. Or I want a mark based on a comparison, such as the max of duration of three images.

@igrigorik
Copy link
Member

@stevesouders I agree, we shouldn't muck with UA generated startTime.

Based on @nicjansma's suggestion, you'd pass in a data object, which would then be accessible as a property on the event.. e.g:

mark("custom-mark", {time: ..., other: ...});

var m = performance.getEntriesByName("custom-mark");
console.log(m.data.time);
...

@eliperelman
Copy link

Bringing over my use cases from w3c/performance-timeline#2, I like this proposal, but would want to extend this to measures as well. Unfortunately the nature of .measure taking optional parameters would mean a little weirdness with its signature if we adopted just another argument. Forcing the argument to be an object helps though.

@stevesouders Wouldn't your use case be better suited to .measure? e.g.:

performance.mark('desiredStart');
...
performance.measure('customMark', 'desiredStart');

All in all, I am for this change and would like to see it move forward.

@eliperelman
Copy link

@igrigorik there is very strong support for having this feature for a wide variety of use cases here at Mozilla, and I think we should make an effort on moving this forward from a standards perspective. We are going to experiment with this to see how well it works and will report back if there are any caveats.

@eliperelman
Copy link

Specifically what we want to experiment with:

void mark(DOMString markName, optional dictionary payload);
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark, optional dictionary payload);

@igrigorik
Copy link
Member

@eliperelman crazy thought...

  • window.markPayloads = {} -> stores "markName -> payload"
  • patch mark and measure to automatically write and pull from both places, or.. define new methods

That's all we're looking for here, right?

@eliperelman
Copy link

<bikshed>
Not sure about exposing another global on window, but maybe window.performance.payloads?
</bikeshed>

Not sure about the implementation at the moment, but for my specific use cases, I would need access to the payload data from Gecko as well as JS, so a function may be in order.

@igrigorik
Copy link
Member

@eliperelman I'm thinking something even simpler... Namely, I'm questioning if this needs to be specced and implemented at platform level at all, since you can easily implement this yourself.

@eliperelman
Copy link

Yes, I suppose that could be done. Going back to @stevesouders case, it would probably mean wrapping the performance.mark call altogether:

var mark = function(markName, payload) {
  mark.cache[markName] = merge(payload, {
    time: Date.now()
  });
  performance.mark(markName);
};
mark.cache = {};

@eliperelman
Copy link

I guess the nice-to-have deals with the retrieving of data, either on the platform side, or the getEntries et al side. You would need to patch getEntries to also fetch the payload associated with the mark.

Given enough demand though for this type of use case, does it make sense for everyone to duplicate this feature in their apps, or bake it into the web? That's a question that I do not yet know the answer to, @igrigorik. It would be nice to know how people feel about it.

@igrigorik
Copy link
Member

Yep, that's exactly what I was thinking... except, with performance.now() instead of Date :)

We can document the pattern and apps can adopt it on as-needed basis. If we find lots of folks using it out in the wild, we can then revisit and see if offering a 'native' version offers any benefit. Yay/nay?

@eliperelman
Copy link

@igrigorik the performance.mark call will already have the startTime, so adding another performance.now() time is redundant. I used Date.now() just as an example of some sample data, in case you wanted to know the Unix epoch of the mark in addition to the High-Res time. :)

@igrigorik
Copy link
Member

Re .now(): gotcha, makes sense.

Good point on getEntries; same applies to observers. It definitely adds some friction, but it's not clear to me if this is such a big deal.. In fact, let me make the argument in other direction: if some script attaches a custom payload to an event then another observer that's not related to that script doesn't know what to do with that payload, so its overhead to propagate it to everyone; observers that care about these extra payloads can just check the appropriate place for additional data?

Re, duplication: I think the fact that you can implement it on your own and in few dozen lines of well-formatted code makes it less appealing from platform perspective. Also, if/once patterns of use emerge, we reserve the right to jump in and offer it as part of standard API? :)

@eliperelman
Copy link

@igrigorik I'd like to point out how we would like to use such a feature in Firefox OS for one of the use cases (there are more), and get your thoughts on it.

When we create performance marks, Gecko has a reference to the origin of the document that generated the mark. For example, if we launch our Clock app and create a mark, we get some output in adb logcat:

performance.mark('fullyLoaded');
I/PerformanceTiming( 6118): Performance Entry: clock.gaiamobile.org|mark|fullyLoaded|1074.739956|0.000000|1434771805380

In our home screen, we also create a performance mark, but have a convention that basically overrides the context of the mark. This lets fake our way to cross-page marks:

// In home screen
performance.mark('[email protected]');

Of course this is hacky. :) It would be preferred that this wasn't encoded in the mark name:

performance.mark('appLaunch', { context: 'clock.gaiamobile.org' });

There is much more information about the whys and hows surrounding this and I don't want to get deep into this here, but basically we are using conventions as a way to get to out-of-page marking, so maybe this is an indication we have something else missing.

@igrigorik
Copy link
Member

@eliperelman interesting. I'm not familiar with the guts of FFOS, so please bear with me... when you say "launch X app", what does that actually do? Is it a separate document, worker, ...?

It sounds like the underlying primitive you're after is a way to translate timestamps between different contexts? As in, you get a timestamp in A and you want to map it onto B's timeline? If so, have you checked our discussion in w3c/hr-time#6 (comment)? The plan is to add a new translateTime method.. which sounds like something you might be able to leverage.

@eliperelman
Copy link

@igrigorik when we launch applications, they are self-contained windows in their own process, similar to tabs with their own process. I haven't really thought about the communication mechanisms to allow mapping of these values in this way. I'll have to think through that some more.

@igrigorik
Copy link
Member

Are we OK with resolving this as a wontfix?

To recap, I believe the behavior we're after here is easy enough to polyfill (see #3 (comment)) and I don't believe there are any strong benefits in requiring that as a native API. In fact, as a first step, I'd like to see folks experiment with such an API on their own and report back with their findings; if there are gaps that can't be filled in via application code, then I think it would make sense to revisit this discussion once more.

/cc @plehegar @toddreifsteck

@eliperelman
Copy link

As much as I don't want to concede on this issue, I feel it's probably necessary until we can flesh out any root holes that the web isn't giving us. I'm fine with wontfixing this.

@igrigorik
Copy link
Member

@eliperelman great, thanks. @nicjansma does this sound reasonable to you as well?

@nicjansma
Copy link
Author

Yes, I haven't come up with any scenario that wouldn't work with a polyfill / 100% JS solution.

@igrigorik
Copy link
Member

Great, thanks guys. Closing, feel free to reopen if anything new comes up.

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

No branches or pull requests

4 participants