clang: Create preamble only on second parse
Needs RevisionPublic

Authored by aaronpuchert on Jan 26 2019, 3:33 PM.

Details

Reviewers
mwolff
brauch
rjvbb
Group Reviewers
KDevelop
Summary

Instead of creating preambles for all files in a project, we only create
them when a translation unit is parsed for a second time, usually
because it's edited. The serialization of the preamble takes time, and
probably doesn't make sense when we throwing it away soon after without
using it again.

Test Plan

The initial parsing of a project doesn't create any preamble files
anymore, but they appear when files are edited.

Diff Detail

Repository
R32 KDevelop
Branch
build-preamble-on-reparse
Lint
No Linters Available
Unit
No Unit Test Coverage
Build Status
Buildable 7553
Build 7571: arc lint + arc unit
aaronpuchert created this revision.Jan 26 2019, 3:33 PM
Restricted Application added a project: KDevelop. · View Herald TranscriptJan 26 2019, 3:33 PM
aaronpuchert requested review of this revision.Jan 26 2019, 3:33 PM
rjvbb added a subscriber: rjvbb.EditedJan 26 2019, 10:36 PM

It'd be interesting to have an estimate of how much faster this makes that initial parse.

EDIT: informal estimate: about 10% on a project of some 250 files many of which in ObjC++ (2 threads allowed for the bg. parser). This is when triggering a full reparse in an already opened session configured not to be parsed on import.
The gain may be a bit higher when multiple projects are being imported and parsed at the same time.

rjvbb accepted this revision.Jan 27 2019, 2:16 PM

LGTM.

In case someone thinks that creating the pch file when you open a file causes a noticeable lag during the opening process: if so this would also be the case when configuring KDevelop not to parse the entire project on import. I use that mode all the time and never noticed any such lag.

This revision is now accepted and ready to land.Jan 27 2019, 2:16 PM
rjvbb added a comment.Jan 28 2019, 9:54 AM

Replying to a remark by Milian on D17289 where this idea came up:

we use CXTranslationUnit_CreatePreambleOnFirstParse to get code completion results fast. otherwise the first code completion request would create the preamble, which felt much worse

Felt or has this been quantified - and if so are those numbers still representative?
I'm guessing that I should get that same "worse feeling" with my habit of not parsing an entire project when opening it. I never had that feeling, having to wait the additional time while KDevelop burns CPU to do things (AGAIN) I will probably never require is much worse IMHO.

It's self-evident that parsing a file is not instantaneous, there's always a lag between the moment you (re)open a file and the parser is done (it seems the parser always gets triggered even when you reopen a file). I've never really noticed this to be worse the 1st time I open a file but I guess that's because there too I know that this is to be expected. Code colouring gives good feedback here, btw.

I cannot comment on the lag before code completion becomes available, it's very rare that I need this in the interval after opening a file and locating the spot where I want to change something.

On a general note: I take it libclang doesn't provide the information used by the parser in sequential fashion (I've never noticed a "syntax colouring wave" move from top to bottom through the file)?

mwolff requested changes to this revision.Jan 28 2019, 10:07 AM

it was measured back then:

commit f14a8fc9ceb38a91c2d718552779da666d509bf1
Author: Sven Brauch <mail@svenbrauch.de>
Date:   Wed Jul 26 00:49:18 2017 +0200

    clang: fix precompiled preamble cache misses
    
    We were a) passing in a wrong file size, and b) a different set of unsaved
    files on building the translation unit as compared to invoking completion.
    This resulted in the precompiled preamble being rebuilt every single time.
    On my test file, time spent in clang_codeCompleteAt goes down from ~700ms
    to ~12ms with this change after the project is fully parsed.
    
    It still doesn't work in header files at all.
    
    Differential Revision: https://phabricator.kde.org/D6905

Maybe the correct fix would be to check if the document is currently open, and if so, directly create the preamble on first parse. If the document isn't open yet, then we don't need to create the preamble yet.

Note that this also needs to work properly when we reparse for code completion, that must create the preamble directly.

As-is, this patch is a no-go, but I would like to see more work in this area. We should probably also create a proper benchmark for this while at it.

This revision now requires changes to proceed.Jan 28 2019, 10:07 AM
On my test file, time spent in clang_codeCompleteAt goes down from ~700ms

