Пример #1
0
        private static MemoryInfoResult GetMemoryInfoLinux()
        {
            var fromProcMemInfo            = GetFromProcMemInfo();
            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     = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile(CgroupMemoryUsage);
                if (cgroupMemoryUsage != null)
                {
                    commitedMemoryInBytes = cgroupMemoryUsage.Value;
                    fromProcMemInfo.Commited.Set(commitedMemoryInBytes, SizeUnit.Bytes);
                    fromProcMemInfo.MemAvailable.Set(maxMemoryUsage - cgroupMemoryUsage.Value, SizeUnit.Bytes);
                }

                fromProcMemInfo.TotalMemory.Set(maxMemoryUsage, SizeUnit.Bytes);
                fromProcMemInfo.CommitLimit.Set(Math.Max(maxMemoryUsage, commitedMemoryInBytes), SizeUnit.Bytes);
            }

            return(BuildPosixMemoryInfoResult(
                       fromProcMemInfo.MemAvailable,
                       fromProcMemInfo.TotalMemory,
                       fromProcMemInfo.Commited,
                       fromProcMemInfo.CommitLimit));
        }
Пример #2
0
        public static string PosixIsSwappingOnHddInsteadOfSsd()
        {
            {
                var path = KernelVirtualFileSystemUtils.ReadSwapInformationFromSwapsFile();
                if (path == null) // on error return as if no swap problem
                {
                    return(null);
                }

                string foundRotationalDiskDrive = null;
                foreach (string partition in path)
                {
                    // remove numbers at end of string (i.e.: /dev/sda5 ==> sda)
                    var reg      = new System.Text.RegularExpressions.Regex(@"\d+$"); // we do not check swap file, only partitions
                    var disk     = reg.Replace(partition, "").Replace("/dev/", "");
                    var filename = $"/sys/block/{disk}/queue/rotational";
                    var isHdd    = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);


                    if (isHdd == -1)
                    {
                        return(null);
                    }
                    if (isHdd == 1)
                    {
                        foundRotationalDiskDrive = filename;
                    }
                    else if (isHdd != 0)
                    {
                        if (Log.IsOperationsEnabled)
                        {
                            Log.Operations($"Got invalid value (not 0 or 1) from {filename} = {isHdd}, assumes this is not a rotational disk");
                        }
                        foundRotationalDiskDrive = null;
                    }
                }

                string hddSwapsInsteadOfSsd = null;
                if (foundRotationalDiskDrive != null)
                {
                    // search if ssd drive is available
                    HashSet <string> disks = KernelVirtualFileSystemUtils.GetAllDisksFromPartitionsFile();
                    foreach (var disk in disks)
                    {
                        var filename = $"/sys/block/{disk}/queue/rotational";
                        var isHdd    = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);
                        if (isHdd == 0)
                        {
                            hddSwapsInsteadOfSsd = disk;
                            break;
                        }
                    }
                }

                return(hddSwapsInsteadOfSsd);
            }
        }
Пример #3
0
        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));
        }
Пример #4
0
        public void WriteAndReadPageUsingCryptoPager_WhenTwoSwapDefined_AllResultShouldBeNotNull()
        {
            var fileName = GetTempFileName();

            string[] lines =
            {
                "Filename				Type		Size	Used	Priority",
                "/dev/sda6                               partition	999420	56320	-2",
                "/dev/sdb7                               partition	999420	56320	-2"
            };
            System.IO.File.WriteAllLines(fileName, lines);

            var swap = KernelVirtualFileSystemUtils.ReadSwapInformationFromSwapsFile(fileName);

            Assert.All(swap, s => Assert.NotNull(s.DeviceName));
        }
