Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cdee06e
Add support for custom CRC parameters
onethumb Jun 10, 2025
99985e5
Add shared library support for custom CRC params
onethumb Jun 10, 2025
2eb380f
Fix formatting
onethumb Jun 10, 2025
54779da
Remove dead code
onethumb Jun 10, 2025
97d8d51
Add more custom parameter support
onethumb Jun 11, 2025
90538b7
Add a command-line tool to calculate CRC params
onethumb Jun 11, 2025
17f4057
Make CrcParams public
onethumb Jun 11, 2025
8c97d7e
Update custom CRC params support in FFI
onethumb Jun 11, 2025
caa1837
Add custom params support to the software fallback
onethumb Jun 11, 2025
d771b8e
Fix formatting
onethumb Jun 11, 2025
9272a48
Merge branch 'main' into support-custom-crc-parameters
onethumb Jun 11, 2025
786b4df
Enable custom parameters via CrcParams constructor
onethumb Jun 12, 2025
9a9f4ca
Generate specs w/Kiro for caching generated keys
onethumb Jul 10, 2025
0eb7765
Add docs for performance considerations
onethumb Jul 10, 2025
65708b4
Add a steering document about commenting
onethumb Jul 10, 2025
3dd32a3
Create cache module with core data structures
onethumb Jul 10, 2025
781d754
Implement thread-safe cache storage
onethumb Jul 10, 2025
243336e
Implement cache lookup and storage functions
onethumb Jul 10, 2025
d51fb6a
Add cache management utilities
onethumb Jul 10, 2025
9d3a433
Integrate cache into CrcParams::new()
onethumb Jul 10, 2025
e8697e6
Create comprehensive unit tests for cache functionality
onethumb Jul 10, 2025
5be2e91
Add thread safety tests
onethumb Jul 10, 2025
7c40333
Create integration tests for CrcParams compatibility
onethumb Jul 10, 2025
97504d6
Add comprehensive error handling tests
onethumb Jul 11, 2025
75464e4
Update existing tests to work with caching
onethumb Jul 11, 2025
322d954
Add documentation and finalize implementation
onethumb Jul 11, 2025
bf7d24a
Add and apply code quality requirements
onethumb Jul 11, 2025
dfc6de6
Create spec for future-proofing CrcParams
onethumb Jul 11, 2025
ccfe362
Add CrcKeysStorage enum and helper methods
onethumb Jul 11, 2025
d726a6a
Update architecture code to use safe accessors
onethumb Jul 11, 2025
35d62fe
Switch CrcParams to use CrcKeysStorage
onethumb Jul 11, 2025
7df28e6
Create comprehensive test suite for future-proof functionality
onethumb Jul 11, 2025
ced964b
Validate migration and run full test suite
onethumb Jul 11, 2025
c19ab97
Implement FFI future-proofing for C/C++ compatibility
onethumb Jul 11, 2025
dad60a2
Remove unused bindgen, update packages
onethumb Jul 16, 2025
01df5f5
Apply latest cargo clippy recommendations
onethumb Jul 16, 2025
026f179
Update dependencies
onethumb Jul 16, 2025
de88e02
Improve function names
onethumb Jul 16, 2025
50c500e
Improve docs
onethumb Jul 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions .kiro/specs/crc-params-caching/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# Design Document

## Overview

The CRC parameters caching system will add a thread-safe, memory-efficient cache to the `CrcParams::new()` method. The cache will store pre-computed folding keys indexed by the input parameters, eliminating redundant key generation for identical parameter sets. The design prioritizes performance, thread safety, and minimal memory overhead while maintaining complete API compatibility.

## Architecture

### Cache Structure

The caching system will use a global, thread-safe cache implemented with:

- **Cache Storage**: `std::collections::HashMap<CrcParamsCacheKey, [u64; 23]>`
- **Thread Safety**: `std::sync::RwLock` for concurrent read access with exclusive write access
- **Cache Key**: Custom struct containing all parameters that affect key generation
- **Lazy Initialization**: `std::sync::OnceLock` to initialize the cache on first use

### Cache Key Design

```rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct CrcParamsCacheKey {
width: u8,
poly: u64,
reflected: bool,
}
```

The cache key includes only the parameters that directly affect key generation (`width`, `poly`, `reflected`), excluding parameters like `name`, `init`, `xorout`, and `check` which don't influence the mathematical key computation.

### Cache Access Pattern

1. **Cache Hit Path**: Read lock → HashMap lookup → Return cached keys
2. **Cache Miss Path**: Read lock → Cache miss → Generate keys → Write lock → Store in cache → Return keys
3. **Concurrent Access**: Multiple readers can access simultaneously; writers get exclusive access

## Components and Interfaces

### Core Components

#### 1. Cache Module (`src/cache.rs`)

```rust
use std::collections::HashMap;
use std::sync::{OnceLock, RwLock};

static CACHE: OnceLock<RwLock<HashMap<CrcParamsCacheKey, [u64; 23]>>> = OnceLock::new();

pub fn get_or_generate_keys(width: u8, poly: u64, reflected: bool) -> [u64; 23]
pub fn clear_cache() // For testing and memory management
```

#### 2. Cache Key Structure

```rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct CrcParamsCacheKey {
width: u8,
poly: u64,
reflected: bool,
}
```

#### 3. Modified CrcParams Implementation

The existing `CrcParams::new()` method will be updated to use the cache:

```rust
impl CrcParams {
pub fn new(
name: &'static str,
width: u8,
poly: u64,
init: u64,
reflected: bool,
xorout: u64,
check: u64,
) -> Self {
let keys = cache::get_or_generate_keys(width, poly, reflected);

let algorithm = match width {
32 => CrcAlgorithm::Crc32Custom,
64 => CrcAlgorithm::Crc64Custom,
_ => panic!("Unsupported width: {}", width),
};

Self {
algorithm,
name,
width,
poly,
init,
refin: reflected,
refout: reflected,
xorout,
check,
keys,
}
}
}
```

### Interface Design

#### Public Interface
- No changes to existing public APIs
- `CrcParams::new()` maintains identical signature and behavior
- Cache operations are completely internal

#### Internal Interface
- `cache::get_or_generate_keys()` - Primary cache interface
- `cache::clear_cache()` - For testing and memory management
- Cache key creation and hashing handled internally

## Data Models

### Cache Key Model
```rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct CrcParamsCacheKey {
width: u8, // CRC width (32 or 64)
poly: u64, // Polynomial value
reflected: bool, // Reflection mode
}
```

### Cache Storage Model
```rust
type CacheStorage = HashMap<CrcParamsCacheKey, [u64; 23]>;
type ThreadSafeCache = RwLock<CacheStorage>;
```

### Memory Layout Considerations
- Cache keys: ~17 bytes per entry (8 + 8 + 1 bytes + HashMap overhead)
- Cache values: 184 bytes per entry (23 × 8 bytes)
- Total per entry: ~201 bytes + HashMap overhead
- Expected usage: 1-10 unique parameter sets in typical applications (single parameter set most common)

## Error Handling

### Cache Access Errors
- **RwLock Poisoning**: If a thread panics while holding the write lock, subsequent accesses will fall back to direct key generation
- **Memory Allocation**: HashMap growth failures will be handled by Rust's standard allocation error handling

### Fallback Strategy
```rust
fn get_or_generate_keys(width: u8, poly: u64, reflected: bool) -> [u64; 23] {
let cache_key = CrcParamsCacheKey { width, poly, reflected };

// Try cache read first
if let Ok(cache) = get_cache().read() {
if let Some(keys) = cache.get(&cache_key) {
return *keys;
}
}

// Generate keys outside of write lock to minimize lock hold time
let keys = generate::keys(width, poly, reflected);

// Try to cache the result (best effort)
if let Ok(mut cache) = get_cache().write() {
cache.insert(cache_key, keys);
}

keys
}
```

### Error Recovery
- Lock poisoning: Continue with direct key generation
- Memory pressure: Cache operations become no-ops, functionality preserved
- Hash collisions: Handled by HashMap implementation

## Testing Strategy

### Unit Tests
1. **Cache Functionality**
- Verify cache hits return identical keys
- Verify cache misses generate and store keys
- Test cache key equality and hashing

2. **Thread Safety**
- Concurrent read access tests
- Read-write contention tests
- Cache consistency under concurrent access

3. **Performance Tests**
- Benchmark cache hit vs. miss performance
- Memory usage validation
- Comparison with uncached implementation

4. **Edge Cases**
- Empty cache behavior
- Cache with single entry
- Maximum realistic cache size
- Lock poisoning recovery

### Integration Tests
1. **API Compatibility**
- Existing CrcParams::new() behavior unchanged
- All existing tests continue to pass
- Identical results for cached vs. uncached keys

2. **Real-world Usage Patterns**
- Multiple CrcParams instances with same parameters
- Mixed usage with different parameters
- Long-running application simulation

### Performance Benchmarks
1. **Cache Hit Performance**: Measure lookup time vs. key generation time
2. **Cache Miss Performance**: Measure overhead of cache check + generation
3. **Memory Usage**: Track cache memory consumption over time
4. **Concurrent Access**: Measure performance under thread contention

## Implementation Phases

### Phase 1: Core Cache Implementation
- Create cache module with basic HashMap storage
- Implement thread-safe access with RwLock
- Add cache key structure and hashing

### Phase 2: Integration
- Modify CrcParams::new() to use cache
- Add fallback error handling
- Ensure API compatibility

### Phase 3: Testing and Optimization
- Comprehensive test suite
- Performance benchmarking
- Memory usage optimization
- Documentation updates

## Performance Considerations

### Cache Hit Performance
- Expected improvement: 50-100x faster than key generation
- RwLock read access: ~10-20ns overhead
- HashMap lookup: O(1) average case, ~50-100ns

### Cache Miss Performance
- Additional overhead: ~100-200ns for cache check
- Write lock acquisition: ~50-100ns
- HashMap insertion: O(1) average case

### Memory Efficiency
- Cache overhead per entry: ~201 bytes
- Expected cache size: 200 bytes - 2KB for typical applications
- Memory growth: Linear with unique parameter combinations

### Thread Contention
- Read-heavy workload: Excellent scalability
- Write contention: Minimal impact (writes are rare after warmup)
- Lock-free reads: Multiple threads can read simultaneously

## Security Considerations

### Memory Safety
- All cache operations use safe Rust constructs
- No unsafe code in cache implementation
- HashMap provides memory safety guarantees

### Thread Safety
- RwLock prevents data races
- Cache key immutability prevents modification after creation
- Atomic operations for cache initialization

### Resource Management
- Cache growth is bounded by unique parameter combinations
- No automatic eviction policy (acceptable for typical usage)
- Manual cache clearing available for memory management
57 changes: 57 additions & 0 deletions .kiro/specs/crc-params-caching/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Requirements Document

## Introduction

This feature adds a caching layer to the `CrcParams::new()` method to optimize performance when the same CRC parameters are used multiple times during program execution. Currently, each call to `CrcParams::new()` regenerates the folding keys through expensive mathematical operations, even when identical parameters have been used before. The caching system will store generated keys in memory and reuse them for subsequent requests with matching parameters, significantly improving performance for applications that create multiple CRC instances with the same configuration.

## Requirements

### Requirement 1

**User Story:** As a developer using the crc-fast library, I want CrcParams::new() to cache generated keys so that repeated calls with identical parameters don't regenerate keys unnecessarily.

#### Acceptance Criteria

1. WHEN CrcParams::new() is called with parameters that have been used before THEN the system SHALL return cached keys instead of regenerating them
2. WHEN CrcParams::new() is called with new parameters for the first time THEN the system SHALL generate the keys and cache them for future use
3. WHEN multiple threads call CrcParams::new() concurrently with the same parameters THEN the system SHALL handle thread safety correctly without data races

### Requirement 2

**User Story:** As a performance-conscious developer, I want the caching mechanism to have minimal overhead so that it doesn't negatively impact single-use scenarios.

#### Acceptance Criteria

1. WHEN CrcParams::new() is called for the first time with any parameters THEN the performance overhead SHALL be minimal compared to the current implementation
2. WHEN CrcParams::new() is called with cached parameters THEN the lookup SHALL be significantly faster than key generation
3. WHEN the cache is accessed THEN the lookup mechanism SHALL use efficient data structures optimized for the expected access patterns

### Requirement 3

**User Story:** As a developer working with custom CRC parameters, I want the cache to correctly identify identical parameter sets so that functionally equivalent calls are properly cached.

#### Acceptance Criteria

1. WHEN two CrcParams::new() calls use identical values for all parameters (name, width, poly, init, reflected, xorout, check) THEN the system SHALL treat them as cache hits
2. WHEN two CrcParams::new() calls differ in any parameter value THEN the system SHALL treat them as separate cache entries
3. WHEN parameter comparison is performed THEN the system SHALL use all relevant fields to determine cache key uniqueness

### Requirement 4

**User Story:** As a developer concerned about memory usage, I want the cache to have reasonable memory management so that it doesn't grow unbounded in long-running applications.

#### Acceptance Criteria

1. WHEN the cache stores parameter sets THEN it SHALL use memory-efficient storage for the cache keys and values
2. WHEN the application runs for extended periods THEN the cache SHALL not consume excessive memory for typical usage patterns
3. IF the cache grows large THEN the system SHALL provide a way to clear or manage cache size (though automatic eviction is not required for this initial implementation)

### Requirement 5

**User Story:** As a developer integrating this library, I want the caching to be transparent so that existing code continues to work without modifications.

#### Acceptance Criteria

1. WHEN existing code calls CrcParams::new() THEN it SHALL work exactly as before with no API changes required
2. WHEN CrcParams instances are created THEN they SHALL have identical behavior regardless of whether keys came from cache or generation
3. WHEN the caching system is active THEN it SHALL not affect the public interface or return values of CrcParams::new()
Loading
Loading