Seriously, we're complaining here about something that takes 700ms the first time?? An almost 70x speed-up sounds impressive but that reeks of a synthetic benchmark. Which also included other changes.
What I'd like to see is how much difference the user sees with or without a preamble created on first parse. If that difference is obvious it can be quantified using a screen recording and measured in frames.

Evidently there should also be some better quantification (from the patch author) of what is gained by postponing the preamble creation.

Preambles are there to speed up repeated reparsing. Most translation units won't be reparsed in a typical session. Since we pay for every preamble we create, I don't think we should create them unless we've some indication that a file needs to be parsed again. It's pretty safe to assume that a file needs to be reparsed again if we parse it for the second time. There is probably no better indicator, which is why this is the default.

The flag provides us with an advantage only in the following very narrow scenario (which is probably exactly what the benchmark is measuring):

  • User opens a file, patiently waits for it to be parsed.
  • Then starts editing and immediately expects code completion to jump into action.

If the user doesn't wait for the initial parse, there will be a delay anyway. Otherwise, there will only be a delay on the very first edit. Is that too much to pay for not having to serialize and store preambles for the entire project?

Maybe the correct fix would be to check if the document is currently open, and if so, directly create the preamble on first parse. If the document isn't open yet, then we don't need to create the preamble yet.

For practical reasons we can only keep a small number of preambles alive. They can be pretty large. When working on the LLVM code base, I observed the typical preamble to be between 30 and 60 MB in size. Having a dozen files open is probably not unusual, and then we get into trouble very soon. Also, I can't talk about others, but I often open files without editing them — KDevelop is not just good for writing code, but also reading it. We only need preambles for code that we change.

Note that this also needs to work properly when we reparse for code completion, that must create the preamble directly.

My understanding is that any reparsing triggers the preamble building.

As-is, this patch is a no-go, but I would like to see more work in this area.

The way I see it, the current situation is a no-go. LLVM has roughly 10.000 translation units. For every TU we create a preamble that is somewhere between 10–70 MB and write it to disk. Thus parsing the entire project results in 100 GB disk I/O (and that is very conservative). Almost all of this is immediately thrown away. There are also larger projects that I'm working on, roughly in the 100.000 TU range.

We should probably also create a proper benchmark for this while at it.

That might depend on the hardware and TMPDIR location, as the preambles are written there. I have /tmp on a RAM disk, but my distro's default is to have no separate file system for it. Then the preambles can actually be written to a spinning hard disk.

rjvbb added a comment.Jan 29 2019, 9:26 AM

Aaron, don't your arguments apply to parsing an entire project on startup as well? I can easily imagine that opening and parsing entire projects of the size you mention must have a non-negligible cost regardless of all optimisation and caching that is currently implemented
There is a setting for this feature. A similar switch for the preamble thing will probably be difficult to label comprehensively but maybe a coupling can be made with the full-project-parse switch?

Probably in the sense that you create the preamble on first parse only when not parsing the entire project on import. I'd think that this should maintain the status quo for those files that the user actually opens, while not generating preambles for all the other files.

Aaron, don't your arguments apply to parsing an entire project on startup as well? I can easily imagine that opening and parsing entire projects of the size you mention must have a non-negligible cost regardless of all optimisation and caching that is currently implemented

It definitely does. Sometimes I just cancel it, but sometimes I need the entire index to understand some code. (“Find uses” is very useful for that.)

Probably in the sense that you create the preamble on first parse only when not parsing the entire project on import. I'd think that this should maintain the status quo for those files that the user actually opens, while not generating preambles for all the other files.

I think that's roughly what @mwolff meant in his comment as well: to create preambles only for open files. It's definitely a nice idea, because then we can immediately do code completion for all open files. But as I mentioned, some open files are never changed, especially when a user is just browsing the code to understand it. So I could definitely live with this, but I would slightly prefer going with the default, meaning to build the preamble only on first reparse. I don't think that hurts too bad. If I'm the only one who thinks that way however, I would change the patch to create preambles only for open files.

To clarify, the patch back then was less about the first-time delay, and more about the delay being there *every* time because of wrong usage of the API. Whether the delay occurs once is arguably a bit less important.

rjvbb added a comment.Jan 30 2019, 9:06 AM

So there should indeed be some real-world benchmarking data to do a cost/benefit analysis that includes the human-in-the-loop aspect and huge projects like the ones Aaron uses. We already have an estimated 10% gain for a full reparse of a small project after its initial import.

