-
Notifications
You must be signed in to change notification settings - Fork 57
Optimize multidimensional arrays, 32-bit read/write, FastMap. #169
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
base: main
Are you sure you want to change the base?
Conversation
Code Review for PR #169: Optimize multidimensional arrays, 32-bit read/write, FastMapSummaryThis PR introduces significant performance optimizations including a new FastMap implementation, 32-bit platform optimizations, and improved multidimensional array serialization. Overall, the changes demonstrate strong performance awareness, but there are several issues that should be addressed before merging. 🔴 Critical Issues1. FastMap.cs - Memory Alignment and Safety IssuesUnaligned Access Concerns (Line 23-29) [StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct Entry
{
public uint HashCode; // Offset 0, aligned
public bool IsOccupied; // Offset 4, aligned
public TKey Key; // Offset 5, UNALIGNED!
public TValue Value; // Varies, UNALIGNED!
}The
Recommendation: Either remove [StructLayout(LayoutKind.Sequential)]
private struct Entry
{
public bool IsOccupied; // 1 byte + 3 bytes padding
public uint HashCode; // 4 bytes, aligned at offset 4
public TKey Key; // Properly aligned at offset 8
public TValue Value;
}Memory Leak in Remove() (Line 431-457) public bool Remove(TKey key)
{
// ...
entry1.IsOccupied = false; // ❌ Key and Value not cleared!
_count--;
_version++;
return true;
}Setting Recommendation: Clear the entry completely: entry1 = default;
entry1.IsOccupied = false;Infinite Recursion Risk (Line 347) if (!TryAdd(key, default))
throw new InvalidOperationException("Failed to add key to dictionary");
return ref GetValueRefOrAddDefault(key, out exists); // ❌ Recursive callIf Recommendation: Get the value reference directly after successful if (!TryAdd(key, default))
throw new InvalidOperationException("Failed to add key to dictionary");
// Return reference to the just-added key
var hashCode = key.GetHashCode();
hashCode ^= hashCode >> 16;
var index1 = hashCode & _capacityMask;
ref Entry entry1 = ref _table1[index1];
if (entry1.HashCode == hashCode && KeyComparer.Equals(entry1.Key, key))
{
exists = false;
return ref entry1.Value;
}
// Check table2...2. ArrayGenerator.cs - Integer Overflow RiskTotal Elements Calculation (Lines 143-149) int totalElements = len0 * len1 * len2; // ❌ Can overflow!With large array dimensions, this multiplication can silently overflow, leading to incorrect serialization or buffer overflows. Recommendation: Use checked arithmetic: int totalElements;
try
{
checked
{
totalElements = len0;
for (int i = 1; i < rank; i++)
totalElements *= len{i};
}
}
catch (OverflowException)
{
throw new InvalidOperationException("Array dimensions too large for serialization");
}🟡 Medium Priority Issues3. FastMap.cs - Missing Capacity Overflow CheckCalculateCapacity() (Lines 101-111) private static int CalculateCapacity(int capacity)
{
if (capacity < MinCapacity) return MinCapacity;
capacity--;
capacity |= capacity >> 1;
// ... bit manipulation
return capacity + 1; // ❌ Can overflow to negative!
}With very large input values (e.g., Recommendation: Add overflow check: if (capacity > (1 << 30))
throw new ArgumentOutOfRangeException(nameof(capacity), "Capacity too large");4. Reader.cs/Writer.cs - Platform Detection OverheadThe Recommendation: Use compile-time checks where possible or JIT-level optimization hints: [MethodImpl(MethodImplOptions.AggressiveOptimization)]5. ArrayGenerator.cs - Confusing NamingCachedSerializer.SerializePolymorphic (Lines 114, 263) The method name Recommendation: Rename to 🟢 Positive Observations
📋 Minor Issues & SuggestionsCode Quality
Security
Test Coverage
❓ Questions for Author
🎯 RecommendationRequest Changes - The critical memory alignment and safety issues in FastMap.cs should be addressed before merging. The integer overflow risk in ArrayGenerator.cs also needs attention. Once these are fixed, this will be an excellent performance improvement. Priority Action Items
Overall, this is ambitious and performance-conscious work. The core ideas are sound, but the implementation needs refinement for production use. Looking forward to seeing these issues addressed! |
Code Review for PR #169: Optimize multidimensional arrays, 32-bit read/write, FastMapThank you for this comprehensive optimization PR! This is a substantial improvement to Nino's performance characteristics. Below is my detailed review: 🎯 Overall AssessmentVerdict: Strong contribution with excellent performance optimizations. A few minor suggestions for consideration. Summary: This PR adds 1,035 lines and removes 223 lines across 5 files, focusing on:
✅ Code Quality & Best PracticesStrengths:
Suggestions:1. FastMap.cs - Missing null checks in hot paths (lines 61, 66)// Current code at lines 61-62:
if (entry1.HashCode == hashCode && KeyComparer.Equals(entry1.Key, key))Issue: If Recommendation: Add occupancy check before key comparison: if (entry1.IsOccupied && entry1.HashCode == hashCode && KeyComparer.Equals(entry1.Key, key))
return ref entry1.Value;2. FastMap.cs - Potential infinite recursion (line 347)public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists)
{
// ... code ...
else
{
if (!TryAdd(key, default))
throw new InvalidOperationException("Failed to add key to dictionary");
return ref GetValueRefOrAddDefault(key, out exists); // ⚠️ Recursion
}
}Issue: If Recommendation: After successful if (!TryAdd(key, default))
throw new InvalidOperationException("Failed to add key to dictionary");
// Key now exists, retrieve it directly
var hashCode = key.GetHashCode();
hashCode ^= hashCode >> 16;
var index1 = hashCode & _capacityMask;
ref Entry entry1 = ref _table1[index1];
if (entry1.IsOccupied && entry1.HashCode == hashCode && KeyComparer.Equals(entry1.Key, key))
{
exists = false;
return ref entry1.Value;
}
// Check table2...3. ArrayGenerator.cs - Code clarityThe monomorphic path optimization is excellent, but consider adding XML documentation comments to explain when 🐛 Potential BugsCritical:None identified - The code appears functionally sound. Minor:FastMap.cs line 147-148:var hashCode = key.GetHashCode();
hashCode ^= hashCode >> 16;Observation: This duplicates the Recommendation: Use the helper consistently: var hashCode = (uint)TransformHashCode(key.GetHashCode());Writer.cs lines 101-123:The 32-bit safe path uses a Question: Should there be validation that ⚡ Performance ConsiderationsExcellent Optimizations:
Suggestions:Reader.cs/Writer.cs - Conditional compilation overheadLines using
ArrayGenerator.cs - Memory allocationFor very large multidimensional arrays, consider:
🔒 Security ConcernsLow Risk - No critical issues foundInput Validation:
Potential DoS consideration:
Memory safety:
🧪 Test Coverage
|
Code Review for PR #169: Optimize multidimensional arrays, 32-bit read/write, FastMapThank you for your contribution! I've reviewed the changes in this PR based on the repository code and test coverage. Positive Aspects
Areas for Review1. New File: NinoMarshal.cs (114 lines)
2. ArrayGenerator.cs ModificationsMonomorphic Fast Path: The canUseMonomorphicPath optimization is only applied to 1D arrays. Is there a reason multi-dimensional arrays can't benefit from this? 32-bit Platform Considerations: Are the new optimizations tested on both 32-bit and 64-bit platforms? Have you verified unaligned write safety on 32-bit platforms? WEAK_VERSION_TOLERANCE Handling: Good optimization - unmanaged types don't need version tolerance overhead. Space Locality: The row-major iteration order naturally provides good cache locality. Good practice! 3. Potential IssuesArray Rank Mismatch Error: Verify string interpolation escaping is correct in generated exception messages. Recursive GetValueRefOrAddDefault (FastMap.cs:347): Could potentially cause infinite recursion. Consider adding a safeguard or comment. FastMap Pack=1: May cause unaligned memory access on ARM. Verify this works on Unity mobile targets. Testing Recommendations
Security Considerations
Documentation
Overall AssessmentSolid performance optimization with well-structured code and good test coverage. Address questions around NinoMarshal.cs purpose, 32-bit testing, integer overflow protection, and provide benchmark results. Review generated by Claude Code |
Pull Request Review: Optimize multidimensional arrays, 32-bit read/write, FastMapThank you for this comprehensive performance optimization PR! I have conducted a thorough review of the changes. ✅ Strengths1. Excellent 32-bit Platform Safety (Writer.cs:89-127)The refactored UnsafeWrite method shows excellent awareness of alignment issues on 32-bit platforms with proper size-aware switch statement and safe memory copy for 8+ byte values. 2. High-Performance FastMap Implementation (FastMap.cs)
3. Multidimensional Array Support (ArrayGenerator.cs)
4. Performance Optimizations (Reader.cs:394-410)
|
- Move FastMapNInt to its own file (FastMapNInt.cs) to fix namespace duplication - Fix GetValueRefOrAddDefault bug in FastMapNInt (exists parameter was overwritten) - Fix indentation inconsistencies in NinoMarshal.cs - Translate Chinese comments to English in ArrayGenerator.cs - Standardize variable naming (use len consistently instead of dim) - Add missing newlines at end of files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Optimize multidimensional arrays, 32-bit read/write, FastMap.