Exemple #1
0
        internal CacheEntryBase(MinidumpSegment segmentData, int derivedMinSize, Action <uint> updateOwningCacheForAddedChunk)
        {
            _segmentData = segmentData;

            int pageCount = (int)((_segmentData.End - _segmentData.VirtualAddress) / EntryPageSize);

            if (((int)(_segmentData.End - _segmentData.VirtualAddress) % EntryPageSize) != 0)
            {
                pageCount++;
            }

            _pages     = new CachePage <T> [pageCount];
            _pageLocks = new ReaderWriterLockSlim[pageCount];
            for (int i = 0; i < _pageLocks.Length; i++)
            {
                _pageLocks[i] = new ReaderWriterLockSlim();
            }

            _minSize = 4 * UIntPtr.Size +                   /*our four fields that are refrence type fields (pages, pageLocks, segmentData, and updateOwningCacheForAddedChunk)*/
                       2 * (_pages.Length * UIntPtr.Size) + /*The array of cache pages and matching size array of locks */
                       2 * sizeof(uint) +                   /*entrySize and minSize fields*/
                       sizeof(long) /*lastAccessTickCount field*/ +
                       derivedMinSize /*size added from our derived classes bookkeeping overhead*/;

            _entrySize = _minSize;

            _updateOwningCacheForAddedChunk = updateOwningCacheForAddedChunk;

            UpdateLastAccessTickCount();
        }
Exemple #2
0
        internal ArrayPoolBasedCacheEntry(MemoryMappedFile mappedFile, MinidumpSegment segmentData, Action <ulong, uint> updateOwningCacheForAddedChunk)
        {
            _mappedFile  = mappedFile;
            _segmentData = segmentData;

            int pageCount = (int)((segmentData.End - segmentData.VirtualAddress) / PageSize);

            if (((int)(segmentData.End - segmentData.VirtualAddress) % PageSize) != 0)
            {
                pageCount++;
            }

            _dataChunks     = new CachePage[pageCount];
            _dataChunkLocks = new ReaderWriterLockSlim[pageCount];
            for (int i = 0; i < _dataChunkLocks.Length; i++)
            {
                _dataChunkLocks[i] = new ReaderWriterLockSlim();
            }

            MinSize = (6 * UIntPtr.Size) +                      /*our six fields that are reference type fields (updateOwningCacheForAddedChunk, disposeQueue, mappedFile, segmentData, dataChunkLocks, dataChunks)*/
                      (_dataChunks.Length * UIntPtr.Size) +     /*The array of data chunks (each element being a pointer)*/
                      (_dataChunkLocks.Length * UIntPtr.Size) + /*The array of locks for our data chunks*/
                      sizeof(int) +                             /*accessCount field*/
                      sizeof(uint) +                            /*entrySize field*/
                      sizeof(long) /*lastAccessTickCount field*/;

            _entrySize = MinSize;

            _updateOwningCacheForAddedChunk = updateOwningCacheForAddedChunk;

            IncrementAccessCount();
            UpdateLastAccessTickCount();
        }
        private int GetSegmentContaining(ulong address)
        {
            int result = -1;
            int lower  = 0;
            int upper  = _segments.Length - 1;

            while (lower <= upper)
            {
                int             mid = (lower + upper) >> 1;
                MinidumpSegment seg = _segments[mid];

                if (seg.Contains(address))
                {
                    result = mid;
                    break;
                }

                if (address < seg.VirtualAddress)
                {
                    upper = mid - 1;
                }
                else
                {
                    lower = mid + 1;
                }
            }

            return(result);
        }
