This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Record memory usages after each notification
ClosedPublic

Authored by kadircet on Sep 28 2020, 7:33 AM.

Diff Detail

Event Timeline

kadircet created this revision.Sep 28 2020, 7:33 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 28 2020, 7:33 AM
kadircet requested review of this revision.Sep 28 2020, 7:33 AM
kadircet updated this revision to Diff 296696.Oct 7 2020, 8:43 AM
  • Rebase and add tests for ClangdLSPServer
sammccall accepted this revision.Oct 7 2020, 9:41 AM
sammccall added inline comments.
clang-tools-extra/clangd/ClangdLSPServer.cpp
171

this change is a bit puzzling - makes it look like there are some cases where we specifically want/don't want to record. why?

172

on the flip side processing cancellations as fast as possible seems like it might be important.

Maybe just move the recording of memory usage to the happy case? (Notification that we have a handler for, after the handler).

179

after each notification?

181

maybe move this into a tiny function? It's self-contained, a bit distracting from the fairly important core logic here, and we may well want to do it conditionally or in more/different places in future.

184

(Sorry, I suspect we discussed this and I forgot)
Is there a reason at this point to put knowledge of the core metric in trace:: rather than define it here locally in ClangdLSPServer?

This revision is now accepted and ready to land.Oct 7 2020, 9:41 AM

this is at least going to take some important locks, hopefully only briefly.

We should watch the timing here carefully and consider guarding it - apart from the minimum time interval we discussed, we could have a check whether metric tracing is actually enabled in a meaningful way.

kadircet updated this revision to Diff 296955.Oct 8 2020, 6:45 AM
kadircet marked 4 inline comments as done.
  • Address comments
kadircet requested review of this revision.Oct 8 2020, 6:45 AM

Bad news, I was testing this with remote-index, hence background-index was turned off. Unfortunately traversing all of the slabs in FileSymbols takes quite a while in this case (~15ms for LLVM).

I don't think it is feasible to do this on every notification now, as this implies an extra 15ms latency for interactive requests like code completion/signature help due to the delay between didChange notification and codeCompletion request.

We should watch the timing here carefully and consider guarding it - apart from the minimum time interval we discussed, we could have a check whether metric tracing is actually enabled in a meaningful way.

I've also added early exit for non-tracing case. But I think we should still change this to be periodic or once every N calls. WDYT?

clang-tools-extra/clangd/ClangdLSPServer.cpp
171

it was to ensure we have a ClangdServer instance we can query for memory usage.

will revert as moving profiling into happy case makes it obselete.

184

(Sorry, I suspect we discussed this and I forgot)

Not really.

Is there a reason at this point to put knowledge of the core metric in trace:: rather than define it here locally in ClangdLSPServer?

ClangdLSPServer didnt feel like the appropriate place for that logic. Moreover other embedders of ClangdServer could benefit from traversal logic if it is defined in a lower level than ClangdLSPServer.

Bad news, I was testing this with remote-index, hence background-index was turned off. Unfortunately traversing all of the slabs in FileSymbols takes quite a while in this case (~15ms for LLVM).

I don't think it is feasible to do this on every notification now, as this implies an extra 15ms latency for interactive requests like code completion/signature help due to the delay between didChange notification and codeCompletion request.

Yeah, 15ms is a lot.
Staring at the code, I think this is our unfortunate index allocation strategy: for each source file in the project, we have one slab allocator for symbols, one for refs, one for relations...
The factor of 3 is sad but the factor of 10000 is what's killing us :-)

So we should fix that someday (DBMS?) but for now, let's back off to measuring once every several minutes.

The main problem I see is that we're almost guaranteed to be "unlucky" with the sample that way.
e.g. delay = 5 min. On startup there's some notification (initialized? didOpen?) that happens before any of the serious allocation and resets the counter.
So we won't have a realistic memory usage until we hit the 5 minute mark and profile again. If many sessions are <5min then our averages are going to be way off.

