Re: Question about HTTP 2.0 priority

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 2/10/2014 9:07 p.m., Chad Austin wrote:
> Thank you for your explanation, Amos.  Thanks especially for
> clarifying that each assets is its own stream.
> 
> You're right that I can use dependencies to implement
> statically-known priorities.  Let me see if it's possible to do the
> same with a more complicated and dynamic (and realistic) example:
> 
> Let's imagine loading a 3D scene.  It contains one room object, 3
> avatar objects (including your own), and 5 pieces of furniture.
> 
> To load an object, first a JSON "object description" must be
> downloaded. This object description roughly corresponds to the HTML
> on a web page; it contains links to the remaining assets: meshes,
> thumbnail textures, and high-res textures.  Once the object
> description JSON is downloaded, all of the remaining assets are
> requested in parallel.  The object will not be visible in WebGL
> until the meshes and low-res textures are downloaded. Afterwards,
> the high-res textures are placed in the scene when they finish 
> downloading (which could be many seconds or even minutes in the
> future, as a scene typically contains 50 MB of high-resolution
> texture data.)
> 
> Calculating priority for a request takes three factors into
> consideration: which object the request is for, the type of the
> asset being loaded, and for some objects the distance from the
> camera, per the following table:
> 
> 
> 
> Room, My Avatar
> 
> Furniture, Other Avatars
> 
> Object Descriptions
> 
> 290
> 
> 280 - DistanceFromCamera
> 
> Meshes, Lo-res Textures
> 
> 190
> 
> 180 - DistanceFromCamera
> 
> High-res Textures
> 
> 90
> 
> 80 - DistanceFromCamera
> 
> 
> The loadObject algorithm looks something like the following
> JavaScript. Load requests happen in some arbitrary order on the web
> page (as people come and go from the 3D scene.)  The web page knows
> how to calculate the priorityModifier given the above algorithm.
> 
> function loadObject(url, priorityModifier) { var object = new
> Object3D;
> 
> // first we need to load the object description JSON return
> request(url, 200 + priorityModifier)
> 
> // parse it into an object description 
> .then(parseObjectDescription)
> 
> .then(function(desc) { // optimistically begin fetching all
> low-priority, high-res textures 
> requestHighResTextures(desc.highResTextures + priorityModifier);
> 
> // then, once the meshes and low-res textures loaded, place the 
> object in the scene return Promise.all([ requestMeshes(desc.meshes,
> 190 + priorityModifier), requestTextures(desc.lowResTextures, 190
> + priorityModifier), ]).then(function() { 
> object.makeVisibleInScene(); }); }); }
> 
> function calledEverySecond() { // go through all pending object
> loads for furniture and other avatars // adjust priorities based on
> distance from camera }
> 
> // call loadObject once for the room, once for your avatar, a few
> times for the other avatars, and a few times for the furniture //
> the sequence of loadObject calls is not necessarily known in
> advance
> 
> 
> That was a long example, but I hope it demonstrates why it's not
> entirely obvious how to build an HTTP/2 dependency graph from what
> are conceptually just priorities.
> 
> This gets especially hairy when a bunch of low-priority requests
> depend on a request that finishes...  if I understand the spec
> correctly, that will implicitly bump up the priority of the
> low-priority requests, which would be undesirable here.
> Low-priority needs to STAY low-priority, even as higher-priority
> (aka dependent) requests finish.

Nod. Its a bit hairy, yes.

The PRIORITY frame can help. I would have the requestHighResTextures()
maintain a list of pending the low-priority assets, which are
prioritized as a sequential dependency chain. With the first stream of
that chain being bumped around by PRIORITY to depend on lowest of the
hi-priority set if/when new hi-priority are added.

> 
> Why does HTTP/2 have such a complicated system for priority rather
> than SPDY's simple priority integer?  It seems a simple priority
> value would make everything so much simpler for both clients and
> servers.

Complication is an emergent property of design-by-commitee combining
both dependency and weighting. For simplicity you can ignore the
weighting, but when you get down to fine-tuning priorities it comes in
handy.

Given you have a table of values to work from, you could map those
into HTTP/2 weight values and have all your high-priority types set
with default dependency. That places them all as highest priority but
bandwdth weighted. The low-priority set as I mention above in a
sequential dependency chain whih is bumped "down" to depend on
whatever the outstanding hi-priority object(s) are.


Remember this is all just a preference, if there is spare bandwidth
and data are available for any asset it can and probably will be
delivered earlier than indicated by the priority order.
> 
> Thanks again.  I truly appreciate that you took the time to
> understand my use case and respond as such.
> 
> Chad
> 
> 
> On Wed, Oct 1, 2014 at 11:01 PM, Amos Jeffries
> <squid3@treenet.co.nz> wrote:
> 
> On 2/10/2014 2:12 p.m., Chad Austin wrote:
>>>> Hi,
>>>> 
>>>> I am reading the HTTP 2.0 draft, and I wonder whether HTTP
>>>> 2.0 supports implementing simple stream priorities like SPDY
>>>> does.
>>>> 
>>>> Our use case is documented in detail at
>>>> 
> http://chadaustin.me/2014/08/web-platform-limitations-xmlhttprequest-priority/
>>>>
>>>>
>
> 
, but I will summarize here.
>>>> 
>>>> We have a whole pile of 3D assets that we need to retrieve
>>>> from various URLs and load into WebGL.  Some of them are
>>>> higher-priority than others. None of them depend on any
>>>> other.  For example, we may want to prioritize resources
>>>> closer to the camera.  We definitely want to prioritize
>>>> meshes and low-resolution textures over high-resolution
>>>> textures and animation files.
>>>> 
>>>> Ideally, our application would immediately issue ALL requests
>>>> and let the browser's network stack (and HTTP/SPDY/HTTP2
>>>> backend) efficiently utilize the socket(s) and bandwidth to
>>>> transfer high-priority assets before low-priority assets.
>>>> However, if there is available bandwidth, we would benefit
>>>> from receiving low-priority assets in the meantime.
>>>> 
>>>> We would benefit from a large number of priority bits, but
>>>> could make it work with as low as 3 bits.  (2 bits would be
>>>> too few.)
>>>> 
>>>> How do I map that use case to HTTP 2.0's dependency graph?
>>>> At first blush, it seems hard: I'd have to define a stream
>>>> per priority level, and set dependencies such that all
>>>> low-priority streams depend on high-priority streams?  And if
>>>> a high-priority stream finishes, then reset the dependency to
>>>> another high-priority stream?
>>>> 
> 
> Not hard at all. Just reverse your thinking about priority levels.
> 
> You have to create a stream per asset in HTTP/2. The priority for
> the stream is assigned based on which *single* asset that stream is
> being used to deliver.
> 
> For assiging HTTP/2 priorities to your assets just work out the 
> dependency tree they naturally have anyway. Then walk down it 
> assigning the root asset the highest priority and each successive 
> level gets assigned a dependency on the asset/stream above it in
> the tree.
> 
> If the drawing dependency is something like: map/mesh -> objects ->
> skeletons -> low-res texture -> high-res texture
> 
> The HTTP/2 fetch dependency would be: map-/mesh <- objects <-
> skeletons <-low-res <- high-res
> 
> eg. - everything depends on the map/mesh finishing first. - object
> descriptions need to finish next, - followed by skeletons as the
> object they are for finishes, - followed by low-res textures once
> skeleton+object are finished, - high-res texture for a construct
> only required after all the previous bits are in.
> 
> When there is multiple (say 20) high-priority objects/skeletons 
> depending on a single low-res texture it is up to you whether you
> make a dependency of the low-res texture on the 1st objects stream
> ID or the 20th objects. If priority is obeyed, depending on the
> first object will allow that and later received objects to a bit
> render earlier incrementally, depending on the last one will make
> them all wait for complete data, but then render as a batch.
> 
> HTTP/2 explicitly makes priority optional, so it helps your
> download performance if the requests are ordered in a similar way
> to how you want them prioritized ("by group" as it were). That way
> even a naive intermediary which ignores priority is likely to
> server the most-wanted assets first due purely to their stream ID
> numbers being first.
> 
> Amos
> 
>> 
>> 
> 
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)

iQEcBAEBAgAGBQJULRW6AAoJELJo5wb/XPRjFMgH/3J0C4klXronIszBvvnCkYDU
prIleZAqJfkMyM6/HVeBXf9+4oMkaxleZDmJYo8496Phh6BWbBboRsRW0+/pwrtK
YGAnNg0NrHScxJRBDCZR75ENPEIPBdemKMPpBQwWsS7mFYrQR2GCeR+CXTCSeKma
AyBaqMtwNfzHqBvz4cfNWqyE/+1wU12h9Wg1XndeTJo/Pi3R5BMp08LwnKjhJ/QY
h1tw6f71xLZDU0yifj/J44nCq3KkCcMMSznRuB8VhkftuMgc5kOYQWr5r/d7N1V8
NNmiDEm7a/j1y2+7JeUzDeB4MjAFXvA8Zf5x8obQQjQJI7UJ/yPujsJDK4FaviQ=
=5k/P
-----END PGP SIGNATURE-----

Received on Thursday, 2 October 2014 09:07:45 UTC