Exemple #4
0
        internal AWEBasedCacheEntry(MinidumpSegment segmentData, Action <ulong, uint> updateOwningCacheForSizeChangeCallback, UIntPtr pageFrameArray, int pageFrameArrayItemCount)
        {
            int pagesSize = (int)(segmentData.Size / VirtualAllocPageSize);

            if ((segmentData.Size % VirtualAllocPageSize) != 0)
            {
                pagesSize++;
            }

            _pages     = new CachePage[pagesSize];
            _pageLocks = new ReaderWriterLockSlim[pagesSize];
            for (int i = 0; i < _pageLocks.Length; i++)
            {
                _pageLocks[i] = new ReaderWriterLockSlim();
            }

            MinSize = (_pages.Length * UIntPtr.Size) +            /*size of pages array*/
                      (_pageLocks.Length * UIntPtr.Size) +        /*size of pageLocks array*/
                      (_pageFrameArrayItemCount * UIntPtr.Size) + /*size of pageFrameArray*/
                      (5 * IntPtr.Size) +                         /*size of reference type fields (updateOwningCacheForSizeChangeCallback, segmentData, pageFrameArray, pageLocks, pages)*/
                      (2 * sizeof(int)) +                         /*size of int fields (pageFrameArrayItemCount, accessSize)*/
                      sizeof(uint) +                              /*size of uint field (accessCount)*/
                      sizeof(long);                               /*size of long field (lasAccessTickCount)*/

            _segmentData = segmentData;
            _updateOwningCacheForSizeChangeCallback = updateOwningCacheForSizeChangeCallback;
            _pageFrameArray          = pageFrameArray;
            _pageFrameArrayItemCount = pageFrameArrayItemCount;

            _entrySize = MinSize;

            IncrementAccessCount();
            UpdateLastAccessTickCount();
        }
        public SegmentCacheEntry CreateAndAddEntry(MinidumpSegment segment)
        {
            SegmentCacheEntry entry = _entryFactory.CreateEntryForSegment(segment, UpdateOverallCacheSizeForAddedChunk);

            _cacheLock.EnterWriteLock();
            try
            {
                // Check the cache again now that we have acquired the write lock
                if (_cache.TryGetValue(segment.VirtualAddress, out SegmentCacheEntry? existingEntry))
                {
                    // Someone else beat us to adding this entry, clean up the entry we created and return the existing one
                    using (entry as IDisposable)
                        return(existingEntry);
                }

                _cache.Add(segment.VirtualAddress, entry);
            }
            finally
            {
                _cacheLock.ExitWriteLock();
            }

            Interlocked.Add(ref _cacheSize, entry.CurrentSize);
            TrimCacheIfOverLimit(segment.VirtualAddress);

            return(entry);
        }
        public override int Read(ulong address, Span <byte> buffer)
        {
            if (address == 0)
            {
                return(0);
            }

            lock (_sync)
            {
                try
                {
                    int bytesRead = 0;

                    while (bytesRead < buffer.Length)
                    {
                        ulong currAddress = address + (uint)bytesRead;
                        int   curr        = GetSegmentContaining(currAddress);
                        if (curr == -1)
                        {
                            break;
                        }

                        MinidumpSegment seg    = _segments[curr];
                        ulong           offset = currAddress - seg.VirtualAddress;

                        Span <byte> slice = buffer.Slice(bytesRead, Math.Min(buffer.Length - bytesRead, (int)(seg.Size - offset)));
                        _stream.Position = (long)(seg.FileOffset + offset);
                        int read = _stream.Read(slice);
                        if (read == 0)
                        {
                            break;
                        }

                        bytesRead += read;
                    }

                    return(bytesRead);
                }
                catch (IOException)
                {
                    return(0);
                }
            }
        }