I can't think of a notification that is ubiquitous but only fires after serious work has happened. (Well, publishDiagnostics, but that goes in the wrong direction and so runs on the wrong thread).

What about something like a 5 minute throttle, but have ClangdLSPServer's constructor set the timestamp to now+1 minute? (Without profiling)

clang-tools-extra/clangd/ClangdLSPServer.cpp
153

I was about to complain that this doesn't work, but it actually does...

This wasn't the intended design of trace/span :-(
The idea was that Args would be null if the tracer dynamically wasn't interested in event details (e.g. an implementation like CSVMetricsTracer that doesn't record event payloads, or a sampling tracer).
In this case !Args would have false positives.

Do you mind adding an explicit trace::enabled() method to Trace.h instead, to be more explicit? I'd like to fix the Trace api.
(Else leave as-is and I can do this as a followup)

184

(Sorry, I guess D88413 was really the place for this discussion)

ClangdLSPServer didnt feel like the appropriate place for that logic.

To me, putting this in ClangdLSPServer feels like "this isn't part of the central mission here, it could be split out for coherence/reuse".
Whereas putting it in support/Trace feels like "this is a layering violation".

other embedders of ClangdServer could benefit from traversal logic

If exporting memorytree->metric with the path as the label is something we want to reuse, that could be a function in MemoryTree.h (taking the metric as parameter) or we can include the generic traversal function you proposed earlier. Even though they're both in Support, layering MemoryTree above Tracer seems more appropriate than the other way around.
My instinct is this is premature generalization and having a traversal in each embedder is fine, though.

kadircet updated this revision to Diff 297173.Oct 9 2020, 3:30 AM
kadircet marked 2 inline comments as done.
  • Implement periodic profiling

What about something like a 5 minute throttle, but have ClangdLSPServer's constructor set the timestamp to now+1 minute? (Without profiling)

SGTM. Note that this means we can't easily test this in LSP layer anymore. (We've got couple of components depending on time, maybe it is time we have a "mock" clock?)

clang-tools-extra/clangd/ClangdLSPServer.cpp
184

If exporting memorytree->metric with the path as the label is something we want to reuse, that could be a function in MemoryTree.h (taking the metric as parameter) or we can include the generic traversal function you proposed earlier. Even though they're both in Support, layering MemoryTree above Tracer seems more appropriate than the other way around.

Added a record member to MemoryTree in D88413.

sammccall added inline comments.Oct 9 2020, 4:01 AM
clang-tools-extra/clangd/ClangdLSPServer.cpp
1242

ClangdLSPServer does own things other than ClangdServer (e.g. the CDB), though we don't yet profile them.
Does it make sense to split this into ClangdLSPServer::profile (with the usual signature, and maybe public?) and ClangdLSPServer::maybeExportMemoryProfile()?

1242

Detailed is always false, drop the parameter? This can't be reused by code wanting to e.g. service a code action anyway.

1432

As written this isn't clearly true or false (what exactly is "startup"?)
Maybe just "Delay first profile until we've finished warming up"?

clang-tools-extra/clangd/ClangdLSPServer.h
173

or NextProfileTime? (to avoid the negation)

kadircet updated this revision to Diff 297565.Oct 12 2020, 5:29 AM
kadircet marked 5 inline comments as done.
  • Separate profiling and exporting into 2 functions
  • Rebase
sammccall accepted this revision.Oct 12 2020, 6:13 AM
sammccall added inline comments.
clang-tools-extra/clangd/ClangdLSPServer.h
72

drop the no-op part?

This revision is now accepted and ready to land.Oct 12 2020, 6:13 AM
kadircet updated this revision to Diff 297568.Oct 12 2020, 6:25 AM
kadircet marked an inline comment as done.
  • Update stale comment
This revision was landed with ongoing or failed builds.Oct 12 2020, 6:27 AM
This revision was automatically updated to reflect the committed changes.