Пример #5
0
        public static int GetProcessorCount()
        {
            if (PlatformDetails.RunningOnPosix == false)
            {
                return(Environment.ProcessorCount);
            }

            // on linux, if running in container, the number of cores might be set by either cpuset-cpus or cpus (cpus == cfs quota)
            // if not in container Environment.ProcessorCount is the value to be considered. So we read all the three values and return the lowest
            var cpussetCpusCores = KernelVirtualFileSystemUtils.ReadNumberOfCoresFromCgroupFile("/sys/fs/cgroup/cpuset/cpuset.cpus");
            var quota            = KernelVirtualFileSystemUtils.ReadNumberFromFile("/sys/fs/cgroup/cpu/cpu.cfs_quota_us");
            var period           = quota != long.MaxValue ? KernelVirtualFileSystemUtils.ReadNumberFromFile("/sys/fs/cgroup/cpu/cpu.cfs_period_us") : 0; // read from file only if quota read successful
            var cpusCore         = period != 0 ? quota / period : Environment.ProcessorCount;                                                            // note that we round down here ("2.5" processors quota will be read as "2")

            if (cpusCore == 0)                                                                                                                           // i.e. "0.5" processors quota
            {
                cpusCore = 1;
            }

            return(Math.Min(Environment.ProcessorCount, Math.Min((int)cpusCore, cpussetCpusCores)));
        }
Пример #6
0
        public static long GetRssMemoryUsage(int procId)
        {
            // currently Process.GetCurrentProcess().WorkingSet64 doesn't give the real RSS number
            // getting it from /proc/self/stat or statm can be also problematic because in some distros the number is in page size, in other pages, and position is not always guarenteed
            // however /proc/self/status gives the real number in humenly format. We extract this here:
            var path = $"/proc/{procId}/status";

            var vmRssString = KernelVirtualFileSystemUtils.ReadLineFromFile(path, "VmRSS");

            if (vmRssString == null)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Failed to read VmRSS from {path}");
                }
                return(0);
            }

            var parsedLine = vmRssString.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            if (parsedLine.Length != 3) // format should be: VmRss: <num> kb
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Failed to read VmRSS from {path}. Line was {parsedLine}");
                }
                return(0);
            }

            if (parsedLine[0].Contains("VmRSS:") == false)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Failed to find VmRSS from {path}. Line was {parsedLine}");
                }
                return(0);
            }

            long result;

            if (long.TryParse(parsedLine[1], out result) == false)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info($"Failed to parse VmRSS from {path}. Line was {parsedLine}");
                }
                return(0);
            }

            switch (parsedLine[2].ToLowerInvariant())
            {
            case "kb":
                result *= 1024L;
                break;

            case "mb":
                result *= 1024L * 1024;
                break;

            case "gb":
                result *= 1024L * 1024 * 1024;
                break;
            }

            return(result);
        }
Пример #7
0
        public static unsafe MemoryInfoResult GetMemoryInfo()
        {
            if (_failedToGetAvailablePhysicalMemory)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Because of a previous error in getting available memory, we are now lying and saying we have 256MB free");
                }
                return(FailedResult);
            }

            try
            {
                if (PlatformDetails.RunningOnPosix == false)
                {
                    // Windows
                    var memoryStatus = new MemoryStatusEx
                    {
                        dwLength = (uint)sizeof(MemoryStatusEx)
                    };
                    var result = GlobalMemoryStatusEx(&memoryStatus);
                    if (result == false)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from Windows, error code is: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    return(new MemoryInfoResult
                    {
                        AvailableMemory = new Size((long)memoryStatus.ullAvailPhys, SizeUnit.Bytes),
                        TotalPhysicalMemory = new Size((long)memoryStatus.ullTotalPhys, SizeUnit.Bytes),
                    });
                }

                // read both cgroup and sysinfo memory stats, and use the lowest if applicable
                var cgroupMemoryLimit = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.limit_in_bytes");
                var cgroupMemoryUsage = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.usage_in_bytes");

                ulong availableRamInBytes;
                ulong totalPhysicalMemoryInBytes;

                if (PlatformDetails.RunningOnMacOsx == false)
                {
                    // Linux
                    var info = new sysinfo_t();
                    if (Syscall.sysinfo(ref info) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from posix, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    availableRamInBytes        = info.AvailableRam;
                    totalPhysicalMemoryInBytes = info.TotalRam;
                }
                else
                {
                    // MacOS
                    var   mib            = new[] { (int)TopLevelIdentifiersMacOs.CTL_HW, (int)CtkHwIdentifiersMacOs.HW_MEMSIZE };
                    ulong physicalMemory = 0;
                    var   len            = sizeof(ulong);

                    if (Syscall.sysctl(mib, 2, &physicalMemory, &len, null, UIntPtr.Zero) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read physical memory info from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    totalPhysicalMemoryInBytes = physicalMemory;

                    uint pageSize;
                    var  vmStats = new vm_statistics64();

                    var machPort = Syscall.mach_host_self();
                    var count    = sizeof(vm_statistics64) / sizeof(uint);

                    if (Syscall.host_page_size(machPort, &pageSize) != 0 ||
                        Syscall.host_statistics64(machPort, (int)FlavorMacOs.HOST_VM_INFO64, &vmStats, &count) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to get vm_stats from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    availableRamInBytes = vmStats.FreePagesCount * (ulong)pageSize;
                }

                Size availableRam, totalPhysicalMemory;
                if (cgroupMemoryLimit < (long)totalPhysicalMemoryInBytes)
                {
                    availableRam        = new Size(cgroupMemoryLimit - cgroupMemoryUsage, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size(cgroupMemoryLimit, SizeUnit.Bytes);
                }
                else
                {
                    availableRam        = new Size((long)availableRamInBytes, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size((long)totalPhysicalMemoryInBytes, SizeUnit.Bytes);
                }

                return(new MemoryInfoResult
                {
                    AvailableMemory = availableRam,
                    TotalPhysicalMemory = totalPhysicalMemory
                });
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Error while trying to get available memory, will stop trying and report that there is 256MB free only from now on", e);
                }
                _failedToGetAvailablePhysicalMemory = true;
                return(FailedResult);
            }
        }
Пример #8
0
        public static string PosixIsSwappingOnHddInsteadOfSsd()
        {
            try
            {
                var swaps = KernelVirtualFileSystemUtils.ReadSwapInformationFromSwapsFile();
                if (swaps.Length == 0) // on error return as if no swap problem
                {
                    return(null);
                }

                string foundRotationalDiskDrive = null;
                for (int i = 0; i < swaps.Length; i++)
                {
                    if (swaps[i].IsDeviceSwapFile)
                    {
                        continue; // we do not check swap file, only partitions
                    }
                    // remove numbers at end of string (i.e.: /dev/sda5 ==> sda)
                    var disk     = _regExRemoveNumbers.Replace(swaps[i].DeviceName, "").Replace("/dev/", "");
                    var filename = $"/sys/block/{disk}/queue/rotational";
                    var isHdd    = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);

                    if (isHdd == -1)
                    {
                        return(null);
                    }
                    if (isHdd == 1)
                    {
                        foundRotationalDiskDrive = filename;
                    }
                    else if (isHdd != 0)
                    {
                        if (Log.IsOperationsEnabled)
                        {
                            Log.Operations($"Got invalid value (not 0 or 1) from {filename} = {isHdd}, assumes this is not a rotational disk");
                        }
                        foundRotationalDiskDrive = null;
                    }
                }

                string hddSwapsInsteadOfSsd = null;
                if (foundRotationalDiskDrive != null)
                {
                    // search if ssd drive is available
                    HashSet <string> disks = KernelVirtualFileSystemUtils.GetAllDisksFromPartitionsFile();
                    foreach (var disk in disks)
                    {
                        var filename = $"/sys/block/{disk}/queue/rotational";
                        var isHdd    = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);
                        if (isHdd == 0)
                        {
                            hddSwapsInsteadOfSsd = disk;
                            break;
                        }
                    }
                }

                return(hddSwapsInsteadOfSsd);
            }
            catch (Exception ex)
            {
                Log.Info("Error while trying to determine if hdd swaps instead of ssd on linux, ignoring this check and assuming no hddswap", ex);
                // ignore
                return(null);
            }
        }
Пример #9
0
        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
            });
        }
Пример #10
0
        public void WriteAndReadPageUsingCryptoPager_WhenCall_AllResultShouldBeNotNull()
        {
            var swap = KernelVirtualFileSystemUtils.ReadSwapInformationFromSwapsFile();

            Assert.All(swap, s => Assert.NotNull(s.DeviceName));
        }
