/// <summary> /// Initializes a new instance of the <see cref="SnapshotElementIndexer" /> class. /// </summary> /// <param name="region">The parent region that contains this element.</param> /// <param name="elementIndex">The index of the element to begin pointing to.</param> public unsafe SnapshotElementIndexer( SnapshotRegion region, Int32 elementIndex = 0) { this.Region = region; this.ElementIndex = elementIndex; }
/// <summary> /// Merges regions in the current list of memory regions using a fast stack based algorithm O(nlogn + n). /// </summary> private void MergeAndSortRegions() { if (this.SnapshotRegions.IsNullOrEmpty()) { return; } // First, sort by start address IEnumerable <SnapshotRegion> sortedRegions = this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64()); // Create and initialize the stack with the first region Stack <SnapshotRegion> combinedRegions = new Stack <SnapshotRegion>(); combinedRegions.Push(sortedRegions.First()); // Build the remaining regions foreach (SnapshotRegion region in sortedRegions.Skip(1)) { SnapshotRegion top = combinedRegions.Peek(); // If the regions do not overlap, the new region is the top region if (top.EndAddress.ToUInt64() < region.BaseAddress.ToUInt64()) { combinedRegions.Push(region); } // The regions are exactly adjacent; merge them else if (top.EndAddress.ToUInt64() == region.BaseAddress.ToUInt64()) { top.RegionSize = region.EndAddress.Subtract(top.BaseAddress).ToUInt64(); // Combine values and labels top.SetElementLabels(top.ElementLabels?.Concat(region.ElementLabels)); top.SetCurrentValues(top.CurrentValues?.Concat(region.CurrentValues)); top.SetPreviousValues(top.PreviousValues?.Concat(region.PreviousValues)); } // The regions overlap else if (top.EndAddress.ToUInt64() <= region.EndAddress.ToUInt64()) { top.RegionSize = region.EndAddress.Subtract(top.BaseAddress).ToUInt64(); Int32 overlapSize = unchecked ((Int32)(region.EndAddress.ToUInt64() - top.EndAddress.ToUInt64())); // Overlap has conflicting values, so we prioritize the top region and trim the current region region.SetElementLabels(region.ElementLabels?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); region.SetCurrentValues(region.CurrentValues?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); region.SetPreviousValues(region.PreviousValues?.SubArray(overlapSize, region.RegionSize.ToInt32() - overlapSize)); // Combine values and labels top.SetElementLabels(top.ElementLabels?.Concat(region.ElementLabels)); top.SetCurrentValues(top.CurrentValues?.Concat(region.CurrentValues)); top.SetPreviousValues(top.PreviousValues?.Concat(region.PreviousValues)); } } this.SnapshotRegions = combinedRegions.ToList().OrderBy(x => x.BaseAddress.ToUInt64()).ToList(); }
/// <summary> /// Indexer to allow the retrieval of the element at the specified index. Notes: This does NOT index into a region. /// </summary> /// <param name="elementIndex">The index of the snapshot element.</param> /// <returns>Returns the snapshot element at the specified index.</returns> public SnapshotElementIndexer this[UInt64 elementIndex] { get { SnapshotRegion region = this.BinaryRegionSearch(elementIndex); if (region == null) { return(null); } return(region[(elementIndex - region.BaseElementIndex).ToInt32()]); } }
/// <summary> /// Initializes a new instance of the <see cref="SnapshotElementComparer" /> class. /// </summary> /// <param name="region">The parent region that contains this element.</param> /// <param name="elementIndex">The index of the element to begin pointing to.</param> /// <param name="compareActionConstraint">The constraint to use for the element quick action.</param> /// <param name="compareActionValue">The value to use for the element quick action.</param> /// <param name="pointerIncrementMode">The method by which to increment element pointers.</param> public unsafe SnapshotElementComparer( SnapshotRegion region, PointerIncrementMode pointerIncrementMode, ScanConstraintManager scanConstraintManager) { this.Region = region; // The garbage collector can relocate variables at runtime. Since we use unsafe pointers, we need to keep these pinned this.CurrentValuesHandle = GCHandle.Alloc(this.Region.ReadGroup.CurrentValues, GCHandleType.Pinned); this.PreviousValuesHandle = GCHandle.Alloc(this.Region.ReadGroup.PreviousValues, GCHandleType.Pinned); this.InitializePointers(); this.SetConstraintFunctions(); this.SetPointerFunction(pointerIncrementMode); this.SetCompareAction(scanConstraintManager); }
/// <summary> /// Initializes a new instance of the <see cref="SnapshotElementVectorComparer" /> class. /// </summary> /// <param name="region">The parent region that contains this element.</param> /// <param name="vectorSize">The size of vectors on the system.</param> /// <param name="scanConstraints">The set of constraints to use for the element comparisons.</param> public unsafe SnapshotElementVectorComparer( SnapshotRegion region, ScanConstraintManager scanConstraints) { this.Region = region; this.VectorSize = EngineCore.GetInstance().Architecture.GetVectorSize(); this.VectorReadBase = this.Region.ReadGroupOffset - this.Region.ReadGroupOffset % this.VectorSize; this.VectorReadIndex = 0; this.DataTypeSize = Conversions.SizeOf(this.Region.ReadGroup.ElementDataType); // Initialize capacity to 1/16 elements this.ResultRegions = new List <SnapshotRegion>(unchecked ((Int32)(this.Region.ElementCount)) / 16); this.SetConstraintFunctions(); this.SetCompareAction(scanConstraints); }
/// <summary> /// Gets the regions in this snapshot with a valid bit set. /// </summary> /// <returns>The regions in this snapshot with a valid bit set.</returns> public IEnumerable <SnapshotRegion> GetValidRegions() { List <SnapshotRegion> validRegions = new List <SnapshotRegion>(); Int32 elementSize = this.GetElementSize(); if (this.ValidBits == null) { return(validRegions); } for (Int32 startIndex = 0; startIndex < this.ValidBits.Length; startIndex += this.Alignment) { if (!this.ValidBits[startIndex]) { continue; } // Get the length of this valid segment Int32 validRegionSize = 0; do { // We only care if the aligned elements are valid validRegionSize += elementSize; }while (startIndex + validRegionSize < this.ValidBits.Length && this.ValidBits[startIndex + validRegionSize]); // Create new subregion from this valid region SnapshotRegion subRegion = new SnapshotRegion(this.BaseAddress + startIndex, validRegionSize.ToUInt64()); // Ensure region size is worth keeping. This can happen if we grab a misaligned segment if (subRegion.RegionSize < Conversions.GetTypeSize(this.ElementType).ToUInt64()) { continue; } // Copy the current values and labels. subRegion.SetCurrentValues(this.CurrentValues.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); subRegion.SetPreviousValues(this.PreviousValues.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); subRegion.SetElementLabels(this.ElementLabels.LargestSubArray(startIndex, subRegion.RegionSize.ToInt64())); validRegions.Add(subRegion); startIndex += validRegionSize; } this.ValidBits = null; return(validRegions); }
/// <summary> /// Initializes a new instance of the <see cref="SnapshotElementIterator" /> class. /// </summary> /// <param name="parent">The parent region that contains this element.</param> /// <param name="elementIndex">The index of the element to begin pointing to.</param> /// <param name="compareActionConstraint">The constraint to use for the element quick action.</param> /// <param name="compareActionValue">The value to use for the element quick action.</param> /// <param name="pointerIncrementMode">The method by which to increment element pointers.</param> public unsafe SnapshotElementIterator( SnapshotRegion parent, Int32 elementIndex = 0, PointerIncrementMode pointerIncrementMode = PointerIncrementMode.AllPointers, ConstraintsEnum compareActionConstraint = ConstraintsEnum.Changed, Object compareActionValue = null) { this.Parent = parent; // The garbage collector can relocate variables at runtime. Since we use unsafe pointers, we need to keep these pinned this.CurrentValuesHandle = GCHandle.Alloc(this.Parent.CurrentValues, GCHandleType.Pinned); this.PreviousValuesHandle = GCHandle.Alloc(this.Parent.PreviousValues, GCHandleType.Pinned); this.InitializePointers(elementIndex); this.SetConstraintFunctions(); this.SetPointerFunction(pointerIncrementMode); this.SetCompareAction(compareActionConstraint, compareActionValue); }
/// <summary> /// Combines the given memory regions with the given memory regions, only keeping the common elements of the two in O(nlogn + n). /// </summary> /// <param name="otherSnapshot">The snapshot regions to mask the target regions against.</param> private void Intersect(Snapshot otherSnapshot) { List <SnapshotRegion> resultRegions = new List <SnapshotRegion>(); otherSnapshot.MergeAndSortRegions(); IEnumerable <NormalizedRegion> otherRegions = otherSnapshot.GetSnapshotRegions(); if (this.SnapshotRegions.IsNullOrEmpty() || otherRegions.IsNullOrEmpty()) { this.SnapshotRegions = resultRegions; return; } this.MergeAndSortRegions(); // Initialize stacks with regions and masking regions Queue <SnapshotRegion> snapshotRegionQueue = new Queue <SnapshotRegion>(); Queue <NormalizedRegion> groundTruthQueue = new Queue <NormalizedRegion>(); // Build candidate region queue from snapshot region array foreach (SnapshotRegion region in this.SnapshotRegions.OrderBy(x => x.BaseAddress.ToUInt64())) { snapshotRegionQueue.Enqueue(region); } // Build masking region queue from snapshot foreach (NormalizedRegion maskRegion in otherRegions.OrderBy(x => x.BaseAddress.ToUInt64())) { groundTruthQueue.Enqueue(maskRegion); } if (snapshotRegionQueue.Count <= 0 || groundTruthQueue.Count <= 0) { this.SnapshotRegions = resultRegions; return; } SnapshotRegion nextSnapshotRegion; NormalizedRegion groundTruthMask = groundTruthQueue.Dequeue(); while (snapshotRegionQueue.Count > 0) { // Grab next region nextSnapshotRegion = snapshotRegionQueue.Dequeue(); // Grab the next mask following the current region while (groundTruthMask.EndAddress.ToUInt64() < nextSnapshotRegion.BaseAddress.ToUInt64() && groundTruthQueue.Count > 0) { groundTruthMask = groundTruthQueue.Dequeue(); } // Check for mask completely removing this region if (groundTruthMask.EndAddress.ToUInt64() < nextSnapshotRegion.BaseAddress.ToUInt64() || groundTruthMask.BaseAddress.ToUInt64() > nextSnapshotRegion.EndAddress.ToUInt64()) { continue; } // Check for mask completely engulfing this region else if (groundTruthMask.BaseAddress.ToUInt64() <= nextSnapshotRegion.BaseAddress.ToUInt64() && groundTruthMask.EndAddress.ToUInt64() >= nextSnapshotRegion.EndAddress.ToUInt64()) { resultRegions.Add(nextSnapshotRegion); continue; } // There are no edge cases, we must mask and copy the valid portion of this region else { UInt64 baseAddress = Math.Max(groundTruthMask.BaseAddress.ToUInt64(), nextSnapshotRegion.BaseAddress.ToUInt64()); UInt64 endAddress = Math.Min(groundTruthMask.EndAddress.ToUInt64(), nextSnapshotRegion.EndAddress.ToUInt64()); Int64 baseOffset = unchecked ((Int64)(baseAddress - nextSnapshotRegion.BaseAddress.ToUInt64())); SnapshotRegion newRegion = new SnapshotRegion(nextSnapshotRegion as NormalizedRegion); newRegion.BaseAddress = baseAddress.ToIntPtr(); newRegion.EndAddress = endAddress.ToIntPtr(); newRegion.SetCurrentValues(nextSnapshotRegion.CurrentValues.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.SetPreviousValues(nextSnapshotRegion.PreviousValues.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.SetElementLabels(nextSnapshotRegion.ElementLabels.LargestSubArray(baseOffset, newRegion.RegionSize.ToInt64())); newRegion.ElementType = nextSnapshotRegion.ElementType; newRegion.Alignment = nextSnapshotRegion.Alignment; resultRegions.Add(newRegion); } } this.SnapshotRegions = resultRegions; }
/// <summary> /// Finalizes any leftover snapshot regions and returns them. /// </summary> public IList <SnapshotRegion> GatherCollectedRegions() { // Create the final region if we are still encoding if (this.Encoding) { this.ResultRegions.Add(new SnapshotRegion(this.Region.ReadGroup, this.VectorReadBase + this.VectorReadIndex - this.RunLength, this.RunLength)); this.RunLength = 0; this.Encoding = false; } // Remove vector misaligned leading regions SnapshotRegion firstRegion = this.ResultRegions.FirstOrDefault(); Int32 adjustedIndex = 0; while (firstRegion != null) { // Exit if not misaligned if (firstRegion.ReadGroupOffset >= this.Region.ReadGroupOffset) { break; } Int32 misalignment = this.Region.ReadGroupOffset - firstRegion.ReadGroupOffset; if (firstRegion.RegionSize <= misalignment) { // The region is totally eclipsed -- remove it this.ResultRegions.Remove(firstRegion); } else { // The region is partially eclipsed -- adjust the size firstRegion.ReadGroupOffset += misalignment; firstRegion.RegionSize -= misalignment; adjustedIndex++; } firstRegion = this.ResultRegions.Skip(adjustedIndex).FirstOrDefault(); } // Remove vector overreading trailing regions SnapshotRegion lastRegion = this.ResultRegions.LastOrDefault(); adjustedIndex = 0; while (lastRegion != null) { // Exit if not overreading if (lastRegion.EndAddress.ToUInt64() <= this.Region.EndAddress.ToUInt64()) { break; } Int32 overread = (lastRegion.EndAddress.ToUInt64() - this.Region.EndAddress.ToUInt64()).ToInt32(); if (lastRegion.RegionSize <= overread) { // The region is totally eclipsed -- remove it this.ResultRegions.Remove(lastRegion); } else { lastRegion.RegionSize -= overread; adjustedIndex++; } lastRegion = this.ResultRegions.Reverse().Skip(adjustedIndex).FirstOrDefault(); } return(this.ResultRegions); }