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

"flutter.setSubscriptions" call never forgets a file (aka will ask about an ever growing number of files) #7980

Open
jensjoha opened this issue Mar 24, 2025 · 1 comment

Comments

@jensjoha
Copy link

In IntelliJ, opening a project with flutter in the environment in pubspec.yaml, e.g. something like

name: issue_whatnot
publish_to: "none"

environment:
  flutter: ">=3.29.0 <4.0.0"
  sdk: ">=3.7.0 <4.0.0"

opening a file sends a flutter.setSubscriptions request looking something like this:

{
  "id": "42",
  "method": "flutter.setSubscriptions",
  "params": {
    "subscriptions": {
      "OUTLINE": [
        "file:///path/to/file_1.dart"
      ]
    }
  }
}

Say we close the file and open another, it now sends something like this:

{
  "id": "42",
  "method": "flutter.setSubscriptions",
  "params": {
    "subscriptions": {
      "OUTLINE": [
        "file:///path/to/file_1.dart",
        "file:///path/to/file_2.dart"
      ]
    }
  }
}

closing that and opening a third, closing that and opening a forth etc a bunch of times and you'll end up with something like

{
  "id": "42",
  "method": "flutter.setSubscriptions",
  "params": {
    "subscriptions": {
      "OUTLINE": [
        "file:///path/to/file_1.dart",
        "file:///path/to/file_2.dart",
        ...
        "file:///path/to/file_n.dart",
      ]
    }
  }
}

at which point the analyzer will start to become slow:

5 ms (+ 22045 ms)	completion.getSuggestions2
23121 ms (+ 100 ms)	edit.getAssists

Notice that if I open a file I've already opened once it doesn't send the request, I believe because of this:

private void addSubscription(@NotNull final String service, @NotNull final String filePath) {
if(!isServerConnected()) {
return;
}
final List<String> files = subscriptions.computeIfAbsent(service, k -> new ArrayList<>());
final String filePathOrUri = getAnalysisService().getLocalFileUri(filePath);
if (!files.contains(filePathOrUri)) {
files.add(filePathOrUri);
sendSubscriptions();
}
}
.

(i.e. sendSubscriptions is only called i it actually adds the path)

I'm guessing something goes wrong in these lines:

final List<String> obsoletePaths = new ArrayList<>();
synchronized (outlineListeners) {
for (final String path : outlineListeners.keySet()) {
if (!newPaths.contains(path)) {
obsoletePaths.add(path);
}
}
for (final String path : obsoletePaths) {
final String filePathOrUri = getAnalysisServer().getAnalysisService().getLocalFileUri(path);
final FlutterOutlineListener listener = outlineListeners.remove(filePathOrUri);
if (listener != null) {
getAnalysisServer().removeOutlineListener(FileUtil.toSystemDependentName(path), listener);
}
}
// Register new outline listeners.
for (final String path : newPaths) {
final String filePathOrUri = getAnalysisServer().getAnalysisService().getLocalFileUri(path);
if (outlineListeners.containsKey(filePathOrUri)) {
continue;
}
final FlutterOutlineListener listener = new OutlineListener(filePathOrUri);
outlineListeners.put(filePathOrUri, listener);
getAnalysisServer().addOutlineListener(FileUtil.toSystemDependentName(path), listener);
}
}

Without having looked into it it seems suspect that it takes a key from outlineListeners (final String path : outlineListeners.keySet()) and then does something to it before trying to remove it again (final String filePathOrUri = getAnalysisServer().getAnalysisService().getLocalFileUri(path);, final FlutterOutlineListener listener = outlineListeners.remove(filePathOrUri);), but I'm guessing.

@jensjoha
Copy link
Author

/cc @jwren

copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Mar 25, 2025
…ening new files

This benchmark simulates the current bug at
flutter/flutter-intellij#7980

Comparing this benchmark across dart versions also reveals something
interesting, here run on the "ImportChain" type with 100 files:

Comparing 3.5.4 with 3.6.2
```
Initial analysis: -2.5724% +/- 1.5022% (-0.16 +/- 0.10) (6.35 -> 6.19)
Completion after open of new file: -1.4714% +/- 1.0334% (-0.04 +/- 0.03) (2.92 -> 2.87)
peak virtual memory size: 8.6445% +/- 2.4585% (220.40 +/- 62.68) (2549.60 -> 2770.00)
total program size (virtual): 9.0756% +/- 2.4049% (226.20 +/- 59.94) (2492.40 -> 2718.60)
peak resident set size ("high water mark"): -9.7940% +/- 1.6649% (-58.00 +/- 9.86) (592.20 -> 534.20)
size of memory portions (rss): -8.7961% +/- 3.4971% (-47.20 +/- 18.77) (536.60 -> 489.40)
```

Comparing 3.6.2 with 3.7.2
```
Initial analysis: -8.7696% +/- 2.2759% (-0.54 +/- 0.14) (6.19 -> 5.64)
Completion without opening files: 16.5289% +/- 8.3591% (0.07 +/- 0.03) (0.41 -> 0.48)
Completion after open of new file: 45.0913% +/- 2.8023% (1.30 +/- 0.08) (2.87 -> 4.17)
getAssists call: 21.4736% +/- 2.3049% (0.61 +/- 0.07) (2.86 -> 3.48)
peak virtual memory size: -5.9134% +/- 3.8164% (-163.80 +/- 105.72) (2770.00 -> 2606.20)
total program size (virtual): -6.5548% +/- 4.0754% (-178.20 +/- 110.79) (2718.60 -> 2540.40)
peak resident set size ("high water mark"): -16.3984% +/- 0.5460% (-87.60 +/- 2.92) (534.20 -> 446.60)
size of memory portions (rss): -18.0629% +/- 3.2699% (-88.40 +/- 16.00) (489.40 -> 401.00)
```

Where, between 3.6.2 and 3.7.2 these stand out:
```
Completion without opening files: 16.5289% +/- 8.3591% (0.07 +/- 0.03) (0.41 -> 0.48)
Completion after open of new file: 45.0913% +/- 2.8023% (1.30 +/- 0.08) (2.87 -> 4.17)
getAssists call: 21.4736% +/- 2.3049% (0.61 +/- 0.07) (2.86 -> 3.48)
```

these surely weren't great before, but are much worse now.

Change-Id: I6f94f941cda86b1aa9ee7e7a9b1912df85c7acb2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417820
Commit-Queue: Jens Johansen <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant