Hi! We are working on app targeting very low end devices, 1gb of ram, 4 cores CPU with 1.4GHz MAX clock frequency.
We noticed useQuery hooks add tens of ms to each component calling it, we were also using apollo-persisted-cache, removing it boosted first render time by HUNDREDS of ms in heavy components.
Now I know I will get comments about nomralizing cache etc., but we don’t even have that much entries, on home screen it’s like this
To verify if the issue is in cache, we must completely get rid of it, but there doesn’t seem to be such option, how can we achieve that?
I’ve tried this How to disable cache in apollo-link or apollo-client? - Stack Overflow but doesn’t seem to work in our case, data is undefined and we also use newer version of apollo client (3.11.10)
You would have to apply no-cache fetch policies everywhere, but honestly that would just lead to many more network requests and probably slow down you application even more.
It wouldn’t avoid the work of parsing your response, so I don’t think it would help you too much.
Did you try to capture profiles and analyze those?
The cache likely has no measurable impact on render time here
The caches you see above are memoization caches to prevent recalculation of known result. They save you CPU time, but have nothing to do with “data stored in the cache”. They are the used cache sizes of memoized functions, and if you were to artificially decrease these numbers, your app would become a lot slower
I’m not sure what exact issue is reported in that StackOverflow thread, but even if you don’t write to the cache, the cache is required to transform data into the right shape, you cannot skip that part. But that doesn’t mean anything is stored in it.
Again, have you done profiling? Right now it seems that you are set on something being the reason of a performance problem without having done any measurements actually pointing to that specific part.
“Cache” here is in fact Persisted Cache, 10 samples for each (averaged), sorry cut label short when generating.
Now given that, I want to verify if regular inMemoryCache would be the root cause for other bottlenecks, so I am not set on that being an issue, I am set on checking if that is an issue, and your response to no.3 somehow confirms it? What does it mean Apollo transforms data to “right shape”? I described explicity in query what the right shape should be no?
If maybe taking the problem for other side would help
calling useQuery adds ~50ms to render time of GeneralScreen. I removed whole displayed UI, it’s esssentialy
const {} = useQuery()
return null
And I want to find out why
EDIT: Brought everything down to cache at this point, no extra links, no extra plugins, pure client with inMemoryCache and ‘no-cache’ set globally, with no inline cache policies
Okay, let’s step back a bit: you’re measuring the time your application needs in total here - that helps a bit, but is very hit-and-miss to pinpoint things.
I’m suggesting a Profile:
It will show you which function was called how often and how much time was spent in each function.
What does it mean Apollo transforms data to “right shape”? I described explicity in query what the right shape should be no?
GraphQL queries can be very complicated, and not always will the shape returned by the server be the shape you end up with in your component. That’s influenced by a lot of stuff like fragments, data masking, local fields, etc.
Those might all seem like edge cases to you, but AC cannot know if they do or don’t apply in your case and skip everything blindly - is has to check one box after the next, even if in the end it looks the same to you.
Brought everything down to cache at this point, no extra links, no extra plugins, pure client with inMemoryCache and ‘no-cache’ set globally, with no inline cache policies
That still leaves a lot of different things: the hooks might be slow, Apollo Client itself might be slow, yes, the cache might be slow, React rendering using useSyncExternalStore, observables etc. There are tons of moving parts. You maybe can opt out of some, maybe not from others. We’ll have to see.
Please record a profile so we have something to start from.
@lenz what exactly would be helpful for you? It’s clear it gets super clogged but I can’t really tell what the culprit can be here (whether it’s apollo’s cache or what)
Here is the exact same action without calling useQuery hook if it’s worth anything, textbook (edit: alright that was exagaraiton, but you get the point ) rendering
Hmm, we don’t have any influence on the native thread - AC is purely JS . I would guess that you see here is the native activity of React rendering 3 times, but every render will probably look like that.
What would really be interesting would be the JS thread.
Hard to read anything in there
Could you maybe mail me the recording to lenz@apollographql.com ?
No promises that I find something actionable, but I can at least take a look.
That explains why this looks unfamiliar - this is still a Java-only profile. What’s labelled as “js” here is the Java side of the JS bridge, but doesn’t actually show the JS work.
I did a video and guide on how to record a JS profile here, maybe that helps? It might be outdated by now, though, so take it with a grain of salt: GitHub - apollographql/rn-apollo-client-testbed
Sampling option is not visible for me, I was able to get the stack trace using Perfetto, but to be honest now I feel like I understand even less of it
Since I was profiling components render time, it was done in DEV mode, I guess it’s very much possible turning dev mode off did help ApolloClient, maybe this 50ms was not that important after all.