Example #1
0
        public static bool CanIncreaseMemoryUsageForThread()
        {
            var memoryInfo = MemoryInformation.GetMemInfoUsingOneTimeSmapsReader();
            var memoryAssumedFreeOrCheapToFree = memoryInfo.AvailableWithoutTotalCleanMemory;
            var allocatedForProcessing         = GetTotalCurrentlyAllocatedForProcessing();

            return(memoryAssumedFreeOrCheapToFree >= allocatedForProcessing);
        }
Example #2
0
        public static bool TryIncreasingMemoryUsageForThread(NativeMemory.ThreadStats threadStats,
                                                             ref Size currentMaximumAllowedMemory,
                                                             Size currentlyInUse,
                                                             bool isRunningOn32Bits,
                                                             Logger logger,
                                                             out ProcessMemoryUsage currentUsage)
        {
            if (isRunningOn32Bits)
            {
                currentUsage = null;
                return(false);
            }

            // we run out our memory quota, so we need to see if we can increase it or break
            var memoryInfoResult = MemoryInformation.GetMemInfoUsingOneTimeSmapsReader();

            using (GetProcessMemoryUsage(out currentUsage, out var mappedSharedMem))
            {
                var memoryAssumedFreeOrCheapToFree = memoryInfoResult.AvailableWithoutTotalCleanMemory;

                // there isn't enough available memory to try, we want to leave some out for other things
                if (memoryAssumedFreeOrCheapToFree <
                    Size.Min(memoryInfoResult.TotalPhysicalMemory / 50, new Size(1, SizeUnit.Gigabytes)))
                {
                    if (logger.IsInfoEnabled)
                    {
                        logger.Info(
                            $"{threadStats.Name} which is already using {currentlyInUse}/{currentMaximumAllowedMemory} and the system has " +
                            $"{memoryInfoResult.AvailableWithoutTotalCleanMemory}/{memoryInfoResult.TotalPhysicalMemory} free RAM. Also have ~{mappedSharedMem} in mmap " +
                            "files that can be cleanly released, not enough to proceed in batch.");
                    }

                    return(false);
                }

                // If there isn't enough here to double our current allocation, we won't allocate any more
                // we do this check in this way to prevent multiple indexes of hitting this at the
                // same time and each thinking that they have enough space
                if (memoryAssumedFreeOrCheapToFree < currentMaximumAllowedMemory)
                {
                    if (logger.IsInfoEnabled)
                    {
                        logger.Info(
                            $"{threadStats} which is already using {currentlyInUse}/{currentMaximumAllowedMemory} and the system has" +
                            $"{memoryInfoResult.AvailableWithoutTotalCleanMemory}/{memoryInfoResult.TotalPhysicalMemory} free RAM. Also have ~{mappedSharedMem} in mmap " +
                            "files that can be cleanly released, not enough to proceed in batch.");
                    }
                    return(false);
                }

                // even though we have twice as much memory as we have current allocated, we will
                // only increment by 16MB to avoid over allocation by multiple indexes. This way,
                // we'll check often as we go along this
                var oldBudget = currentMaximumAllowedMemory;
                currentMaximumAllowedMemory = currentlyInUse + new Size(16, SizeUnit.Megabytes);

                if (logger.IsInfoEnabled)
                {
                    logger.Info(
                        $"Increasing memory budget for {threadStats.Name} which is using  {currentlyInUse}/{oldBudget} and the system has" +
                        $"{memoryInfoResult.AvailableWithoutTotalCleanMemory}/{memoryInfoResult.TotalPhysicalMemory} free RAM with {mappedSharedMem} in mmap " +
                        $"files that can be cleanly released. Budget increased to {currentMaximumAllowedMemory}");
                }

                return(true);
            }
        }
Example #3
0
        private static DynamicJsonValue MemoryStatsInternal()
        {
            using (var currentProcess = Process.GetCurrentProcess())
            {
                var workingSet = PlatformDetails.RunningOnLinux == false
                        ? currentProcess.WorkingSet64
                        : MemoryInformation.GetRssMemoryUsage(currentProcess.Id);

                var memInfo = MemoryInformation.GetMemInfoUsingOneTimeSmapsReader();

                long totalMapping          = 0;
                var  fileMappingByDir      = new Dictionary <string, Dictionary <string, ConcurrentDictionary <IntPtr, long> > >();
                var  fileMappingSizesByDir = new Dictionary <string, long>();
                foreach (var mapping in NativeMemory.FileMapping)
                {
                    var dir = Path.GetDirectoryName(mapping.Key);

                    if (fileMappingByDir.TryGetValue(dir, out Dictionary <string, ConcurrentDictionary <IntPtr, long> > value) == false)
                    {
                        value = new Dictionary <string, ConcurrentDictionary <IntPtr, long> >();
                        fileMappingByDir[dir] = value;
                    }
                    value[mapping.Key] = mapping.Value;
                    foreach (var singleMapping in mapping.Value)
                    {
                        fileMappingSizesByDir.TryGetValue(dir, out long prevSize);
                        fileMappingSizesByDir[dir] = prevSize + singleMapping.Value;
                        totalMapping += singleMapping.Value;
                    }
                }

                var prefixLength = LongestCommonPrefixLength(new List <string>(fileMappingSizesByDir.Keys));

                var fileMappings = new DynamicJsonArray();
                foreach (var sizes in fileMappingSizesByDir.OrderByDescending(x => x.Value))
                {
                    if (fileMappingByDir.TryGetValue(sizes.Key, out Dictionary <string, ConcurrentDictionary <IntPtr, long> > value))
                    {
                        var details = new DynamicJsonValue();

                        var dir = new DynamicJsonValue
                        {
                            [nameof(MemoryInfoMappingItem.Directory)]                = sizes.Key.Substring(prefixLength),
                            [nameof(MemoryInfoMappingItem.TotalDirectorySize)]       = sizes.Value,
                            [nameof(MemoryInfoMappingItem.HumaneTotalDirectorySize)] = Size.Humane(sizes.Value),
                            [nameof(MemoryInfoMappingItem.Details)] = details
                        };
                        foreach (var file in value.OrderBy(x => x.Key))
                        {
                            long totalMapped = 0;
                            var  dja         = new DynamicJsonArray();
                            var  dic         = new Dictionary <long, long>();
                            foreach (var mapping in file.Value)
                            {
                                totalMapped += mapping.Value;
                                dic.TryGetValue(mapping.Value, out long prev);
                                dic[mapping.Value] = prev + 1;
                            }
                            foreach (var maps in dic)
                            {
                                dja.Add(new DynamicJsonValue
                                {
                                    [nameof(MemoryInfoMappingDetails.Size)]  = maps.Key,
                                    [nameof(MemoryInfoMappingDetails.Count)] = maps.Value
                                });
                            }
                            var fileSize = GetFileSize(file.Key);
                            details[Path.GetFileName(file.Key)] = new DynamicJsonValue
                            {
                                [nameof(MemoryInfoMappingFileInfo.FileSize)]          = fileSize,
                                [nameof(MemoryInfoMappingFileInfo.HumaneFileSize)]    = Size.Humane(fileSize),
                                [nameof(MemoryInfoMappingFileInfo.TotalMapped)]       = totalMapped,
                                [nameof(MemoryInfoMappingFileInfo.HumaneTotalMapped)] = Size.Humane(totalMapped),
                                [nameof(MemoryInfoMappingFileInfo.Mappings)]          = dja
                            };
                        }
                        fileMappings.Add(dir);
                    }
                }

                long totalUnmanagedAllocations = 0;
                var  threads = new DynamicJsonArray();
                foreach (var stats in NativeMemory.AllThreadStats
                         .Where(x => x.IsThreadAlive())
                         .GroupBy(x => x.Name)
                         .OrderByDescending(x => x.Sum(y => y.TotalAllocated)))
                {
                    var unmanagedAllocations = stats.Sum(x => x.TotalAllocated);
                    totalUnmanagedAllocations += unmanagedAllocations;
                    var ids = new DynamicJsonArray(stats.OrderByDescending(x => x.TotalAllocated).Select(x => new DynamicJsonValue
                    {
                        ["Id"] = x.UnmanagedThreadId,
                        ["ManagedThreadId"]   = x.Id,
                        ["Allocations"]       = x.TotalAllocated,
                        ["HumaneAllocations"] = Size.Humane(x.TotalAllocated)
                    }));
                    var groupStats = new DynamicJsonValue
                    {
                        ["Name"]              = stats.Key,
                        ["Allocations"]       = unmanagedAllocations,
                        ["HumaneAllocations"] = Size.Humane(unmanagedAllocations)
                    };
                    if (ids.Count == 1)
                    {
                        var threadStats = stats.First();
                        groupStats["Id"] = threadStats.UnmanagedThreadId;
                        groupStats["ManagedThreadId"] = threadStats.Id;
                    }
                    else
                    {
                        groupStats["Ids"] = ids;
                    }
                    threads.Add(groupStats);
                }
                var managedMemory = GC.GetTotalMemory(false);
                var djv           = new DynamicJsonValue
                {
                    [nameof(MemoryInfo.WorkingSet)] = workingSet,
                    [nameof(MemoryInfo.TotalUnmanagedAllocations)] = totalUnmanagedAllocations,
                    [nameof(MemoryInfo.ManagedAllocations)]        = managedMemory,
                    [nameof(MemoryInfo.TotalMemoryMapped)]         = totalMapping,
                    [nameof(MemoryInfo.PhysicalMem)]           = Size.Humane(memInfo.TotalPhysicalMemory.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.FreeMem)]               = Size.Humane(memInfo.CalculatedAvailableMemory.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.HighMemLastOneMinute)]  = Size.Humane(memInfo.MemoryUsageRecords.High.LastOneMinute.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.LowMemLastOneMinute)]   = Size.Humane(memInfo.MemoryUsageRecords.Low.LastOneMinute.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.HighMemLastFiveMinute)] = Size.Humane(memInfo.MemoryUsageRecords.High.LastFiveMinutes.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.LowMemLastFiveMinute)]  = Size.Humane(memInfo.MemoryUsageRecords.Low.LastFiveMinutes.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.HighMemSinceStartup)]   = Size.Humane(memInfo.MemoryUsageRecords.High.SinceStartup.GetValue(SizeUnit.Bytes)),
                    [nameof(MemoryInfo.LowMemSinceStartup)]    = Size.Humane(memInfo.MemoryUsageRecords.Low.SinceStartup.GetValue(SizeUnit.Bytes)),

                    [nameof(MemoryInfo.Humane)] = new DynamicJsonValue
                    {
                        [nameof(MemoryInfoHumane.WorkingSet)] = Size.Humane(workingSet),
                        [nameof(MemoryInfoHumane.TotalUnmanagedAllocations)] = Size.Humane(totalUnmanagedAllocations),
                        [nameof(MemoryInfoHumane.ManagedAllocations)]        = Size.Humane(managedMemory),
                        [nameof(MemoryInfoHumane.TotalMemoryMapped)]         = Size.Humane(totalMapping)
                    },

                    ["Threads"] = threads,

                    [nameof(MemoryInfo.Mappings)] = fileMappings
                };
                return(djv);
            }
        }