Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Js/engine memory fixes #8200

Closed
wants to merge 5 commits into from
Closed

Js/engine memory fixes #8200

wants to merge 5 commits into from

Conversation

cuba
Copy link
Contributor

@cuba cuba commented Oct 5, 2023

Summary of Changes

This pull request fixes #

Submitter Checklist:

  • Unit Tests are updated to cover new or changed functionality
  • User-facing strings use NSLocalizableString()
  • New or updated UI has been tested across:
    • Light & dark mode
    • Different size classes (iPhone, landscape, iPad)
    • Different dynamic type sizes

Test Plan:

Screenshots:

Reviewer Checklist:

  • Issues include necessary QA labels:
    • QA/(Yes|No)
    • bug / enhancement
  • Necessary security reviews have taken place.
  • Adequate unit test coverage exists to prevent regressions.
  • Adequate test plan exists for QA to validate (if applicable).
  • Issue and pull request is assigned to a milestone (should happen at merge time).

@cuba cuba force-pushed the js/engine-memory-fixes branch 4 times, most recently from a55cfc2 to 01a0062 Compare October 6, 2023 05:37
@cuba cuba force-pushed the js/engine-memory-fixes branch from 01a0062 to 66c39f2 Compare October 6, 2023 05:39
}
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I realized I was unnecessarily removing content blockers when filter lists were not yet ready.

" #\(scriptType.order) \(scriptType.debugDescription)"
}.joined(separator: "\n")
]
ContentBlockerManager.log.debug("Loaded \(userScripts.count + customScripts.count) script(s): \n\(logComponents.joined(separator: "\n"))")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some logging to help me debug the code and ensure everything is working properly

Toggle("All", isOn: allToggled)
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
#endif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some debugging functionality so I can test while compiling/uncomplying all the engines.

Task {
await AdBlockStats.shared.removeDisabledEngines()
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove some engines after changing the settings to help free up memory

// Fallback on earlier versions

}
}, accessory: .disclosureIndicator, cellClass: MultilineSubtitleCell.self),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access to a debug tool

@@ -90,7 +90,8 @@ extension ContentBlockerHelper: TabContentScript {
sourceURL: sourceURL,
enabledRuleTypes: genericTypes,
resourceType: dto.data.resourceType,
isAggressiveMode: domain.blockAdsAndTrackingLevel.isAggressive
isAggressiveMode: domain.blockAdsAndTrackingLevel.isAggressive,
domain: domain
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the domain wasn't being checked. It's not a big deal because this responds to scripts that wouldn't be injected anyway, but figured should fix it.

removedIds.sorted(by: { $0 < $1 }).map({ " - \($0)" }).joined(separator: "\n")
]

ContentBlockerManager.log.debug("Set rule lists:\n\(parts.joined(separator: "\n"))")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some more logs for debugging reasons

ContentBlockerManager.log.error(
"Failed to compile rule lists for `\(type.identifier)` v\(version):\n\(error)"
)
foundError = error
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some debugging changes

self.cachedRuleLists[type.makeIdentifier(for: mode)] = .emptyRules
}
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I handle empty lists or wkwebview spits out an error

case .emptyRules:
return nil
case .none:
return try await loadRuleList(for: type, mode: mode)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gracefully handling the empty lists

ContentBlockerManager.log.debug("Filtered out \(count) rules")
if count > 0 {
ContentBlockerManager.log.debug("Filtered out \(count) rules for `\(type.identifier)`")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some debugging changes

#Preview {
TestAdblockEnginesView()
}
#endif
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debugging tool to brute force large engine compilations under different conditions

} else {
await AdBlockStats.shared.removeEngine(for: .filterListURL(uuid: uuid))
} catch {
ContentBlockerManager.log.error("Failed to compile engine for custom filter list `\(uuid)` v\(version): \(String(describing: error))")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responding to changes to AdBlockStats

@@ -280,7 +274,7 @@ public actor FilterListResourceDownloader {
let result = try AdblockEngine.contentBlockerRules(fromFilterSet: filterSet)

try await ContentBlockerManager.shared.compile(
encodedContentRuleList: result.rulesJSON, for: blocklistType,
encodedContentRuleList: result.rulesJSON, for: blocklistType, version: version,
options: .all, modes: modes
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responding to changes to AdBlockStats

@@ -62,8 +50,7 @@ extension AdblockEngine {

private func useResources(fromFileURL fileURL: URL) throws {
// Add scriplets if available
if let data = FileManager.default.contents(atPath: fileURL.path),
let json = try Self.validateJSON(data) {
if let json = try Self.validateJSON(Data(contentsOf: fileURL)) {
useResources(json)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory usage fixups. This alone would solve a large amount of crashes.

return CachedAdBlockEngine(
engine: engine, filterListInfo: filterListInfo, resourcesInfo: resourcesInfo,
isAlwaysAggressive: isAlwaysAggressive
)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed all serialQueues, None of these are async anymore.

@@ -12,66 +12,228 @@ import os.log
/// for injected scripts needed during web navigation and cosmetic filters models needed by the `SelectorsPollerScript.js` script.
public actor AdBlockStats {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the following changes have been made:

  1. resourcesInfo has been moved to here instead of FilterListResourcesDownloader. This is needed for lazy loading.
  2. Non-enabled filter lists will be lazily loaded when they are enabled by the user next time the user reloads the page. We store the necessary information that is needed to lazy load in availableFilterLists
  3. Serial queue is added to synchronously compile engines (one by one) so memory does not climb during critical compilation stages such as launch. Normally only 3 engines are compiled but if the user enables a large amount of filter lists or custom filter lists this, would cause a crash without this serial queue.
  4. Handling of memory warnings by deleting non-critical engines. Later perhaps we should disable some filer lists and show a warning to the user.

@cuba cuba force-pushed the js/engine-memory-fixes branch from 66c39f2 to 7ddf697 Compare October 6, 2023 06:09
Copy link
Contributor

@iccub iccub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests fail

@iccub iccub marked this pull request as ready for review October 11, 2023 13:53
@iccub iccub requested a review from a team as a code owner October 11, 2023 13:53
@cuba
Copy link
Contributor Author

cuba commented Oct 11, 2023

@iccub Sorry you shouldn't look at this PR.

@cuba cuba closed this Oct 11, 2023
@cuba
Copy link
Contributor Author

cuba commented Oct 11, 2023

Moved here: #8224

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants