private static MemoryInfoResult GetMemoryInfoLinux(SmapsReader smapsReader, bool extended) { var fromProcMemInfo = new ProcMemInfoResults(); GetFromProcMemInfo(smapsReader, ref fromProcMemInfo); var totalPhysicalMemoryInBytes = fromProcMemInfo.TotalMemory.GetValue(SizeUnit.Bytes); var cgroupMemoryLimit = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMemoryLimit); var cgroupMaxMemoryUsage = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMaxMemoryUsage); // here we need to deal with _soft_ limit, so we'll take the largest of these values var maxMemoryUsage = Math.Max(cgroupMemoryLimit ?? 0, cgroupMaxMemoryUsage ?? 0); if (maxMemoryUsage != 0 && maxMemoryUsage <= totalPhysicalMemoryInBytes) { // running in a limited cgroup var commitedMemoryInBytes = 0L; var cgroupMemoryUsage = LowMemoryNotification.Instance.UseTotalDirtyMemInsteadOfMemUsage // RDBS-45 ? fromProcMemInfo.TotalDirty.GetValue(SizeUnit.Bytes) : KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMemoryUsage); if (cgroupMemoryUsage != null) { commitedMemoryInBytes = cgroupMemoryUsage.Value; fromProcMemInfo.Commited.Set(commitedMemoryInBytes, SizeUnit.Bytes); fromProcMemInfo.MemAvailable.Set(maxMemoryUsage - cgroupMemoryUsage.Value, SizeUnit.Bytes); var realAvailable = maxMemoryUsage - cgroupMemoryUsage.Value + fromProcMemInfo.SharedCleanMemory.GetValue(SizeUnit.Bytes); if (realAvailable < 0) { realAvailable = 0; } fromProcMemInfo.AvailableWithoutTotalCleanMemory.Set(realAvailable, SizeUnit.Bytes); } fromProcMemInfo.TotalMemory.Set(maxMemoryUsage, SizeUnit.Bytes); fromProcMemInfo.CommitLimit.Set(Math.Max(maxMemoryUsage, commitedMemoryInBytes), SizeUnit.Bytes); } var workingSet = new Size(0, SizeUnit.Bytes); if (smapsReader != null) { // extended info is needed workingSet.Set(GetRssMemoryUsage(), SizeUnit.Bytes); } return(BuildPosixMemoryInfoResult( fromProcMemInfo.MemAvailable, fromProcMemInfo.TotalMemory, fromProcMemInfo.Commited, fromProcMemInfo.CommitLimit, fromProcMemInfo.AvailableWithoutTotalCleanMemory, fromProcMemInfo.SharedCleanMemory, workingSet, extended)); }
internal static bool GetFromProcMemInfo(SmapsReader smapsReader, ref ProcMemInfoResults procMemInfoResults) { const string path = "/proc/meminfo"; // this is different then sysinfo freeram+buffered (and the closest to the real free memory) // MemFree is really different then MemAvailable (while free is usually lower then the real free, // and available is only estimated free which sometimes higher then the real free memory) // for some distros we have only MemFree try { using (var bufferedReader = new KernelVirtualFileSystemUtils.BufferedPosixKeyValueOutputValueReader(path)) { bufferedReader.ReadFileIntoBuffer(); var memAvailableInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemAvailable); var memFreeInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemFree); var totalMemInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemTotal); var swapTotalInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(SwapTotal); var commitedInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(Committed_AS); var totalClean = new Size(memAvailableInKb, SizeUnit.Kilobytes); var totalDirty = new Size(0, SizeUnit.Bytes); var sharedCleanMemory = new Size(0, SizeUnit.Bytes); if (smapsReader != null) { var result = smapsReader.CalculateMemUsageFromSmaps <SmapsReaderNoAllocResults>(); totalClean.Add(result.SharedClean, SizeUnit.Bytes); totalClean.Add(result.PrivateClean, SizeUnit.Bytes); sharedCleanMemory.Set(result.SharedClean, SizeUnit.Bytes); totalDirty.Add(result.TotalDirty, SizeUnit.Bytes); } procMemInfoResults.MemAvailable = new Size(Math.Max(memAvailableInKb, memFreeInKb), SizeUnit.Kilobytes); procMemInfoResults.TotalMemory = new Size(totalMemInKb, SizeUnit.Kilobytes); procMemInfoResults.Commited = new Size(commitedInKb, SizeUnit.Kilobytes); // on Linux, we use the swap + ram as the commit limit, because the actual limit // is dependent on many different factors procMemInfoResults.CommitLimit = new Size(totalMemInKb + swapTotalInKb, SizeUnit.Kilobytes); procMemInfoResults.AvailableWithoutTotalCleanMemory = totalClean; procMemInfoResults.SharedCleanMemory = sharedCleanMemory; procMemInfoResults.TotalDirty = totalDirty; } } catch (Exception ex) { if (Logger.IsInfoEnabled) { Logger.Info($"Failed to read value from {path}", ex); } return(false); } return(true); }
private static MemoryInfoResult GetMemoryInfoLinux(SmapsReader smapsReader, bool extended) { var fromProcMemInfo = new ProcMemInfoResults(); GetFromProcMemInfo(smapsReader, ref fromProcMemInfo); var totalPhysicalMemoryInBytes = fromProcMemInfo.TotalMemory.GetValue(SizeUnit.Bytes); var cgroupMemoryLimit = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMemoryLimit); var cgroupMaxMemoryUsage = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMaxMemoryUsage); // here we need to deal with _soft_ limit, so we'll take the largest of these values var maxMemoryUsage = Math.Max(cgroupMemoryLimit ?? 0, cgroupMaxMemoryUsage ?? 0); if (maxMemoryUsage != 0 && maxMemoryUsage <= totalPhysicalMemoryInBytes) { // running in a limited cgroup var commitedMemoryInBytes = 0L; var cgroupMemoryUsage = LowMemoryNotification.Instance.UseTotalDirtyMemInsteadOfMemUsage // RDBS-45 ? fromProcMemInfo.TotalDirty.GetValue(SizeUnit.Bytes) : KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMemoryUsage); if (cgroupMemoryUsage != null) { commitedMemoryInBytes = cgroupMemoryUsage.Value; fromProcMemInfo.Commited.Set(commitedMemoryInBytes, SizeUnit.Bytes); fromProcMemInfo.AvailableMemory.Set(maxMemoryUsage - cgroupMemoryUsage.Value, SizeUnit.Bytes); var realAvailable = maxMemoryUsage - cgroupMemoryUsage.Value + fromProcMemInfo.SharedCleanMemory.GetValue(SizeUnit.Bytes); if (realAvailable < 0) { realAvailable = 0; } fromProcMemInfo.AvailableMemoryForProcessing.Set(realAvailable, SizeUnit.Bytes); } fromProcMemInfo.TotalMemory.Set(maxMemoryUsage, SizeUnit.Bytes); fromProcMemInfo.CommitLimit.Set(Math.Max(maxMemoryUsage, commitedMemoryInBytes), SizeUnit.Bytes); } var workingSet = new Size(0, SizeUnit.Bytes); var swapUsage = new Size(0, SizeUnit.Bytes); if (smapsReader != null) { // extended info is needed var procStatus = GetMemoryUsageFromProcStatus(); workingSet.Set(procStatus.Rss, SizeUnit.Bytes); swapUsage.Set(procStatus.Swap, SizeUnit.Bytes); } SetMemoryRecords(fromProcMemInfo.AvailableMemoryForProcessing.GetValue(SizeUnit.Bytes)); return(new MemoryInfoResult { TotalCommittableMemory = fromProcMemInfo.CommitLimit, CurrentCommitCharge = fromProcMemInfo.Commited, AvailableMemory = fromProcMemInfo.AvailableMemory, AvailableMemoryForProcessing = fromProcMemInfo.AvailableMemoryForProcessing, SharedCleanMemory = fromProcMemInfo.SharedCleanMemory, TotalPhysicalMemory = fromProcMemInfo.TotalMemory, InstalledMemory = fromProcMemInfo.TotalMemory, WorkingSet = workingSet, TotalSwapSize = fromProcMemInfo.TotalSwap, TotalSwapUsage = swapUsage, WorkingSetSwapUsage = fromProcMemInfo.WorkingSetSwap, IsExtended = extended }); }
private static bool GetFromProcMemInfo(SmapsReader smapsReader, ref ProcMemInfoResults procMemInfoResults) { const string path = "/proc/meminfo"; // this is different then sysinfo freeram+buffered (and the closest to the real free memory) // MemFree is really different then MemAvailable (while free is usually lower then the real free, // and available is only estimated free which sometimes higher then the real free memory) // for some distros we have only MemFree try { using (var bufferedReader = new KernelVirtualFileSystemUtils.BufferedPosixKeyValueOutputValueReader(path)) { bufferedReader.ReadFileIntoBuffer(); var memAvailableInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemAvailable); var memFreeInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemFree); var totalMemInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(MemTotal); var swapTotalInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(SwapTotal); var commitedInKb = bufferedReader.ExtractNumericValueFromKeyValuePairsFormattedFile(Committed_AS); var totalClean = new Size(0, SizeUnit.Kilobytes); var totalDirty = new Size(0, SizeUnit.Bytes); var sharedCleanMemory = new Size(0, SizeUnit.Bytes); var swapWorkingSet = new Size(0, SizeUnit.Bytes); if (smapsReader != null) { var result = smapsReader.CalculateMemUsageFromSmaps <SmapsReaderNoAllocResults>(); totalClean.Add(result.SharedClean, SizeUnit.Bytes); totalClean.Add(result.PrivateClean, SizeUnit.Bytes); sharedCleanMemory.Set(result.SharedClean, SizeUnit.Bytes); totalDirty.Add(result.TotalDirty, SizeUnit.Bytes); swapWorkingSet.Add(result.Swap, SizeUnit.Bytes); } procMemInfoResults.AvailableMemory = new Size(memFreeInKb, SizeUnit.Kilobytes); procMemInfoResults.TotalMemory = new Size(totalMemInKb, SizeUnit.Kilobytes); procMemInfoResults.Commited = new Size(commitedInKb, SizeUnit.Kilobytes); // on Linux, we use the swap + ram as the commit limit, because the actual limit // is dependent on many different factors procMemInfoResults.CommitLimit = new Size(totalMemInKb + swapTotalInKb, SizeUnit.Kilobytes); // AvailableMemoryForProcessing: AvailableMemory actually does add reclaimable memory (divided by 2), so if AvailableMemory is equal or lower then the _real_ available memory // If it is lower the the real value because of RavenDB's Clean memory - then we use 'totalClean' as reference // Otherwise - either it is correct value, or it is lower because of (clean or dirty memory of) another process var availableMemoryForProcessing = new Size(Math.Max(memAvailableInKb, memFreeInKb), SizeUnit.Kilobytes); procMemInfoResults.AvailableMemoryForProcessing = Size.Max(availableMemoryForProcessing, totalClean); procMemInfoResults.SharedCleanMemory = sharedCleanMemory; procMemInfoResults.TotalDirty = totalDirty; procMemInfoResults.TotalSwap = new Size(swapTotalInKb, SizeUnit.Kilobytes); procMemInfoResults.WorkingSetSwap = swapWorkingSet; } } catch (Exception ex) { if (Logger.IsInfoEnabled) { Logger.Info($"Failed to read value from {path}", ex); } return(false); } return(true); }