Skip to content

Commit 449c8cd

Browse files
authored
Merge pull request #31 from frengor/dev
- Update to 0.5.0 - Implement tracing doing a breadth-first traversal of the heap, making the collector not overflow the stack when analyzing very deep and nested structures - Improve performance when weak pointers are enabled. - *(nightly only)* Derive `SmartPointer` for `Cc` - Minor improvements and fixes - Update iai-callgrind to 1.12.2
2 parents b61b5ed + d2051fa commit 449c8cd

File tree

20 files changed

+1535
-1062
lines changed

20 files changed

+1535
-1062
lines changed

.github/workflows/bench.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ on:
55
types: [labeled]
66

77
env:
8-
IAI_CALLGRIND_VERSION: 0.7.3
98
CARGO_TERM_COLOR: always
109
IAI_CALLGRIND_COLOR: never
1110
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
@@ -27,7 +26,12 @@ jobs:
2726
- uses: taiki-e/install-action@valgrind
2827
- uses: taiki-e/install-action@cargo-binstall
2928
- name: Install iai-callgrind-runner
30-
run: cargo binstall --no-confirm --no-symlinks iai-callgrind-runner --version ${IAI_CALLGRIND_VERSION}
29+
run: |
30+
version=$(cargo metadata --format-version=1 |\
31+
jq '.packages[] | select(.name == "iai-callgrind").version' |\
32+
tr -d '"'
33+
)
34+
cargo binstall --no-confirm --no-symlinks iai-callgrind-runner --version "${version}"
3135
- name: Bench base branch
3236
run: |
3337
cargo update

CONTRIBUTING.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Also, remember to open the pull requests toward the `dev` branch. The `main` bra
1010

1111
The core idea behind the algorithm is the same as the one presented by Lins in ["Cyclic Reference Counting With Lazy Mark-Scan"](https://kar.kent.ac.uk/22347/1/CyclicLin.pdf)
1212
and by Bacon and Rajan in ["Concurrent Cycle Collection in Reference Counted Systems"](https://pages.cs.wisc.edu/~cymen/misc/interests/Bacon01Concurrent.pdf).
13-
However, the implementation differs in order to make the collector faster and more resilient to random panics and failures in general.
13+
However, the implementation differs in order to make the collector faster and more resilient to panics and failures.
1414

1515
> [!IMPORTANT]
1616
> `rust-cc` is *not* strictly an implementation of the algorithm shown in the linked papers and it's never been
@@ -23,24 +23,33 @@ The `POSSIBLE_CYCLES` is an (intrusive) list which contains the possible roots o
2323
Sometimes (see [`crate::trigger_collection`](./src/lib.rs)), when creating a new `Cc` or when `collect_cycles` is called,
2424
the objects inside the `POSSIBLE_CYCLES` list are checked to see if they are part of a garbage cycle.
2525

26-
Therefore, they undergo two tracing passes:
27-
- **Trace Counting:** during this phase, starting from the elements inside `POSSIBLE_CYCLES`,
28-
objects are traced to count the amount of pointers to each `CcBox` that is reachable from the list's `Cc`s.
26+
Therefore, they undergo two tracing phases:
27+
- **Trace Counting:** during this phase, a breadth-first traversal of the heap is performed starting from the elements inside
28+
`POSSIBLE_CYCLES` to count the number of pointers to each `CcBox` that is reachable from the list's `Cc`s.
2929
The `tracing_counter` "field" (see the [`counter_marker` module](./src/counter_marker.rs) for more info) is used to keep track of this number.
3030
<details>
3131
<summary>About tracing_counter</summary>
3232
<p>In the papers, Lins, Bacon and Rajan decrement the RC itself instead of using another counter. However, if during tracing there was a panic,
3333
it would be hard for `rust-cc` to restore the RC correctly. This is the reason for the choice of having another counter.
34-
The invariant regarding this second counter is that it must always be between 0 and RC inclusively.
34+
The invariant regarding this second counter is that it must always be between 0 and RC (inclusively).
3535
</p>
3636
</details>
3737
- **Trace Roots:** now, every `CcBox` which has the RC strictly greater than `tracing_counter` can be considered a root,
38-
since it must exist a `Cc` pointer which points at it that hasn't been traced before. Thus, a trace is started from these roots,
39-
and all objects not reached during this trace are finalized/deallocated (the story is more complicated because of possible
38+
since it must exist a `Cc` pointer which points at it that hasn't been traced in the previous phase. Thus, a trace is started from these roots,
39+
and all objects not reached during this trace are finalized/deallocated (this is actually more complex due to possible
4040
object resurrections, see the comments in [lib.rs](./src/lib.rs)).
4141
Note that this second phase is correct only if the graph formed by the pointers is not changed between the two phases. Thus,
4242
this is a key requirement of the `Trace` trait and one of the reasons it is marked `unsafe`.
4343

44+
## Using lists and queues
45+
46+
When debug assertions are enabled, the `add` method may panic before actually updating the list to contain the added object.
47+
Similarly, the `remove` method may panic after having removed the object from the list.
48+
49+
Thus, marking should be done only:
50+
- after the call to the `add` method
51+
- before the call to the `remove` method.
52+
4453
## Writing tests
4554

4655
Every unit test should start with a call to `tests::reset_state()` to make sure errors in other tests don't impact the current one.

Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ edition.workspace = true
1414
members = ["derive"]
1515

1616
[workspace.package]
17-
version = "0.4.0" # Also update in [dependencies.rust-cc-derive.version]
17+
version = "0.5.0" # Also update in [dependencies.rust-cc-derive.version]
1818
authors = ["fren_gor <[email protected]>"]
1919
repository = "https://github.com/frengor/rust-cc"
2020
categories = ["memory-management", "no-std"]
@@ -49,12 +49,12 @@ std = ["slotmap?/std", "thiserror/std"]
4949
pedantic-debug-assertions = []
5050

5151
[dependencies]
52-
rust-cc-derive = { path = "./derive", version = "=0.4.0", optional = true }
52+
rust-cc-derive = { path = "./derive", version = "=0.5.0", optional = true }
5353
slotmap = { version = "1.0", optional = true }
5454
thiserror = { version = "1.0", package = "thiserror-core", default-features = false }
5555

5656
[dev-dependencies]
57-
iai-callgrind = "=0.7.3" # Also update IAI_CALLGRIND_VERSION in .github/workflows/bench.yml
57+
iai-callgrind = "=0.12.2"
5858
rand = "0.8.3"
5959
trybuild = "1.0.85"
6060
test-case = "3.3.1"
@@ -64,6 +64,10 @@ name = "bench"
6464
harness = false
6565
required-features = ["std", "derive"]
6666

67+
[profile.bench]
68+
debug = true # Required by iai-callgrind
69+
strip = false # Required by iai-callgrind
70+
6771
[lints.rust]
6872
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_auto_cfg)'] }
6973

benches/bench.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod benches {
88
}
99

1010
use std::hint::black_box;
11-
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
11+
use iai_callgrind::{library_benchmark, library_benchmark_group, LibraryBenchmarkConfig, main};
1212
use crate::benches::binary_trees::count_binary_trees;
1313
use crate::benches::binary_trees_with_parent_pointers::count_binary_trees_with_parent;
1414
use crate::benches::large_linked_list::large_linked_list;
@@ -53,4 +53,7 @@ library_benchmark_group!(
5353
benchmarks = large_linked_list_bench
5454
);
5555

56-
main!(library_benchmark_groups = stress_tests_group, binary_trees_group, linked_lists_group);
56+
main!(
57+
config = LibraryBenchmarkConfig::default().raw_callgrind_args(["--branch-sim=yes"]);
58+
library_benchmark_groups = stress_tests_group, binary_trees_group, linked_lists_group
59+
);

0 commit comments

Comments
 (0)