I'm attaching two potential useful personal patches that add timing on the project import and parsing in case anyone else wants to look at such data, the patch that allows to reparse a loaded project without reloading it is D11934 .


To clarify, the patch back then was less about the first-time delay, and more about the delay being there *every* time because of wrong usage of the API. Whether the delay occurs once is arguably a bit less important.

That's good to hear, reading your commit message made me think that preventing the delay of the first reparse was not the goal of these changes.

again: why don't we keep this flag when the file is opened in the editor?

I'm fine with that, but would prefer never having it. Not all files that are opened will be edited, and the delay caused by creating the preamble after the first edit is probably negligible over the lifetime of a session. It would also allow us to just drop affected preambles when a header is edited — otherwise we might have to recreate all preambles that include the header.

rjvbb added a comment.Feb 2 2019, 8:46 AM

Is Milian's suggestion different from mine of setting the flag only when projects are not parsed entirely on import (which may be easier to test for where the flag is set, I haven't checked)?

aaronpuchert added a comment.EditedFeb 2 2019, 4:13 PM

The way I understand it, the proposals are slightly different. Maybe we can summarize them as follows:

Create preamble for@aaronpuchert@rjvbb@mwolff
files that are not opennevernevernever
files that are open if (1)on first changeon first changewhen opening
files that are open if ¬(1)on first changewhen openingwhen opening

where (1) = entire project is parsed on import. Is that correct? For your proposal the first column says “never” because you don't create preambles immediately when parsing the entire project.

rjvbb added a comment.Feb 2 2019, 8:03 PM
where (1) = entire project is parsed on import. Is that correct?

If line 3 means "files opened after (1)" then yes, that's probably correct.

If line 3 means "files opened after (1)" then yes, that's probably correct.

Then I misunderstood you. You want to make it dependent on whether the file is opened after parsing the entire project, if it is parsed at all? I thought you meant it should depend on whether a user has chosen that option.

rjvbb added a comment.Feb 3 2019, 6:39 PM

No, sorry, I am a bit confused by your notation and the fact you seem to consider only files that are open when you start a session and then probably confused myself a bit more while answering.

So:

  • when "¬(1)", the clang flag is set and preambles are created as they are currently, nothing changes.
  • when "(1)", the clang flag is not set, preambles are not created during the initial import except possibly for the files that opened with the session if the parser is triggered twice for those. If it is not, the preamble will be created on first change. For all other files the preamble will be created later, I presume when you open the file (because that always seems to trigger the parser for me).

preambles are not created during the initial import except possibly for the files that opened with the session if the parser is triggered twice for those.

Is the parser triggered again if the entire project has been parsed already? I thought not, but I haven't looked at the code yet. If that is the case, then your and Milian's approaches should have the same effect, if I'm not missing anything.

rjvbb added a comment.Feb 5 2019, 9:12 AM
Is the parser triggered again if the entire project has been parsed already?

I can't say that it happens systematically but neither that it does NOT happen systematically, and I mean that in general: re-opening a file you just closed.

Isn't this unavoidable BTW, given that we don't end up with preambles of all files?

I can't say that it happens systematically but neither that it does NOT happen systematically, and I mean that in general: re-opening a file you just closed.

Isn't this unavoidable BTW, given that we don't end up with preambles of all files?

Yes, we don't keep these. But my understanding is that we translate Clang's index into our own (the mystical DUChain) and when opening a file it might not be necessary to reparse the file, if we still have everything we need in our own data structures. Then I'm also not sure if we actually "reparse" (i.e. call clang_reparseTranslationUnit) the translation unit that we still have laying around, but have "suspended" with clang_suspendTranslationUnit, or if we create a new one. I don't see us calling the latter function, so I assumed we just dispose the translation unit (clang_disposeTranslationUnit), meaning that we have to create it again when opening it — which would make it the first parse, not the first reparse.

I'm fine with that, but would prefer never having it. Not all files that are opened will be edited, and the delay caused by creating the preamble after the first edit is probably negligible over the lifetime of a session. It would also allow us to just drop affected preambles when a header is edited — otherwise we might have to recreate all preambles that include the header.

Hm yes and no. Yes, many files you open due to browsing won't be edited. But once you do, performance is imo quite important. See e.g. ClangSupport::documentActivated which has explicit code to attach the AST cf. AttachASTWithoutUpdating. The AST is essentially the Clang TU representation. Without that, we can't do code completion at all. Now, imagine we open a C++ file, we realize we don't have the AST, so we trigger a parse to attach the AST. Now you do code completion. When we didn't create the preamble, we will have to reparse the file completely. And this can easily take 1-2s per file, which is *really* annoying. Also note how we just reparsed the file solely for code completion purposes!

So I really am opposed to the idea of never passing CXTranslationUnit_CreatePreambleOnFirstParse. Please, do create the preamble when we have the TU main file or its header file open in the editor.

aaronpuchert added a comment.EditedFeb 11 2019, 10:48 PM

When we didn't create the preamble, we will have to reparse the file completely. And this can easily take 1-2s per file, which is *really* annoying.

It only happens on the very first edit though, and will only be noticeable if code completion is required immediately after starting to edit the file. All following parses and code completions can use the precompiled preamble then. I don't think that's too bad. It's also not unusual, many applications have something like a "warmup phase" where not everything is loaded yet.

Also note how we just reparsed the file solely for code completion purposes!

You mean the preamble? Since code completion is usually invoked after some initial changes, we have to reparse anyway. What you said would only be true if we invoke code completion without changing anything first, which seems rather weird.

So I really am opposed to the idea of never passing CXTranslationUnit_CreatePreambleOnFirstParse. Please, do create the preamble when we have the TU main file or its header file open in the editor.

For all open files, or just the ones that are active? My point is that we will probably not get to a point where we can guarantee that we have preambles for all open files around, so why bother at all? Preambles are there to speed up repeated reparsing, so I think we should only keep them for files where that is actually the case, meaning that they are actively changed.

Anything beyond that would put enormous strain on the user's resources. Imagine someone editing a header that is used in other open files. We don't want to immediately reparse them every time the header is changed. So the user will always get in situations where the preamble is not immediately available. Unless we guarantee that however, using the flag is purely window-dressing.

rjvbb added a comment.Feb 12 2019, 9:20 AM

+++

Or, you add a flag to one of the relevant settings panels. There are already a number of options that aren't exactly easy to understand for everyone, this one could be something like "Make code-completion results available faster (can require significant resources)".

Or, you add a flag to one of the relevant settings panels. There are already a number of options that aren't exactly easy to understand for everyone, this one could be something like "Make code-completion results available faster (can require significant resources)".

Not so sure about that. I would rather make sure that the currently active document (meaning it has keyboard focus) is always up-to-date. Currently we don't reparse (always?) when an included file changes. That's probably way more annoying than the first code completion having some delay.

This is not something that should be configurable. The follow-up to hard-to-understand options shouldn't be to add more of them.

rjvbb added a comment.Feb 13 2019, 8:49 AM

Well, if among developers you cannot find a solution that covers all use cases a configurable setting (applying only to setting the preamble-on-first parse flag or not) could well be the only compromise. And this one doesn't have to be hard to understand, which doesn't mean it has to (probably means that it should not) indicate exactly what it does.

I would rather make sure that the currently active document (meaning it has keyboard focus) is always up-to-date.

But that's a different issue, isn't it? Can the parser even be expected to react to chages to a headerfile that don't lead to a change notification?

way more annoying than the first code completion having some delay.

Oh yes, there are many things way more annoying than that. Like the fact that the parser can probably never know when you're done with an edit and only then start parsing instead of belching out errors about unfinished changes ;) Or when not to apply a seemingly obvious code completion which you then have to correct manually

Well, if among developers you cannot find a solution that covers all use cases a configurable setting (applying only to setting the preamble-on-first parse flag or not) could well be the only compromise.

I wouldn't want to give up on a consensus just yet. I think the Clang developers have actually chosen a pretty smart default, and this additional flag incurs costs that are hard to control for hardly any benefit.

To some extent this resembles the classic latency/throughput discussion. Just with a minor twist: we increase the overall load of the program for a one-time latency reduction. Keeping unnecessary preambles is problematic regardless of whether /tmp is a RAM disk or not — if it is, we consume valuable memory without using it, if it isn't, we incur unnecessary disk I/O.

I would rather make sure that the currently active document (meaning it has keyboard focus) is always up-to-date.

But that's a different issue, isn't it? Can the parser even be expected to react to changes to a headerfile that don't lead to a change notification?

I can't say how hard it would be technically. But since we watch files anyway, we could also track dependencies and reparse active documents if a dependency has changed. Of course that's a separate issue and probably not easy to solve.

rjvbb added a comment.Feb 14 2019, 9:24 AM
To some extent this resembles the classic latency/throughput discussion.

I'd say that is exactly what it is, not just to some extent. What else would it be?

Keeping unnecessary preambles is problematic regardless of whether `/tmp` is a RAM disk or not

Indeed, and in that light clang's solution is maybe not that smart, at least not for use as a parser for an entire project. From what I understand that preamble is just a precompiled header file, which in my experience can be tricky to set up (typically require some sort of central header that imports everything that'll be needed everywhere). Having one such preamble per file cannot but duplicate lots of data.

I can't say how hard it would be technically. But since we watch files anyway,

Separate issue, but not all systems support tracking (that many) individual files. On Mac you only get directory watching, for instance.

we could also track dependencies and reparse active documents if a dependency has changed.

I was assuming this is what happens, at least for open files. Of course that could be something done entirely by libclang internally.

Indeed, and in that light clang's solution is maybe not that smart, at least not for use as a parser for an entire project. From what I understand that preamble is just a precompiled header file, which in my experience can be tricky to set up (typically require some sort of central header that imports everything that'll be needed everywhere). Having one such preamble per file cannot but duplicate lots of data.

You're right, it's a precompiled header file. I think it works very well for the intended purpose: quick reparsing on most user edits. The additional option that we use here was added in https://reviews.llvm.org/D15490 for pure code completion workloads. I don't think it's meant for us, even though we do completion as well: we also build an index, and have possibly many more files open.

we could also track dependencies and reparse active documents if a dependency has changed.

I was assuming this is what happens, at least for open files. Of course that could be something done entirely by libclang internally.

Sometimes it works, sometimes it doesn't. Often I have to mock-edit a file to force reparsing when some header has changed.

rjvbb added a comment.Feb 15 2019, 8:47 AM
Sometimes it works, sometimes it doesn't. Often I have to mock-edit a file to force reparsing when some header has changed.

I find that just reloading the file works too (I have a shortcut for that).
Come to think of it, libclang probably doesn't bother with file-change monitoring given that it's intended primarily for use in compilers.

When we didn't create the preamble, we will have to reparse the file completely. And this can easily take 1-2s per file, which is *really* annoying.

It only happens on the very first edit though, and will only be noticeable if code completion is required immediately after starting to edit the file. All following parses and code completions can use the precompiled preamble then. I don't think that's too bad. It's also not unusual, many applications have something like a "warmup phase" where not everything is loaded yet.

Yes, but hiding or minimizing the warmup phase is good. And it would be possible by having the flag active for opened files like I request.

Also note how we just reparsed the file solely for code completion purposes!

You mean the preamble? Since code completion is usually invoked after some initial changes, we have to reparse anyway. What you said would only be true if we invoke code completion without changing anything first, which seems rather weird.

I mean: We trigger a reparse when we open a document, to get hold of the clang TU to do code completion. If this *does not* create a preamble, then the following call to query code completion items - *after* editing - will create the preamble. The preamble only includes the headers of the file, not the contents of the .cpp. You usually edit the .cpp file and then you want to get code completion results immediately. Having a preamble is crucial for good performance here.

So I really am opposed to the idea of never passing CXTranslationUnit_CreatePreambleOnFirstParse. Please, do create the preamble when we have the TU main file or its header file open in the editor.

For all open files, or just the ones that are active? My point is that we will probably not get to a point where we can guarantee that we have preambles for all open files around, so why bother at all? Preambles are there to speed up repeated reparsing, so I think we should only keep them for files where that is actually the case, meaning that they are actively changed.

Lacking an proper LRU cache, enabling it for all open documents is the only option we have currently I think.

Anything beyond that would put enormous strain on the user's resources. Imagine someone editing a header that is used in other open files. We don't want to immediately reparse them every time the header is changed. So the user will always get in situations where the preamble is not immediately available. Unless we guarantee that however, using the flag is purely window-dressing.

The reparse would only happen when we trigger a new parse job. Which we - afaik - only do on activation.

Currently we don't reparse (always?) when an included file changes. That's probably way more annoying than the first code completion having some delay.

That sounds like a serious bug, I was under the impression that we properly check the include files for updates too. But thinking more about this: Afaik we properly did that in old-cpp, but maybe kdev-clang lost that feature since we don't store the included files anymore? I have to look into this. Anyhow, unrelated to the patch at hand.

rjvbb added a comment.Mar 14 2019, 9:49 AM

Re: reparsing reliably each time a headerfile is changed: wouldn't the use of forwarding headers increase the chance of missing a change?

Re: reparsing reliably each time a headerfile is changed: wouldn't the use of forwarding headers increase the chance of missing a change?

What's a forwarding header? Do you mean something like #include <Foo> which then contains a #include <foo.h>? We obviously should use the full include chain which will cover all files, not only direct includes.

rjvbb added a comment.Apr 15 2019, 9:01 AM
Do you mean something like `#include <Foo>` which then contains a `#include <foo.h>`?

Yes.

We obviously should use the full include chain which will cover all files, not only direct includes.

This kind of circles back to earlier discussions we had about monitoring file changes and how that's not always as simple as adding another inotify thingy. If anything it would be mostly a waste to monitor a header that only serves to include another header (except in the unlikely event the forward changes).

Is it even up to KDevelop to detect changes in all files that should trigger a reparse of a given translation unit or does libclang take care of that?

quite obviously libclang doesn't handle it

I still think this is the right change, but if there is no consensus I will implement @mwolff's suggestion. That would certainly be an improvement, but it doesn't really solve my problem. I'm currently working on Clang and have around 6 files open, which is really not a lot. I haven't changed any of them. The result:

aaron:~/src/llvm-project> ls -l /tmp/preamble-*
-rw-r--r-- 1 aaron users 73139496 Okt  9 22:27 /tmp/preamble-0e19f4.pch
-rw-r--r-- 1 aaron users 59327864 Okt  9 22:23 /tmp/preamble-2a515c.pch
-rw-r--r-- 1 aaron users 61885536 Okt  9 22:23 /tmp/preamble-2baca3.pch
-rw-r--r-- 1 aaron users 76913424 Okt  9 22:23 /tmp/preamble-9853df.pch
-rw-r--r-- 1 aaron users 64254872 Okt  9 22:23 /tmp/preamble-cbb035.pch
-rw-r--r-- 1 aaron users 64829792 Okt  9 22:24 /tmp/preamble-dd9bf1.pch
aaron:~/src/llvm-project> du -s /tmp/ 2>/dev/null
391204  /tmp/

Now I actually have /tmp as tmpfs, and so these 400 MB don't come for free. This is perfectly fine when I'm actually working on these files, but so far I have only opened KDevelop.

When we didn't create the preamble, we will have to reparse the file completely. And this can easily take 1-2s per file, which is *really* annoying.

It only happens on the very first edit though, and will only be noticeable if code completion is required immediately after starting to edit the file. All following parses and code completions can use the precompiled preamble then. I don't think that's too bad. It's also not unusual, many applications have something like a "warmup phase" where not everything is loaded yet.

Yes, but hiding or minimizing the warmup phase is good. And it would be possible by having the flag active for opened files like I request.

Creating a preamble is actually more expensive than not creating it. So we make the initial parsing slower. This is only faster for files are actually edited.

Creating it immediately only improves the reaction time for the first edit. For that small benefit, we're paying a hefty price.

Also note how we just reparsed the file solely for code completion purposes!

You mean the preamble? Since code completion is usually invoked after some initial changes, we have to reparse anyway. What you said would only be true if we invoke code completion without changing anything first, which seems rather weird.

I mean: We trigger a reparse when we open a document, to get hold of the clang TU to do code completion. If this *does not* create a preamble, then the following call to query code completion items - *after* editing - will create the preamble. The preamble only includes the headers of the file, not the contents of the .cpp.

Well, then why don't we just skip the initial reparse, and only reparse after the first edit?

You usually edit the .cpp file and then you want to get code completion results immediately.

We're talking about a one-time delay, all further edits will have a preamble.

Having a preamble is crucial for good performance here.

I'm not suggesting to not create a preamble at all, but to create it only when we know it is needed.

rjvbb added a comment.Thu, Oct 10, 8:26 AM
I'm not suggesting to not create a preamble at all, but to create it only when we **know** it is needed.

+++
This should speed up the initial opening significantly for sessions that restore a large number of documents on start (= most of mine).

It may be worth repeating my recent observation here that under some conditions a reparse will be triggered on launch of files that are not open but mentioned in one of the session's working sets that have remained in the sessionrc file. That's probably a bug (just like the "do you want to save this modified file" alert I got the other day for a document that wasn't open at all *in the editor*). But then again I never grasped what KDevelop's working sets are supposed to do (and how), so maybe it *is* relevant here.