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

Browser performance issue on iterative property access #45

Open
matthieu-fesselier opened this issue Oct 28, 2019 · 66 comments
Open

Browser performance issue on iterative property access #45

matthieu-fesselier opened this issue Oct 28, 2019 · 66 comments
Assignees
Labels
bug Something isn't working

Comments

@matthieu-fesselier
Copy link

I face performances issues when accessing datas on a container. It makes all our apps not useable for now with LDFlex. For example, with the following code:

  await solid.data.context.extend(base_context)
  const container = solid.data["https://apiprod.happy-dev.fr/clients/"];
  console.time(container.toString())
  for await (const r of container.ldp_contains) {
    console.time(r.toString())
    console.log((await r.img).toString());
    console.timeEnd(r.toString())
  }
  console.timeEnd(container.toString())

It takes ~3000ms to display 70 times the img property of a resource.
For each resource, it takes between 10ms to 90ms to display its img.

Is there something we can do to improve this?

@RubenVerborgh
Copy link
Member

3s is long indeed. However, are we sure it is an LDflex problem? Because the above involves (independently of whether you are using LDflex or not) fetching 70 resources over HTTP. I suspect those are the source of the 10–90ms delay.

A solution would be to parallelize the for loop.

@matthieu-fesselier
Copy link
Author

When I inspect the network requests, as all the resources are in the 1rst graph, only one request to https://apiprod.happy-dev.fr/clients/ is made

@RubenVerborgh
Copy link
Member

I see; the img is local indeed. Will investigate!

@happy-dev
Copy link

Ah ah, cool!!!
We were all hoping you'd say that.
The team will celebrate that response :D

@happy-dev
Copy link

Hi @RubenVerborgh,

Any news here?

This one is a priority for us since it is turning our apps into lazy slugs :)
Don't hesitate to tell us if you think we can help.

@RubenVerborgh
Copy link
Member

Don't hesitate to tell us if you think we can help.

Any profiling or insights where time is being spent, would help me get this solved faster. Booked time for this early next week.

@matthieu-fesselier
Copy link
Author

I don't know if it helps but here are some observations:

  await solid.data.context.extend(base_context)
  const resource = solid.data["https://apiprod.happy-dev.fr/clients/1/"];
  console.time();
  await resource.name;
  console.timeEnd(); // first call, need to request server: ~150-200ms 

  console.time();
  await resource.img;
  console.timeEnd(); // no need to request server: ~10ms

  console.time();
  await resource['http://happy-dev.fr/owl/#img']; // with full path, same time to resolve: ~10ms
  console.timeEnd();

  // same observations with this syntax
  console.time();
  const name = await solid.data["https://apiprod.happy-dev.fr/clients/2/"].name;
  console.log(name.toString());
  console.timeEnd(); // ~200ms

  console.time();
  const img = await solid.data["https://apiprod.happy-dev.fr/clients/2/"].img;
  console.log(img.toString());
  console.timeEnd(); // ~10ms
  // and same without extending our context
  const res = solid.data["https://apiprod.happy-dev.fr/clients/3/"];
  console.time();
  console.log((await res['rdfs:label']).toString());
  console.timeEnd(); // ~200ms
  
  console.time();
  console.log((await res['http://happy-dev.fr/owl/#img']).toString());
  console.timeEnd(); // ~10ms

@RubenVerborgh
Copy link
Member

This is interesting indeed, looks like we're chasing some specific requests in particular. Thanks.

@RubenVerborgh RubenVerborgh added the bug Something isn't working label Nov 1, 2019
@RubenVerborgh RubenVerborgh self-assigned this Nov 1, 2019
@RubenVerborgh
Copy link
Member

When testing the "without extending our context" example, I get consistently good performance in Node.js 12.6.0:

https://apiprod.happy-dev.fr/clients/: 445.242ms
https://apiprod.happy-dev.fr/clients/1/: 2.918ms
https://apiprod.happy-dev.fr/clients/2/: 1.596ms
https://apiprod.happy-dev.fr/clients/3/: 1.518ms
https://apiprod.happy-dev.fr/clients/4/: 1.481ms
https://apiprod.happy-dev.fr/clients/5/: 1.806ms
https://apiprod.happy-dev.fr/clients/6/: 1.760ms
https://apiprod.happy-dev.fr/clients/7/: 1.465ms
https://apiprod.happy-dev.fr/clients/8/: 1.302ms
https://apiprod.happy-dev.fr/clients/9/: 1.230ms
https://apiprod.happy-dev.fr/clients/10/: 1.301ms
https://apiprod.happy-dev.fr/clients/11/: 1.234ms
https://apiprod.happy-dev.fr/clients/12/: 1.222ms
https://apiprod.happy-dev.fr/clients/13/: 1.556ms
https://apiprod.happy-dev.fr/clients/14/: 1.379ms
https://apiprod.happy-dev.fr/clients/15/: 3.331ms
https://apiprod.happy-dev.fr/clients/16/: 1.756ms
https://apiprod.happy-dev.fr/clients/17/: 1.573ms
https://apiprod.happy-dev.fr/clients/18/: 1.355ms
https://apiprod.happy-dev.fr/clients/19/: 1.262ms
https://apiprod.happy-dev.fr/clients/20/: 1.478ms
https://apiprod.happy-dev.fr/clients/21/: 1.408ms
https://apiprod.happy-dev.fr/clients/22/: 1.378ms
https://apiprod.happy-dev.fr/clients/23/: 1.483ms
https://apiprod.happy-dev.fr/clients/24/: 1.281ms
https://apiprod.happy-dev.fr/clients/25/: 1.314ms
https://apiprod.happy-dev.fr/clients/26/: 2.273ms
https://apiprod.happy-dev.fr/clients/27/: 1.299ms
https://apiprod.happy-dev.fr/clients/28/: 1.477ms
https://apiprod.happy-dev.fr/clients/29/: 1.282ms
https://apiprod.happy-dev.fr/clients/30/: 1.580ms
https://apiprod.happy-dev.fr/clients/31/: 1.331ms
https://apiprod.happy-dev.fr/clients/32/: 3.948ms
https://apiprod.happy-dev.fr/clients/33/: 1.317ms
https://apiprod.happy-dev.fr/clients/34/: 1.268ms
https://apiprod.happy-dev.fr/clients/35/: 1.332ms
https://apiprod.happy-dev.fr/clients/36/: 1.316ms
https://apiprod.happy-dev.fr/clients/37/: 1.244ms
https://apiprod.happy-dev.fr/clients/38/: 1.394ms
https://apiprod.happy-dev.fr/clients/39/: 1.330ms
https://apiprod.happy-dev.fr/clients/40/: 1.471ms
https://apiprod.happy-dev.fr/clients/41/: 1.430ms
https://apiprod.happy-dev.fr/clients/42/: 1.130ms
https://apiprod.happy-dev.fr/clients/43/: 1.132ms
https://apiprod.happy-dev.fr/clients/44/: 1.092ms
https://apiprod.happy-dev.fr/clients/46/: 1.167ms
https://apiprod.happy-dev.fr/clients/47/: 1.102ms
https://apiprod.happy-dev.fr/clients/48/: 1.127ms
https://apiprod.happy-dev.fr/clients/49/: 1.108ms
https://apiprod.happy-dev.fr/clients/50/: 1.078ms
https://apiprod.happy-dev.fr/clients/51/: 1.099ms
https://apiprod.happy-dev.fr/clients/52/: 1.130ms
https://apiprod.happy-dev.fr/clients/53/: 1.099ms
https://apiprod.happy-dev.fr/clients/54/: 1.086ms
https://apiprod.happy-dev.fr/clients/57/: 1.298ms
https://apiprod.happy-dev.fr/clients/58/: 1.237ms
https://apiprod.happy-dev.fr/clients/59/: 1.181ms
https://apiprod.happy-dev.fr/clients/61/: 1.307ms
https://apiprod.happy-dev.fr/clients/63/: 1.446ms
https://apiprod.happy-dev.fr/clients/64/: 2.788ms
https://apiprod.happy-dev.fr/clients/65/: 1.138ms
https://apiprod.happy-dev.fr/clients/66/: 1.084ms
https://apiprod.happy-dev.fr/clients/67/: 1.031ms
https://apiprod.happy-dev.fr/clients/68/: 1.433ms
https://apiprod.happy-dev.fr/clients/69/: 1.071ms
https://apiprod.happy-dev.fr/clients/70/: 0.975ms
https://apiprod.happy-dev.fr/clients/72/: 0.947ms
https://apiprod.happy-dev.fr/clients/73/: 0.937ms
https://apiprod.happy-dev.fr/clients/75/: 0.936ms
https://apiprod.happy-dev.fr/clients/76/: 1.142ms
https://apiprod.happy-dev.fr/clients/77/: 0.993ms
https://apiprod.happy-dev.fr/clients/78/: 1.033ms
https://apiprod.happy-dev.fr/clients/79/: 1.311ms
https://apiprod.happy-dev.fr/clients/: 445.242ms