Пример #11
0
        public static unsafe MemoryInfoResult GetMemoryInfo()
        {
            if (_failedToGetAvailablePhysicalMemory)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Because of a previous error in getting available memory, we are now lying and saying we have 256MB free");
                }
                return(FailedResult);
            }

            try
            {
                if (PlatformDetails.RunningOnPosix == false)
                {
                    // windows
                    var memoryStatus = new MemoryStatusEx
                    {
                        dwLength = (uint)sizeof(MemoryStatusEx)
                    };

                    if (GlobalMemoryStatusEx(&memoryStatus) == false)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from Windows, error code is: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    // The amount of physical memory retrieved by the GetPhysicallyInstalledSystemMemory function
                    // must be equal to or greater than the amount reported by the GlobalMemoryStatusEx function
                    // if it is less, the SMBIOS data is malformed and the function fails with ERROR_INVALID_DATA.
                    // Malformed SMBIOS data may indicate a problem with the user's computer.
                    var fetchedInstalledMemory = GetPhysicallyInstalledSystemMemory(out var installedMemoryInKb);

                    SetMemoryRecords((long)memoryStatus.ullAvailPhys);

                    return(new MemoryInfoResult
                    {
                        TotalCommittableMemory = new Size((long)memoryStatus.ullTotalPageFile, SizeUnit.Bytes),
                        CurrentCommitCharge = new Size((long)(memoryStatus.ullTotalPageFile - memoryStatus.ullAvailPageFile), SizeUnit.Bytes),
                        AvailableMemory = new Size((long)memoryStatus.ullAvailPhys, SizeUnit.Bytes),
                        TotalPhysicalMemory = new Size((long)memoryStatus.ullTotalPhys, SizeUnit.Bytes),
                        InstalledMemory = fetchedInstalledMemory ?
                                          new Size(installedMemoryInKb, SizeUnit.Kilobytes) :
                                          new Size((long)memoryStatus.ullTotalPhys, SizeUnit.Bytes),
                        MemoryUsageRecords = new MemoryInfoResult.MemoryUsageLowHigh
                        {
                            High = new MemoryInfoResult.MemoryUsageIntervals
                            {
                                LastOneMinute = new Size(HighLastOneMinute, SizeUnit.Bytes),
                                LastFiveMinutes = new Size(HighLastFiveMinutes, SizeUnit.Bytes),
                                SinceStartup = new Size(HighSinceStartup, SizeUnit.Bytes)
                            },
                            Low = new MemoryInfoResult.MemoryUsageIntervals
                            {
                                LastOneMinute = new Size(LowLastOneMinute, SizeUnit.Bytes),
                                LastFiveMinutes = new Size(LowLastFiveMinutes, SizeUnit.Bytes),
                                SinceStartup = new Size(LowSinceStartup, SizeUnit.Bytes)
                            }
                        }
                    });
                }

                // read both cgroup and sysinfo memory stats, and use the lowest if applicable
                var cgroupMemoryLimit = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.limit_in_bytes");
                var cgroupMemoryUsage = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.usage_in_bytes");

                ulong availableRamInBytes;
                ulong totalPhysicalMemoryInBytes;

                if (PlatformDetails.RunningOnMacOsx == false)
                {
                    // linux
                    int   rc       = 0;
                    ulong totalram = 0;
                    if (PlatformDetails.Is32Bits == false)
                    {
                        var info = new sysinfo_t();
                        rc       = Syscall.sysinfo(ref info);
                        totalram = info.TotalRam;
                    }
                    else
                    {
                        var info = new sysinfo_t_32bit();
                        rc       = Syscall.sysinfo(ref info);
                        totalram = info.TotalRam;
                    }
                    if (rc != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from posix, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    var availableAndFree = GetAvailableAndFreeMemoryFromProcMemInfo();

                    availableRamInBytes        = (ulong)availableAndFree.MemAvailable;
                    totalPhysicalMemoryInBytes = totalram;
                }
                else
                {
                    // macOS
                    var   mib            = new[] { (int)TopLevelIdentifiersMacOs.CTL_HW, (int)CtkHwIdentifiersMacOs.HW_MEMSIZE };
                    ulong physicalMemory = 0;
                    var   len            = sizeof(ulong);

                    if (Syscall.sysctl(mib, 2, &physicalMemory, &len, null, UIntPtr.Zero) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read physical memory info from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    totalPhysicalMemoryInBytes = physicalMemory;

                    uint pageSize;
                    var  vmStats = new vm_statistics64();

                    var machPort = Syscall.mach_host_self();
                    var count    = sizeof(vm_statistics64) / sizeof(uint);

                    if (Syscall.host_page_size(machPort, &pageSize) != 0 ||
                        Syscall.host_statistics64(machPort, (int)FlavorMacOs.HOST_VM_INFO64, &vmStats, &count) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to get vm_stats from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    availableRamInBytes = (vmStats.FreePagesCount + vmStats.InactivePagesCount) * (ulong)pageSize;
                }

                Size availableRam, totalPhysicalMemory;
                if (cgroupMemoryLimit < (long)totalPhysicalMemoryInBytes)
                {
                    availableRam        = new Size(cgroupMemoryLimit - cgroupMemoryUsage, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size(cgroupMemoryLimit, SizeUnit.Bytes);
                }
                else
                {
                    availableRam        = new Size((long)availableRamInBytes, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size((long)totalPhysicalMemoryInBytes, SizeUnit.Bytes);
                }

                SetMemoryRecords((long)availableRamInBytes);

                var commitAsAndCommitLimit = GetCommitAsAndCommitLimitFromProcMemInfo();

                return(new MemoryInfoResult
                {
                    TotalCommittableMemory = new Size(commitAsAndCommitLimit.CommitLimit, SizeUnit.Kilobytes),
                    CurrentCommitCharge = new Size(commitAsAndCommitLimit.Committed_AS, SizeUnit.Kilobytes),

                    AvailableMemory = availableRam,
                    TotalPhysicalMemory = totalPhysicalMemory,
                    InstalledMemory = totalPhysicalMemory,
                    MemoryUsageRecords = new MemoryInfoResult.MemoryUsageLowHigh
                    {
                        High = new MemoryInfoResult.MemoryUsageIntervals
                        {
                            LastOneMinute = new Size(HighLastOneMinute, SizeUnit.Bytes),
                            LastFiveMinutes = new Size(HighLastFiveMinutes, SizeUnit.Bytes),
                            SinceStartup = new Size(HighSinceStartup, SizeUnit.Bytes)
                        },
                        Low = new MemoryInfoResult.MemoryUsageIntervals
                        {
                            LastOneMinute = new Size(LowLastOneMinute, SizeUnit.Bytes),
                            LastFiveMinutes = new Size(LowLastFiveMinutes, SizeUnit.Bytes),
                            SinceStartup = new Size(LowSinceStartup, SizeUnit.Bytes)
                        }
                    }
                });
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Error while trying to get available memory, will stop trying and report that there is 256MB free only from now on", e);
                }
                _failedToGetAvailablePhysicalMemory = true;
                return(FailedResult);
            }
        }
Пример #12
0
        public static unsafe MemoryInfoResult GetMemoryInfo()
        {
            if (_failedToGetAvailablePhysicalMemory)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Because of a previous error in getting available memory, we are now lying and saying we have 256MB free");
                }
                return(FailedResult);
            }

            try
            {
                if (PlatformDetails.RunningOnPosix == false)
                {
                    // windows
                    var memoryStatus = new MemoryStatusEx
                    {
                        dwLength = (uint)sizeof(MemoryStatusEx)
                    };

                    if (GlobalMemoryStatusEx(&memoryStatus) == false)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from Windows, error code is: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    if (GetPhysicallyInstalledSystemMemory(out var installedMemoryInKb) == false)
                    {
                        installedMemoryInKb = (long)memoryStatus.ullTotalPhys;
                    }

                    SetMemoryRecords((long)memoryStatus.ullAvailPhys);

                    return(new MemoryInfoResult
                    {
                        AvailableMemory = new Size((long)memoryStatus.ullAvailPhys, SizeUnit.Bytes),
                        TotalPhysicalMemory = new Size((long)memoryStatus.ullTotalPhys, SizeUnit.Bytes),
                        InstalledMemory = new Size(installedMemoryInKb, SizeUnit.Kilobytes),
                        MemoryUsageRecords = new MemoryInfoResult.MemoryUsageLowHigh
                        {
                            High = new MemoryInfoResult.MemoryUsageIntervals
                            {
                                LastOneMinute = new Size(HighLastOneMinute, SizeUnit.Bytes),
                                LastFiveMinutes = new Size(HighLastFiveMinutes, SizeUnit.Bytes),
                                SinceStartup = new Size(HighSinceStartup, SizeUnit.Bytes)
                            },
                            Low = new MemoryInfoResult.MemoryUsageIntervals
                            {
                                LastOneMinute = new Size(LowLastOneMinute, SizeUnit.Bytes),
                                LastFiveMinutes = new Size(LowLastFiveMinutes, SizeUnit.Bytes),
                                SinceStartup = new Size(LowSinceStartup, SizeUnit.Bytes)
                            }
                        }
                    });
                }

                // read both cgroup and sysinfo memory stats, and use the lowest if applicable
                var cgroupMemoryLimit = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.limit_in_bytes");
                var cgroupMemoryUsage = KernelVirtualFileSystemUtils.ReadNumberFromCgroupFile("/sys/fs/cgroup/memory/memory.usage_in_bytes");

                ulong availableRamInBytes;
                ulong totalPhysicalMemoryInBytes;

                if (PlatformDetails.RunningOnMacOsx == false)
                {
                    // linux
                    var info = new sysinfo_t();
                    if (Syscall.sysinfo(ref info) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read memory info from posix, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    availableRamInBytes        = (ulong)GetAvailableMemoryFromProcMemInfo();
                    totalPhysicalMemoryInBytes = info.TotalRam;
                }
                else
                {
                    // macOS
                    var   mib            = new[] { (int)TopLevelIdentifiersMacOs.CTL_HW, (int)CtkHwIdentifiersMacOs.HW_MEMSIZE };
                    ulong physicalMemory = 0;
                    var   len            = sizeof(ulong);

                    if (Syscall.sysctl(mib, 2, &physicalMemory, &len, null, UIntPtr.Zero) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to read physical memory info from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    totalPhysicalMemoryInBytes = physicalMemory;

                    uint pageSize;
                    var  vmStats = new vm_statistics64();

                    var machPort = Syscall.mach_host_self();
                    var count    = sizeof(vm_statistics64) / sizeof(uint);

                    if (Syscall.host_page_size(machPort, &pageSize) != 0 ||
                        Syscall.host_statistics64(machPort, (int)FlavorMacOs.HOST_VM_INFO64, &vmStats, &count) != 0)
                    {
                        if (Logger.IsInfoEnabled)
                        {
                            Logger.Info("Failure when trying to get vm_stats from MacOS, error code was: " + Marshal.GetLastWin32Error());
                        }
                        return(FailedResult);
                    }

                    availableRamInBytes = (vmStats.FreePagesCount + vmStats.InactivePagesCount) * (ulong)pageSize;
                }

                Size availableRam, totalPhysicalMemory;
                if (cgroupMemoryLimit < (long)totalPhysicalMemoryInBytes)
                {
                    availableRam        = new Size(cgroupMemoryLimit - cgroupMemoryUsage, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size(cgroupMemoryLimit, SizeUnit.Bytes);
                }
                else
                {
                    availableRam        = new Size((long)availableRamInBytes, SizeUnit.Bytes);
                    totalPhysicalMemory = new Size((long)totalPhysicalMemoryInBytes, SizeUnit.Bytes);
                }

                SetMemoryRecords((long)availableRamInBytes);

                return(new MemoryInfoResult
                {
                    AvailableMemory = availableRam,
                    TotalPhysicalMemory = totalPhysicalMemory,
                    //TODO: http://issues.hibernatingrhinos.com/issue/RavenDB-8468
                    InstalledMemory = totalPhysicalMemory,
                    MemoryUsageRecords = new MemoryInfoResult.MemoryUsageLowHigh
                    {
                        High = new MemoryInfoResult.MemoryUsageIntervals
                        {
                            LastOneMinute = new Size(HighLastOneMinute, SizeUnit.Bytes),
                            LastFiveMinutes = new Size(HighLastFiveMinutes, SizeUnit.Bytes),
                            SinceStartup = new Size(HighSinceStartup, SizeUnit.Bytes)
                        },
                        Low = new MemoryInfoResult.MemoryUsageIntervals
                        {
                            LastOneMinute = new Size(LowLastOneMinute, SizeUnit.Bytes),
                            LastFiveMinutes = new Size(LowLastFiveMinutes, SizeUnit.Bytes),
                            SinceStartup = new Size(LowSinceStartup, SizeUnit.Bytes)
                        }
                    }
                });
            }
            catch (Exception e)
            {
                if (Logger.IsInfoEnabled)
                {
                    Logger.Info("Error while trying to get available memory, will stop trying and report that there is 256MB free only from now on", e);
                }
                _failedToGetAvailablePhysicalMemory = true;
                return(FailedResult);
            }
        }
Пример #13
0
        public static string PosixIsSwappingOnHddInsteadOfSsd()
        {
            try
            {
                var swaps = KernelVirtualFileSystemUtils.ReadSwapInformationFromSwapsFile();
                if (swaps.Length == 0) // on error return as if no swap problem
                {
                    return(null);
                }

                const string sysBlockDirectoryPath = "/sys/block/";

                var blocks = Directory
                             .GetDirectories(sysBlockDirectoryPath)
                             .Select(x => x.Substring(sysBlockDirectoryPath.Length))
                             .Where(x => x.StartsWith("loop") == false)
                             .ToList();

                if (blocks.Count == 0)
                {
                    return(null);
                }

                string foundRotationalDiskDrive = null;
                for (int i = 0; i < swaps.Length; i++)
                {
                    if (swaps[i].IsDeviceSwapFile)
                    {
                        continue; // we do not check swap file, only partitions
                    }
                    if (TryFindDisk(swaps[i].DeviceName, out var disk) == false)
                    {
                        continue;
                    }

                    var filename = $"/sys/block/{disk}/queue/rotational";
                    if (File.Exists(filename) == false)
                    {
                        continue;
                    }

                    var isHdd = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);
                    if (isHdd == -1)
                    {
                        return(null);
                    }
                    if (isHdd == 1)
                    {
                        foundRotationalDiskDrive = filename;
                    }
                    else if (isHdd != 0)
                    {
                        if (Log.IsOperationsEnabled)
                        {
                            Log.Operations($"Got invalid value (not 0 or 1) from {filename} = {isHdd}, assumes this is not a rotational disk");
                        }
                        foundRotationalDiskDrive = null;
                    }
                }

                string hddSwapsInsteadOfSsd = null;
                if (foundRotationalDiskDrive != null)
                {
                    // search if ssd drive is available
                    foreach (var partitionDisk in KernelVirtualFileSystemUtils.GetAllDisksFromPartitionsFile())
                    {
                        //ignore ramdisks (ram0..ram15 etc)
                        if (partitionDisk.StartsWith("ram", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        if (TryFindDisk(partitionDisk, out var disk) == false)
                        {
                            continue;
                        }

                        var filename = $"/sys/block/{disk}/queue/rotational";
                        if (File.Exists(filename) == false)
                        {
                            continue;
                        }

                        var isHdd = KernelVirtualFileSystemUtils.ReadNumberFromFile(filename);
                        if (isHdd == 0)
                        {
                            hddSwapsInsteadOfSsd = disk;
                            break;
                        }
                    }
                }

                return(hddSwapsInsteadOfSsd);

                bool TryFindDisk(string deviceName, out string disk)
                {
                    disk = null;

                    if (string.IsNullOrWhiteSpace(deviceName))
                    {
                        return(false);
                    }

                    deviceName = deviceName.Replace("/dev/", string.Empty);

                    foreach (var block in blocks)
                    {
                        if (deviceName.Contains(block))
                        {
                            disk = block;
                            return(true);
                        }
                    }

                    return(false);
                }
            }
            catch (Exception ex)
            {
                Log.Info("Error while trying to determine if hdd swaps instead of ssd on linux, ignoring this check and assuming no hddswap", ex);
                // ignore
                return(null);
            }
        }