Skip to content

Commit a7d7173

Browse files
committed
feat: update docs
1 parent bb4620a commit a7d7173

File tree

4 files changed

+37
-20
lines changed

4 files changed

+37
-20
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ lto = "fat"
2323
codegen-units = 1
2424

2525
[dev-dependencies]
26-
criterion = { version = "0.7", features = ["html_reports"] }
26+
criterion = { version = "0.7" }
2727

2828
[[bench]]
2929
name = "bench"

README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ this to write Rust programs with low-latency message passing.
99
Add this to your `Cargo.toml`:
1010
```TOML
1111
[dependencies]
12-
fq = "0.0.2"
12+
fq = "0.0.3"
1313
```
1414

1515
## Quickstart
@@ -35,30 +35,35 @@ receiver.join().expect("The receiver thread has panicked");
3535
```
3636

3737
## Examples
38-
See the [examples](examples) directory for more usage examples.
38+
See the [examples](examples/README.md) directory for more usage examples.
3939

4040
## How does it work?
41-
The ring buffer structure allows for a contigous data structure. The idea is that if we are able to get extreme
41+
The ring buffer structure allows for a contiguous data structure. The idea is that if we are able to get extreme
4242
cache locality, we can improve performance by reducing cache misses. This is also the reason why if you use
43-
smart pointers like `Box<T>`, performance *may* degrade since cache locality gets affected. For very large
43+
smart pointers like `Box<T>`, performance *may* degrade since cache locality gets degraded. For very large
4444
`T` types, you are more limited by `memcpy()` performance and less from queue implementations. As such,
45-
ring buffers can be considered strongly optimized for data of a few word sizes with some non-linear
45+
ring buffers can be considered strongly optimized for data of a few word sizes with some non-linear performance
4646
degradation for larger sizes. Additional optimizations are provided for CPUs that support `sse` and `prfchw`
47-
flags. As and when Rust `std` provides more relevant instructions, they will be added. This is simply a
47+
instructions. As and when Rust `std` provides more relevant instructions, they will be added. This is simply a
4848
high-level explanation of some of the techniques employed by this crate, you can read the code to gain a better
4949
understanding of what's happening under the hood.
5050

51+
## Profiles
52+
The crate is fully synchronous and runtime-agnostic. We are heavily reliant on `std` for memory management, so
53+
it's unlikely that we will support `#[no_std]` runtimes anytime soon. You should be using the `release` or
54+
`maxperf` profiles for optimal performance.
55+
5156
## Principles
5257
* This crate will always prioritize message throughput over memory usage.
53-
* This crate will always support generic types only.
58+
* This crate will always support generic types.
5459
* This crate will always provide a wait-free **and** lock-free API.
5560
* This crate will use unsafe Rust where possible for maximal throughput.
5661

5762
## Benchmarks
5863
Benchmarks are strictly difficult due to the nature of the program, it's somewhat simple to do a same-CPU
5964
bench but performance will still be affected based on the core type and cache contention. Benchmarks are
60-
provided in the [benchmark](benchmark) directory and can be run with `cargo bench`. Contributions via PRs for
61-
additional benchmarks are welcome.
65+
provided in the [benches](benches/bench.rs) directory and can be run with `cargo bench`. Contributions via
66+
PRs for additional benchmarks are welcome.
6267

6368
## License
6469
Licensed under either of:
@@ -67,9 +72,8 @@ Licensed under either of:
6772
at your option.
6873

6974
### Contribution
70-
Unless you explicitly state otherwise, any contribution intentionally submitted
71-
for inclusion in the work by you, as defined in the LGPL-3.0 license, shall be dual licensed as above, without any
72-
additional terms or conditions.
75+
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you,
76+
as defined in the LGPL-3.0 license, shall be dual licensed as above, without any additional terms or conditions.
7377

7478
## Acknowledgements
75-
Inspired from previous works like [fastqueue2](https://github.com/andersc/fastqueue2), [rigtorp](https://rigtorp.se/ringbuffer) and [rtrb](https://github.com/mgeier/rtrb).
79+
Inspired from the previous works of [fastqueue2](https://github.com/andersc/fastqueue2), [rigtorp](https://rigtorp.se/ringbuffer) and [rtrb](https://github.com/mgeier/rtrb).

examples/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## Examples
2+
The directory provides two simple implementations using `fq`:
3+
1. A basic example demonstrating the usage of the queue with `std` threads.
4+
2. Another example using `tokio` threads.

src/lib.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,11 @@ impl<T> Producer<T> {
210210
unsafe {
211211
let next_index = next_head & self.queue.0.mask.0;
212212
let next_slot = self.queue.0.buffer.0.add(next_index);
213-
#[cfg(target_feature = "sse")]
213+
#[cfg(all(target_arch = "x86_64", target_feature = "sse"))]
214214
{
215215
prefetch_read(next_slot as *const u8);
216216
}
217-
#[cfg(target_feature = "prfchw")]
217+
#[cfg(any(target_arch = "x86", target_feature = "prfchw"))]
218218
{
219219
prefetch_write(next_slot as *const u8);
220220
}
@@ -258,6 +258,7 @@ impl<T> Producer<T> {
258258
/// ```
259259
/// use fq::FastQueue;
260260
/// let (mut producer, mut consumer) = FastQueue::new(2);
261+
/// assert_eq!(consumer.len(), 0);
261262
/// producer.push(42).unwrap();
262263
/// assert_eq!(consumer.len(), 1);
263264
/// ```
@@ -275,8 +276,9 @@ impl<T> Producer<T> {
275276
/// ```
276277
/// use fq::FastQueue;
277278
/// let (mut producer, mut consumer) = FastQueue::new(2);
279+
/// assert!(consumer.is_empty());
278280
/// producer.push(42).unwrap();
279-
/// assert_eq!(consumer.is_empty(), false);
281+
/// assert!(!consumer.is_empty());
280282
/// ```
281283
#[inline(always)]
282284
pub fn is_empty(&self) -> bool {
@@ -289,8 +291,10 @@ impl<T> Producer<T> {
289291
/// ```
290292
/// use fq::FastQueue;
291293
/// let (mut producer, mut consumer) = FastQueue::<usize>::new(2);
292-
/// producer.push(42).unwrap();
294+
/// producer.push(42).unwrap(); // ⚠️ Prefer handling the error over using unwrap()
293295
/// assert_eq!(producer.is_full(), false);
296+
/// producer.push(43).unwrap();
297+
/// assert_eq!(producer.is_full(), true);
294298
/// ```
295299
#[inline(always)]
296300
pub fn is_full(&self) -> bool {
@@ -398,6 +402,7 @@ impl<T> Consumer<T> {
398402
/// ```
399403
/// use fq::FastQueue;
400404
/// let (mut producer, mut consumer) = FastQueue::new(2);
405+
/// assert_eq!(consumer.len(), 0);
401406
/// producer.push(42).unwrap();
402407
/// assert_eq!(consumer.len(), 1);
403408
/// ```
@@ -415,6 +420,7 @@ impl<T> Consumer<T> {
415420
/// ```
416421
/// use fq::FastQueue;
417422
/// let (mut producer, mut consumer) = FastQueue::new(2);
423+
/// assert_eq!(consumer.is_empty(), true);
418424
/// producer.push(42).unwrap();
419425
/// assert_eq!(consumer.is_empty(), false);
420426
/// ```
@@ -424,6 +430,7 @@ impl<T> Consumer<T> {
424430
}
425431
}
426432

433+
/// Helper function to prefetch read operation on supported architectures.
427434
#[cfg(any(
428435
target_arch = "x86",
429436
all(target_arch = "x86_64", target_feature = "sse")
@@ -441,6 +448,7 @@ fn prefetch_read(p: *const u8) {
441448
}
442449
}
443450

451+
/// Helper function to prefetch a write operation on supported architectures.
444452
#[cfg(any(
445453
target_arch = "x86",
446454
all(target_arch = "x86_64", target_feature = "prfchw")
@@ -479,10 +487,11 @@ impl<T> Iterator for Consumer<T> {
479487
self.pop()
480488
}
481489

490+
/// Provides a size hint (may be stale)
482491
#[inline(always)]
483492
fn size_hint(&self) -> (usize, Option<usize>) {
484-
let len = self.len();
485-
(len, Some(len))
493+
// (lower bound, upper bound)
494+
(self.len(), None)
486495
}
487496
}
488497

0 commit comments

Comments
 (0)