So two questions:

  • On what platform did you measure?
  • Could I have your extended JSON-LD context (if the problem is there)?

@matthieu-fesselier
Copy link
Author

matthieu-fesselier commented Nov 1, 2019

I am testing in a browser (Chrome 78). Without extending our context, with this code:

  const container = solid.data["https://apiprod.happy-dev.fr/clients/"];
  console.time(container.toString())
  for await (const r of container.ldp_contains) {
    console.time(r.toString())
    await r['rdfs:label']
    console.timeEnd(r.toString())
  }
  console.timeEnd(container.toString())

I get different results than yours:

https://apiprod.happy-dev.fr/clients/: 1088.90087890625ms
https://apiprod.happy-dev.fr/clients/1/: 10.197998046875ms
https://apiprod.happy-dev.fr/clients/2/: 9.509033203125ms
https://apiprod.happy-dev.fr/clients/3/: 15.14794921875ms
https://apiprod.happy-dev.fr/clients/4/: 9.77783203125ms
https://apiprod.happy-dev.fr/clients/5/: 8.005126953125ms
https://apiprod.happy-dev.fr/clients/6/: 9.4130859375ms
https://apiprod.happy-dev.fr/clients/7/: 7.76416015625ms
https://apiprod.happy-dev.fr/clients/8/: 8.996826171875ms
https://apiprod.happy-dev.fr/clients/9/: 7.68896484375ms
https://apiprod.happy-dev.fr/clients/10/: 10.088134765625ms
https://apiprod.happy-dev.fr/clients/11/: 9.110107421875ms
https://apiprod.happy-dev.fr/clients/12/: 7.708984375ms
https://apiprod.happy-dev.fr/clients/13/: 9.901123046875ms
https://apiprod.happy-dev.fr/clients/14/: 8.379150390625ms
https://apiprod.happy-dev.fr/clients/15/: 8.369873046875ms
https://apiprod.happy-dev.fr/clients/16/: 12.80322265625ms
https://apiprod.happy-dev.fr/clients/17/: 20.765869140625ms
https://apiprod.happy-dev.fr/clients/18/: 9.837890625ms
https://apiprod.happy-dev.fr/clients/19/: 9.588134765625ms
https://apiprod.happy-dev.fr/clients/20/: 8.70068359375ms
https://apiprod.happy-dev.fr/clients/21/: 7.68505859375ms
https://apiprod.happy-dev.fr/clients/22/: 7.837646484375ms
https://apiprod.happy-dev.fr/clients/23/: 7.675048828125ms
https://apiprod.happy-dev.fr/clients/24/: 7.82080078125ms
https://apiprod.happy-dev.fr/clients/25/: 9.09814453125ms
https://apiprod.happy-dev.fr/clients/26/: 7.682861328125ms
https://apiprod.happy-dev.fr/clients/27/: 8.43994140625ms
https://apiprod.happy-dev.fr/clients/28/: 7.598876953125ms
https://apiprod.happy-dev.fr/clients/29/: 7.510986328125ms
https://apiprod.happy-dev.fr/clients/30/: 7.52392578125ms
https://apiprod.happy-dev.fr/clients/31/: 6.930908203125ms
https://apiprod.happy-dev.fr/clients/32/: 13.077880859375ms
https://apiprod.happy-dev.fr/clients/33/: 16.430908203125ms
https://apiprod.happy-dev.fr/clients/34/: 9.43603515625ms
https://apiprod.happy-dev.fr/clients/35/: 44.575927734375ms
https://apiprod.happy-dev.fr/clients/36/: 10.1259765625ms
https://apiprod.happy-dev.fr/clients/37/: 7.884033203125ms
https://apiprod.happy-dev.fr/clients/38/: 7.990966796875ms
https://apiprod.happy-dev.fr/clients/39/: 7.700927734375ms
https://apiprod.happy-dev.fr/clients/40/: 7.747802734375ms
https://apiprod.happy-dev.fr/clients/41/: 8.593017578125ms
https://apiprod.happy-dev.fr/clients/42/: 10.65673828125ms
https://apiprod.happy-dev.fr/clients/43/: 11.967041015625ms
https://apiprod.happy-dev.fr/clients/44/: 8.828125ms
https://apiprod.happy-dev.fr/clients/46/: 8.567138671875ms
https://apiprod.happy-dev.fr/clients/47/: 8.598876953125ms
https://apiprod.happy-dev.fr/clients/48/: 8.014892578125ms
https://apiprod.happy-dev.fr/clients/49/: 8.022216796875ms
https://apiprod.happy-dev.fr/clients/50/: 7.285888671875ms
https://apiprod.happy-dev.fr/clients/51/: 10.23974609375ms
https://apiprod.happy-dev.fr/clients/52/: 7.982177734375ms
https://apiprod.happy-dev.fr/clients/53/: 8.64990234375ms
https://apiprod.happy-dev.fr/clients/54/: 8.32080078125ms
https://apiprod.happy-dev.fr/clients/57/: 7.7568359375ms
https://apiprod.happy-dev.fr/clients/58/: 9.184814453125ms
https://apiprod.happy-dev.fr/clients/59/: 8.089111328125ms
https://apiprod.happy-dev.fr/clients/61/: 10.52490234375ms
https://apiprod.happy-dev.fr/clients/63/: 10.336669921875ms
https://apiprod.happy-dev.fr/clients/64/: 8.001953125ms
https://apiprod.happy-dev.fr/clients/65/: 8.064208984375ms
https://apiprod.happy-dev.fr/clients/66/: 7.955810546875ms
https://apiprod.happy-dev.fr/clients/67/: 8.31396484375ms
https://apiprod.happy-dev.fr/clients/68/: 7.802001953125ms
https://apiprod.happy-dev.fr/clients/69/: 9.5849609375ms
https://apiprod.happy-dev.fr/clients/70/: 10.0341796875ms
https://apiprod.happy-dev.fr/clients/72/: 8.09912109375ms
https://apiprod.happy-dev.fr/clients/73/: 10.044921875ms
https://apiprod.happy-dev.fr/clients/75/: 7.333984375ms
https://apiprod.happy-dev.fr/clients/76/: 8.4609375ms
https://apiprod.happy-dev.fr/clients/77/: 8.4951171875ms
https://apiprod.happy-dev.fr/clients/78/: 7.4658203125ms
https://apiprod.happy-dev.fr/clients/79/: 11.096923828125ms
https://apiprod.happy-dev.fr/clients/: 1088.90087890625ms

Here is the context I used:

const base_context = {
  '@vocab': 'http://happy-dev.fr/owl/#',
  rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
  rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
  ldp: 'http://www.w3.org/ns/ldp#',
  foaf: 'http://xmlns.com/foaf/0.1/',
  name: 'rdfs:label',
  acl: 'http://www.w3.org/ns/auth/acl#',
  permissions: 'acl:accessControl',
  mode: 'acl:mode',
  email: 'http://happy-dev.fr/owl/#email',
};

@RubenVerborgh
Copy link
Member

Thanks, will test on Chrome! Although it's the same V8 engine, so I wonder what goes wrong.

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Nov 1, 2019

Slower timings in Chrome and Firefox confirmed.

RubenVerborgh added a commit that referenced this issue Nov 1, 2019
@RubenVerborgh
Copy link
Member

Added comparative tests to the branch https://github.com/solid/query-ldflex/tree/test/45-performance. Run in node with node test.js; in browser with npm start demo.

I've traced the problem back to Comunica: it is the this._engine.query(sparql, { sources }) call in to Comunica in LDflex-Comunica that is slower in both Firefox and Chrome compared to Node.js. Assigning to Comunica people so they can trace on their end.

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Nov 1, 2019

My first suspect was transpiling: perhaps the transpiled version of asynchronous iteration is slower than the native version. However, the same transpiled version is used for browsers and Node.js (I expect this to be the case all the way down Comunica as well). So I suspect the problem is rather in a shim.

@happy-dev
Copy link

Thank @RubenVerborgh for your time here.

@rubensworks, @joachimvh: Let us know if we can help you finding out why the query function is being slow in browsers. Don't we polyfill anything in it?

@happy-dev
Copy link

@rubensworks, @joachimvh: Any good news you would like to share with us? :-)

@RubenVerborgh
Copy link
Member

Let us know if we can help you finding out why the query function is being slow in browsers.

I think it is a shim or polyfill indeed. If you could identify the different code being called in command-line or browser, that would definitely help. Once possible example could be doing a loop of 1000 await solid.data["https://apiprod.happy-dev.fr/clients/2/"].img with a profiler, and comparing the results.

@RubenVerborgh
Copy link
Member

I just did the above; I see a quite some time spent in setImmediate. Perhaps we are using a non-optimal shim for that one.

@happy-dev
Copy link

@matthieu-fesselier: If you have any further insight that might help...

@happy-dev
Copy link

Indeed, the function is not supported by both Chrome and Firefox : https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate

I'll dig deeper tomorrow afternoon.

@RubenVerborgh
Copy link
Member

@happy-dev

What options do we have to get this issue fixed within days?

I have sketched a possible solution here: LDflex/LDflex#44

While this does not address the root cause (= queries have an overhead in browsers), it will reduce the number of queries overall. We have not hit the threshold of a problematic number of queries in Node.js yet (I think 145ms for 180 SPARQL queries is quite acceptable), but we will eventually hit that point if more queries are needed (as do similar solutions like ActiveRecord).

In parallel, we can look at what is slowing down browsers.

RubenVerborgh added a commit that referenced this issue Nov 6, 2019
@RubenVerborgh
Copy link
Member

RubenVerborgh commented Nov 6, 2019

Testing progress: the branch https://github.com/solid/query-ldflex/tree/test/45-performance now has a ./run-test script that executes the same code on the Node version and the browser version.
The timings are currently:

  • 165ms with the Node version in Node
  • 2300ms with the browser version in Node
  • 320ms with the browser version in Node when disabling the setImmediate shim
  • 590ms with the browser version in Chrome
  • 500ms with the browser version in Firefox

So we can test things without a browser now.

@happy-dev
Copy link

happy-dev commented Nov 6, 2019

Don't get me wrong, this issue is important to me.

I can tell, and that is totally clear to me, even though you are right to say it, things are often better understood when said :-)

Help us find sustainable funding for Comunica, so we can hire a dedicated developer.

I'd be happy to dig into that, even though that won't help us here but I am totally up for catching that ball

We reach back to you tomorrow regarding our progress towards a short term solution.

@RubenVerborgh
Copy link
Member

In any case, we're definitely spending way too much time on SPARQL parsing (RubenVerborgh/SPARQL.js#94). It's a major contributor to time.

@RubenVerborgh

This comment has been minimized.

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Nov 6, 2019

I can confirm that the problem is in the browser-supplied version of stream, which is stream-browserify. When swapping it out for the native Node.js stream implementation, the performance between the browser and Node.js versions becomes identical.

@RubenVerborgh
Copy link
Member

And the root issue is likely this one: defunctzombie/node-process#86

@RubenVerborgh
Copy link
Member

When fixing process.nextTick (as root cause), I obtain identical performance when feeding Node.js the regular source code and the compiled browser version.

Unfortunately, this performance does not translate directly to the browser. It seems that the browser build still contains code that executes differently on Node. So we need to dig deeper.

Yet based on the above, I have already made some performance improvements. Please check out how this branch is working for you: https://github.com/solid/query-ldflex/tree/fix/browser-performance

@rubensworks
Copy link
Contributor

rubensworks commented Nov 8, 2019

In any case, we're definitely spending way too much time on SPARQL parsing (RubenVerborgh/SPARQL.js#94). It's a major contributor to time.

Instead of passing SPARQL queries to Comunica, LDflex could also just pass SPARQL algebra to Comunica directly. This would avoid the parsing overhead. (This is also how GraphQL-LD does it)

@sylvainlb
Copy link

Thanks Ruben for all this study. We're working on a workaround for now on our side. But it's a temporary measure, and as soon as we're done with it, we're gonna have to find a more definitive solution.

@RubenVerborgh
Copy link
Member

Definitely, and we know where to look already.

@RubenVerborgh
Copy link
Member

@sylvainlb @matthieu-fesselier @happy-dev preload is implemented on the latest LDflex master (LDflex/LDflex#44). It makes repeated accesses go faster. (However, I still find browser query overhead to be significant: comunica/comunica#561)

@matthieu-fesselier
Copy link
Author

I tested it and it works as expected. It does not make the first call faster, but the next ones are

@RubenVerborgh
Copy link
Member

Thanks so much for testing this. Will close this now, while we follow up in Comunica to make queries as a whole faster in browsers. We now have several pointers to look at the performance differences.

@sylvainlb
Copy link

Thanks Ruben for all these efforts. We're still in the process of closing the crisis on our side, but I'll get back to you once we're done to see how we can proceed to integrate LDFlex in our work.

Thanks!

@matthieu-fesselier
Copy link
Author

Hello @RubenVerborgh @rubensworks !

I follow up here as it seems to be the most appropriate issue related to performances. I investigated a bit more the performances with the last version of query-ldflex. (not sure all the dependencies were updated as they should be, maybe you can confirm?)

Here is a real use case of an app made with Startin'blox. On load time:

  • We load ~ 150 different resources used in ~400 components (most of the time, 1 component is responsible of 1 node only)
  • We access ~ 1.2k properties on these resources. (~700 different properties)

I made some tests with LDFlex in replacement to our store. It does not loads all the resources mentioned above, it needed more work to make all the components work. However, here are some results:

  • On load time, we first make 15 calls to solid.data[something]the page freezes for 5 to 10 seconds (@RubenVerborgh you told us about this on our last call, I confirm it happens also with us).
  • Then, we make some iterations on containers → it seems pretty fast
  • Then, we make ~40 calls to solid.data[something]freezes the page for 2-3 seconds
  • Then we access some properties on the resources → it seems a bit slow (~8 to 10ms per property).
    On a list of 600 resources, when we need to show 2 properties of each resource, we have 600 * 10ms * 2 = 12s.
    I think that these access in the loops make the whole app quite slow.

Here is a small test I made with our data:

  <script src="solid-auth-client.bundle.js"></script>
  <script src="solid-query-ldflex.bundle.js"></script>
	<script>
  document.addEventListener('DOMContentLoaded', async () => {
    const data = solid.data['https://api.community.hubl.world/skills/'];
    for await (const s of data['ldp:contains']) {
      const id = s.value;
      console.time(id)
      await s['rdfs:label'].value;
      await s['type'].value;
      console.timeEnd(id)
    }
  });
  </script>

I tested with distant data (https://api.community.hubl.world/skills/) and the same data in a local jsonld file, with the same results.

Each time shows between 15 and 20ms. As they are all executed sequentially, it takes around 12s to have the whole list loaded.

I hope it helps, don't hesitate to reach back if you need more informations about our tests/uses cases!

@RubenVerborgh
Copy link
Member

Thanks @matthieu-fesselier, this is a very interesting case, which we will analyze in detail.

Quick thoughts:

  • the sequentiality will likely have to be tackled with parallelization
  • the freezing, I think we will need to tackle by making every 1 out of 100 queueMicrotask calls a setTimeout call instead (good old DoEvents)
  • In general, the await pattern seems to encourage actively waiting for things, whereas we probably want to dispatch the (unevaluated) LDflex expressions to other functions/components as much as possible, so they all await in their own time.

@RubenVerborgh RubenVerborgh reopened this Jun 18, 2020
@RubenVerborgh
Copy link
Member

Reminder to self: the above remarks pertain to this hack rather than the queueMicrotask-based AsyncIterator implementation.

@matthieu-fesselier
Copy link
Author

A more precise example which illustrates what I said before:

<pre id="test"></pre>
<script>
  // for freeze test
  setInterval(() => {
    document.getElementById('test').textContent = Math.random();
  }, 200);

  document.addEventListener('DOMContentLoaded', async () => {
    const skills = 'https://api.community.hubl.world/skills/';
    const context = {
      '@vocab': 'http://happy-dev.fr/owl/#',
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      ldp: 'http://www.w3.org/ns/ldp#',
      foaf: 'http://xmlns.com/foaf/0.1/',
      name: 'rdfs:label',
      acl: 'http://www.w3.org/ns/auth/acl#',
      permissions: 'acl:accessControl',
      mode: 'acl:mode',
      geo: "http://www.w3.org/2003/01/geo/wgs84_pos#",
      lat: "geo:lat",
      lng: "geo:long"
    };

    await solid.data.context.extend(context);
    const data = solid.data[skills];

    console.time('iteration')
    for await (const s of data['http://www.w3.org/ns/ldp#contains']) { }
    console.timeEnd('iteration')

    console.time('iteration + value')
    for await (const s of data['http://www.w3.org/ns/ldp#contains']) {
      const id = s.value;
    }
    console.timeEnd('iteration + value')

    console.time('iteration + 1 prop')
    for await (const s of data['http://www.w3.org/ns/ldp#contains']) {
      await s['rdfs:label'].value;
    }
    console.timeEnd('iteration + 1 prop')

    console.time('iteration + 2 props')
    for await (const s of data['http://www.w3.org/ns/ldp#contains']) {
      await s['rdfs:label'].value;
      await s['type'].value;
    }
    console.timeEnd('iteration + 2 props')
  });
</script>

With this, I can see that:

  • iteration ~5400ms -> first iteration on the container, no property access
  • iteration + value ~260ms -> second time, even if s.value is accessed, it's fast
  • iteration + 1 prop ~5400ms -> when a property is accessed, it's slow again
  • iteration + 2 prop ~10800ms -> with a new property access, it 2x slower
  • during all the process (~20s), the setInterval function which should show a random number every 200ms in the page freezes. I'm not sure if it can be compared to what happens in real life, but it seems very similar

@RubenVerborgh
Copy link
Member

the freezing, I think we will need to tackle by making every 1 out of 100 queueMicrotask calls a setTimeout call instead (good old DoEvents)

FYI we have this now here: RubenVerborgh/AsyncIterator@c0d8cac#diff-1a12957b96162e114d61ede68b100ab3R13-R21

@matthieu-fesselier
Copy link
Author

Following up with the tests I made just above with the new version of AsyncIterator, I am facing a bug, which might be related to #71 .
It seems that if I loop twice on the same container, the second time, it never goes inside the loop:

document.addEventListener('DOMContentLoaded', async () => {
        const skills = 'https://api.community.hubl.world/skills/';
        const data = solid.data[skills];
        // 1rst loop
        for await (const s of data['http://www.w3.org/ns/ldp#contains']) { }
        console.log('passes here...');

        // 2nd loop
        for await (const s of data['http://www.w3.org/ns/ldp#contains']) {
          console.log('but not here');
          const id = s.value;
        }
        console.log('and here neither');
});

Did I miss something?

@RubenVerborgh
Copy link
Member

I suspect #71 indeed, we're investigating it.

@matthieu-fesselier
Copy link
Author

matthieu-fesselier commented Feb 25, 2021

For reference, if it helps, I runned some additionnal tests based on the code I showed here, and here are the results:

instructions LDFlex (1) LDFlex + Turtle file (2) LDFlex + rdflib.js
iteration 7600ms 495ms 3350ms
iteration + value 315ms 320ms 45ms
iteration + 1 prop 3100ms 3150ms 4700ms
iteration + 2 props 6800ms 7050ms 9000ms

(1) I used the master branch
(2) I converted the skills JSONLD document in 1 local turtle file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants