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

(perf) bump "string-cache" crate for per-bucket mutex #6980

Merged
merged 2 commits into from Mar 8, 2023

Conversation

YoniFeng
Copy link
Contributor

Description:

Bump the "string-cache" crate to 0.8.5, which includes this PR.
Internally, it now locks on each individual bucket within the DYNAMIC_SET struct, rather than locking on the whole data structure.
Parallel performance should improve.

BREAKING CHANGE:

Related issue (if exists):

@CLAassistant
Copy link

CLAassistant commented Feb 22, 2023

CLA assistant check
All committers have signed the CLA.

@YoniFeng
Copy link
Contributor Author

Rust newbie.

  1. I didn't bump swc_common
  2. Bumping breaks browserslist-rs v0.12.2.
    Locally I altered back to 0.8.4 but still got the build break, so I convinced myself it it's a fake issue.
    Needed to modify the lockfile with cargo update.

Looking at the issue in browserslist-rs (makes no sense on the surface level - string_cache's APIs didn't change).
Will need to PR there, wait for publish and bump dependency version here.

@YoniFeng
Copy link
Contributor Author

Waiting on the breaking change getting reverted and a new string_cache version published (with the Mutex PR)

@kdy1 kdy1 marked this pull request as draft February 28, 2023 03:36
@YoniFeng YoniFeng marked this pull request as ready for review March 3, 2023 19:11
@YoniFeng YoniFeng marked this pull request as draft March 3, 2023 20:21
bors-servo added a commit to servo/string-cache that referenced this pull request Mar 5, 2023
fix: move debug_assert check

Fix needed after #268
The fix is only for debug_assert correctness. There's no functional effect.
i.e. version 0.8.6 might cause debug tests to fail, but it isn't a (functionally) breaking change.

**Explanation**
Moving the lock to be per-bucket changed the `DYNAMIC_SET`'s API so that it doesn't need to be locked (i.e. `DYANMIC_SET` is not wrapped with a `Mutex`).
The `Atom`'s `fn drop` changed from
```rust
fn drop(&mut self) {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
                drop_slow(self)
            }
        }

        // Out of line to guide inlining.
        fn drop_slow<Static>(this: &mut Atom<Static>) {
            DYNAMIC_SET
                .lock()
                .remove(this.unsafe_data.get() as *mut Entry);
        }
    }
```
to
```rust
impl<Static> Drop for Atom<Static> {
    #[inline]
    fn drop(&mut self) {
        if self.tag() == DYNAMIC_TAG {
            let entry = self.unsafe_data.get() as *const Entry;
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
                drop_slow(self)
            }
        }

        // Out of line to guide inlining.
        fn drop_slow<Static>(this: &mut Atom<Static>) {
            DYNAMIC_SET.remove(this.unsafe_data.get() as *mut Entry);
        }
    }
```
(the `lock()` is gone)
Now when we enter `DYNAMIC_SET.remove()`, there's no longer a lock guarantee.
Until we lock the bucket, another thread could be in the middle of performing a `DYNAMIC_SET.insert()` for the same string.
Therefore, the `debug_assert!(value.ref_count.load(SeqCst) == 0)` is premature - it needs to occur after we take the lock for the bucket.

Caught at swc-project/swc#6980 in a [failed test](https://github.com/swc-project/swc/actions/runs/4326536698/jobs/7554083939).
@YoniFeng YoniFeng mentioned this pull request Mar 7, 2023
6 tasks
@YoniFeng YoniFeng changed the title (perf) Bump "string-cache" crate (perf) bump "string-cache" crate for per-bucket mutex Mar 7, 2023
@YoniFeng YoniFeng marked this pull request as ready for review March 7, 2023 14:58
@YoniFeng
Copy link
Contributor Author

YoniFeng commented Mar 7, 2023

@kdy1
is there a need/want to benchmark before merging, or should we just look at post-merge CI benchmark?

@kdy1
Copy link
Member

kdy1 commented Mar 8, 2023

I think the post-merge benchmark is fine, as we can revert them easily

@YoniFeng
Copy link
Contributor Author

YoniFeng commented Mar 8, 2023

Is something missing for merge?

Copy link
Member

@kdy1 kdy1 left a comment

Choose a reason for hiding this comment

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

swc-bump:

  • swc_atoms

@kdy1 kdy1 merged commit 9841f0b into swc-project:main Mar 8, 2023
@kdy1 kdy1 modified the milestones: Planned, v1.3.39 Mar 8, 2023
@swc-project swc-project locked as resolved and limited conversation to collaborators Apr 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants