Skip to content

Commit

Permalink
Merge pull request #23 from tweedegolf/page-pointers
Browse files Browse the repository at this point in the history
Added page pointer cache type
  • Loading branch information
diondokter authored Feb 7, 2024
2 parents 60267b3 + 0d8858f commit d549965
Show file tree
Hide file tree
Showing 10 changed files with 528 additions and 92 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

(DD-MM-YY)

## Unreleased
## 0.8.1 07-02-24

- Added new PagePointerCache that caches more than the PageStateCache. See the readme for more details.

## 0.8.0 05-12-24

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sequential-storage"
version = "0.8.0"
version = "0.8.1"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "A crate for storing data in flash with minimal erase cycles."
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,20 @@ Instead, we can optionally store some state in ram.

These numbers are taken from the test cases in the cache module:

| Name | Map # flash reads | Map flash bytes read | Queue # flash reads | Queue flash bytes read |
| -------------: | ----------------: | -------------------: | ------------------: | ---------------------: |
| NoCache | 100% | 100% | 100% | 100% |
| PageStateCache | 77% | 97% | 51% | 90% |
| Name | RAM bytes | Map # flash reads | Map flash bytes read | Queue # flash reads | Queue flash bytes read |
| ---------------: | ------------: | ----------------: | -------------------: | ------------------: | ---------------------: |
| NoCache | 0 | 100% | 100% | 100% | 100% |
| PageStateCache | 1 * num pages | 77% | 97% | 51% | 90% |
| PagePointerCache | 9 * num pages | 69% | 89% | 35% | 61% |

#### Takeaways

- PageStateCache
- Mostly tackles number of reads
- Very cheap in RAM, so easy win
- PagePointerCache
- Very efficient for the queue
- Minimum cache level that makes a dent in the map

## Inner workings

Expand Down
25 changes: 18 additions & 7 deletions fuzz/fuzz_targets/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,28 @@ use libfuzzer_sys::arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;
use rand::SeedableRng;
use sequential_storage::{
cache::{CacheImpl, NoCache, PagePointerCache, PageStateCache},
map::{MapError, StorageItem},
mock_flash::{MockFlashBase, MockFlashError, WriteCountCheck},
};
use std::{collections::HashMap, ops::Range};

fuzz_target!(|data: Input| fuzz(data));
const PAGES: usize = 4;
const WORD_SIZE: usize = 4;
const WORDS_PER_PAGE: usize = 256;

fuzz_target!(|data: Input| match data.cache_type {
CacheType::NoCache => fuzz(data, NoCache::new()),
CacheType::PageStateCache => fuzz(data, PageStateCache::<PAGES>::new()),
CacheType::PagePointerCache => fuzz(data, PagePointerCache::<PAGES>::new()),
});

#[derive(Arbitrary, Debug, Clone)]
struct Input {
seed: u64,
fuel: u16,
ops: Vec<Op>,
cache_type: CacheType,
}

#[derive(Arbitrary, Debug, Clone)]
Expand Down Expand Up @@ -86,20 +96,21 @@ impl StorageItem for TestItem {
}
}

fn fuzz(ops: Input) {
const PAGES: usize = 4;
const WORD_SIZE: usize = 4;
const WORDS_PER_PAGE: usize = 256;
#[derive(Arbitrary, Debug, Clone)]
enum CacheType {
NoCache,
PageStateCache,
PagePointerCache,
}

fn fuzz(ops: Input, mut cache: impl CacheImpl) {
let mut flash = MockFlashBase::<PAGES, WORD_SIZE, WORDS_PER_PAGE>::new(
WriteCountCheck::OnceOnly,
Some(ops.fuel as u32),
true,
);
const FLASH_RANGE: Range<u32> = 0x000..0x1000;

let mut cache = sequential_storage::cache::NoCache::new();

let mut map = HashMap::new();
#[repr(align(4))]
struct AlignedBuf([u8; 260]);
Expand Down
31 changes: 22 additions & 9 deletions fuzz/fuzz_targets/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@ use libfuzzer_sys::arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;
use rand::{Rng, SeedableRng};
use sequential_storage::{
cache::{CacheImpl, NoCache, PagePointerCache, PageStateCache},
mock_flash::{MockFlashBase, MockFlashError, WriteCountCheck},
Error,
};
use std::{collections::VecDeque, ops::Range};
const MAX_VALUE_SIZE: usize = u8::MAX as usize;

fuzz_target!(|data: Input| fuzz(data));
const PAGES: usize = 4;
const WORD_SIZE: usize = 4;
const WORDS_PER_PAGE: usize = 256;

fuzz_target!(|data: Input| match data.cache_type {
CacheType::NoCache => fuzz(data, NoCache::new()),
CacheType::PageStateCache => fuzz(data, PageStateCache::<PAGES>::new()),
CacheType::PagePointerCache => fuzz(data, PagePointerCache::<PAGES>::new()),
});

#[derive(Arbitrary, Debug, Clone)]
struct Input {
seed: u64,
fuel: u16,
ops: Vec<Op>,
cache_type: CacheType,
}

#[derive(Arbitrary, Debug, Clone)]
Expand All @@ -34,23 +44,24 @@ struct PushOp {
value_len: u8,
}

#[derive(Arbitrary, Debug, Clone)]
enum CacheType {
NoCache,
PageStateCache,
PagePointerCache,
}

#[repr(align(4))]
struct AlignedBuf([u8; MAX_VALUE_SIZE + 1]);

fn fuzz(ops: Input) {
const PAGES: usize = 4;
const WORD_SIZE: usize = 4;
const WORDS_PER_PAGE: usize = 256;

fn fuzz(ops: Input, mut cache: impl CacheImpl) {
let mut flash = MockFlashBase::<PAGES, WORD_SIZE, WORDS_PER_PAGE>::new(
WriteCountCheck::Twice,
Some(ops.fuel as u32),
true,
);
const FLASH_RANGE: Range<u32> = 0x000..0x1000;

let mut cache = sequential_storage::cache::NoCache::new();

let mut order = VecDeque::new();
let mut buf = AlignedBuf([0; MAX_VALUE_SIZE + 1]);

Expand All @@ -67,7 +78,9 @@ fn fuzz(ops: Input) {
#[cfg(fuzzing_repro)]
eprintln!("{}", flash.print_items());
#[cfg(fuzzing_repro)]
eprintln!("=== OP: {op:?} ===");
eprintln!("{:?}", cache);
#[cfg(fuzzing_repro)]
eprintln!("\n=== OP: {op:?} ===\n");

match &mut op {
Op::Push(op) => {
Expand Down
Loading

0 comments on commit d549965

Please sign in to comment.