Exemple #7
0
        public SegmentCacheEntry CreateAndAddEntry(MinidumpSegment segment)
        {
            ThrowIfDisposed();

            if (_cacheIsComplete)
            {
                throw new InvalidOperationException($"You cannot call {nameof(CreateAndAddEntry)} after having called {nameof(CreateAndAddEntry)} enough times to cause the entry count to rise to {_entryCountWhenFull}, which was given to the ctor as the largest possible size");
            }

            SegmentCacheEntry entry = _entryFactory.CreateEntryForSegment(segment, UpdateOverallCacheSizeForAddedChunk);

            if (!_cacheIsFullyPopulatedBeforeUse)
            {
                _cacheLock.EnterWriteLock();
            }

            try
            {
                // Check the cache again now that we have acquired the write lock
                if (_cache.TryGetValue(segment.VirtualAddress, out SegmentCacheEntry existingEntry))
                {
                    // Someone else beat us to adding this entry, clean up the entry we created and return the existing one
                    using (entry as IDisposable)
                        return(existingEntry);
                }

                _cache.Add(segment.VirtualAddress, entry);
                _cacheIsComplete = (_cache.Count == _entryCountWhenFull);
            }
            finally
            {
                if (!_cacheIsFullyPopulatedBeforeUse)
                {
                    _cacheLock.ExitWriteLock();
                }
            }

            Interlocked.Add(ref _cacheSize, entry.CurrentSize);
            TrimCacheIfOverLimit();

            return(entry);
        }
Exemple #8
0
        public bool Read(ulong address, Span <byte> buffer, out int bytesRead)
        {
            lock (_sync)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(nameof(MinidumpMemoryReader));
                }

                try
                {
                    bytesRead = 0;

                    while (bytesRead < buffer.Length)
                    {
                        ulong currAddress = address + (uint)bytesRead;
                        int   curr        = GetSegmentContaining(currAddress);
                        if (curr == -1)
                        {
                            break;
                        }

                        ref MinidumpSegment seg = ref _segments[curr];
                        ulong offset            = currAddress - seg.VirtualAddress;

                        Span <byte> slice = buffer.Slice(bytesRead, Math.Min(buffer.Length - bytesRead, (int)(seg.Size - offset)));
                        _stream.Position = (long)(seg.FileOffset + offset);
                        int read = _stream.Read(slice);
                        if (read == 0)
                        {
                            break;
                        }

                        bytesRead += read;
                    }

                    return(bytesRead > 0);
                }
 internal AWEBasedCacheEntry(MinidumpSegment segmentData, Action <uint> updateOwningCacheForSizeChangeCallback, UIntPtr pageFrameArray, int pageFrameArrayItemCount) : base(segmentData, derivedMinSize: UIntPtr.Size + (pageFrameArrayItemCount * UIntPtr.Size) + sizeof(int), updateOwningCacheForSizeChangeCallback)
 {
     _pageFrameArray          = pageFrameArray;
     _pageFrameArrayItemCount = pageFrameArrayItemCount;
 }
Exemple #10
0
 public abstract SegmentCacheEntry CreateEntryForSegment(MinidumpSegment segmentData, Action <uint> updateOwningCacheForSizeChangeCallback);
 public override SegmentCacheEntry CreateEntryForSegment(MinidumpSegment segmentData, Action <uint> updateOwningCacheForSizeChangeCallback)
 {
     return(new ArrayPoolBasedCacheEntry(_mappedFile, segmentData, updateOwningCacheForSizeChangeCallback));
 }
        public override SegmentCacheEntry CreateEntryForSegment(MinidumpSegment segmentData, Action <ulong, uint> updateOwningCacheForSizeChangeCallback)
        {
            bool setFPRes = CacheNativeMethods.File.SetFilePointerEx(_dumpFileHandle, (long)segmentData.FileOffset, SeekOrigin.Begin);

            if (!setFPRes)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            uint numberOfPages = (uint)(segmentData.Size / (ulong)Environment.SystemPageSize);

            if ((segmentData.Size % (ulong)Environment.SystemPageSize) != 0)
            {
                numberOfPages++;
            }

            uint    bytesNeededForPageArray       = numberOfPages * (uint)IntPtr.Size;
            UIntPtr pageFrameArray                = CacheNativeMethods.Memory.HeapAlloc(bytesNeededForPageArray);
            uint    numberOfPagesAllocated        = numberOfPages;
            bool    handedAllocationsToCacheEntry = false;

            // Allocate the physical memory for our pages and store the mapping data into our page frame array
            try
            {
                // Allocate the physical memory, this claims this much physical memory but it does not yet count against our process usage limits
                bool physicalAllocRes = CacheNativeMethods.AWE.AllocateUserPhysicalPages(ref numberOfPagesAllocated, pageFrameArray);
                if (!physicalAllocRes)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                if (numberOfPagesAllocated != numberOfPages)
                {
                    throw new OutOfMemoryException("Failed to allocate the required number of pages for segment in AWE based cache.");
                }

                UIntPtr reservedMemory = UIntPtr.Zero;
                try
                {
                    // Now reserve a chunk of VM equivalent in size to the physical memory, this will now count against our process usage limits, but ony temporarily
                    reservedMemory = _sharedSegment != UIntPtr.Zero ? _sharedSegment : CacheNativeMethods.Memory.VirtualAlloc((uint)segmentData.Size,
                                                                                                                              CacheNativeMethods.Memory.VirtualAllocType.Reserve | CacheNativeMethods.Memory.VirtualAllocType.Physical,
                                                                                                                              CacheNativeMethods.Memory.MemoryProtection.ReadWrite);

                    // Now assign our previously reserved physical memory to the VM range we just reserved
                    bool mapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(reservedMemory, numberOfPages, pageFrameArray);
                    if (!mapPhysicalPagesResult)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    // Now that the physical memory is mapped into our VM space, fill it with data from the heap segment from the dump
                    bool readFileRes = CacheNativeMethods.File.ReadFile(_dumpFileHandle, reservedMemory, (uint)segmentData.Size, out uint bytesRead);
                    if (!readFileRes)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    // Now for the magic, this line unmaps the physical memory from our process, it still counts against our process limits (until the VirtualFree below). Once we
                    // VirtualFree it below the memory 'cost' still is assigned to our process BUT it doesn't count against our resource limits until/unless we map it back into the VM space.
                    // BUT, most importatnly, the physical memory remains and contains the data we read from the file.
                    bool unmapPhysicalPagesResult = CacheNativeMethods.AWE.MapUserPhysicalPages(reservedMemory, numberOfPages, UIntPtr.Zero);
                    if (!unmapPhysicalPagesResult)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    if (_sharedSegment != reservedMemory)
                    {
                        // Free the virtual memory we were using to map the physical memory. NOTE: sizeToFree must be 0 when we are calling with VirtualFreeType.Release
                        bool virtualFreeRes = CacheNativeMethods.Memory.VirtualFree(reservedMemory, sizeToFree: UIntPtr.Zero, CacheNativeMethods.Memory.VirtualFreeType.Release);
                        if (!virtualFreeRes)
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }

                    reservedMemory = UIntPtr.Zero;

                    // Now give our page frame table to the AWE cache node so it can map the memory back into our VM as needed
                    handedAllocationsToCacheEntry = true;
                    return(new AWEBasedCacheEntry(segmentData, updateOwningCacheForSizeChangeCallback, pageFrameArray, (int)numberOfPages));
                }
                finally
                {
                    // Something failed, clean up if we allocated memory
                    if (!handedAllocationsToCacheEntry && (reservedMemory != UIntPtr.Zero) && (_sharedSegment != reservedMemory))
                    {
                        CacheNativeMethods.Memory.VirtualFree(reservedMemory, UIntPtr.Zero, CacheNativeMethods.Memory.VirtualFreeType.Release);
                    }
                }
            }
            finally
            {
                // Something failed, clean up
                if (!handedAllocationsToCacheEntry)
                {
                    CacheNativeMethods.AWE.FreeUserPhysicalPages(ref numberOfPagesAllocated, pageFrameArray);
                }
            }
        }
Exemple #13
0
 internal ArrayPoolBasedCacheEntry(MemoryMappedFile mappedFile, MinidumpSegment segmentData, Action <uint> updateOwningCacheForAddedChunk) : base(segmentData, derivedMinSize: 2 * IntPtr.Size, updateOwningCacheForAddedChunk)
 {
     _mappedFile = mappedFile;
 }