// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package procfs

import (
	
	
	
	
	
	

	
)

// Meminfo represents memory statistics.
type Meminfo struct {
	// Total usable ram (i.e. physical ram minus a few reserved
	// bits and the kernel binary code)
	MemTotal *uint64
	// The sum of LowFree+HighFree
	MemFree *uint64
	// An estimate of how much memory is available for starting
	// new applications, without swapping. Calculated from
	// MemFree, SReclaimable, the size of the file LRU lists, and
	// the low watermarks in each zone.  The estimate takes into
	// account that the system needs some page cache to function
	// well, and that not all reclaimable slab will be
	// reclaimable, due to items being in use. The impact of those
	// factors will vary from system to system.
	MemAvailable *uint64
	// Relatively temporary storage for raw disk blocks shouldn't
	// get tremendously large (20MB or so)
	Buffers *uint64
	Cached  *uint64
	// Memory that once was swapped out, is swapped back in but
	// still also is in the swapfile (if memory is needed it
	// doesn't need to be swapped out AGAIN because it is already
	// in the swapfile. This saves I/O)
	SwapCached *uint64
	// Memory that has been used more recently and usually not
	// reclaimed unless absolutely necessary.
	Active *uint64
	// Memory which has been less recently used.  It is more
	// eligible to be reclaimed for other purposes
	Inactive     *uint64
	ActiveAnon   *uint64
	InactiveAnon *uint64
	ActiveFile   *uint64
	InactiveFile *uint64
	Unevictable  *uint64
	Mlocked      *uint64
	// total amount of swap space available
	SwapTotal *uint64
	// Memory which has been evicted from RAM, and is temporarily
	// on the disk
	SwapFree *uint64
	// Memory which is waiting to get written back to the disk
	Dirty *uint64
	// Memory which is actively being written back to the disk
	Writeback *uint64
	// Non-file backed pages mapped into userspace page tables
	AnonPages *uint64
	// files which have been mapped, such as libraries
	Mapped *uint64
	Shmem  *uint64
	// in-kernel data structures cache
	Slab *uint64
	// Part of Slab, that might be reclaimed, such as caches
	SReclaimable *uint64
	// Part of Slab, that cannot be reclaimed on memory pressure
	SUnreclaim  *uint64
	KernelStack *uint64
	// amount of memory dedicated to the lowest level of page
	// tables.
	PageTables *uint64
	// NFS pages sent to the server, but not yet committed to
	// stable storage
	NFSUnstable *uint64
	// Memory used for block device "bounce buffers"
	Bounce *uint64
	// Memory used by FUSE for temporary writeback buffers
	WritebackTmp *uint64
	// Based on the overcommit ratio ('vm.overcommit_ratio'),
	// this is the total amount of  memory currently available to
	// be allocated on the system. This limit is only adhered to
	// if strict overcommit accounting is enabled (mode 2 in
	// 'vm.overcommit_memory').
	// The CommitLimit is calculated with the following formula:
	// CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
	//                overcommit_ratio / 100 + [total swap pages]
	// For example, on a system with 1G of physical RAM and 7G
	// of swap with a `vm.overcommit_ratio` of 30 it would
	// yield a CommitLimit of 7.3G.
	// For more details, see the memory overcommit documentation
	// in vm/overcommit-accounting.
	CommitLimit *uint64
	// The amount of memory presently allocated on the system.
	// The committed memory is a sum of all of the memory which
	// has been allocated by processes, even if it has not been
	// "used" by them as of yet. A process which malloc()'s 1G
	// of memory, but only touches 300M of it will show up as
	// using 1G. This 1G is memory which has been "committed" to
	// by the VM and can be used at any time by the allocating
	// application. With strict overcommit enabled on the system
	// (mode 2 in 'vm.overcommit_memory'),allocations which would
	// exceed the CommitLimit (detailed above) will not be permitted.
	// This is useful if one needs to guarantee that processes will
	// not fail due to lack of memory once that memory has been
	// successfully allocated.
	CommittedAS *uint64
	// total size of vmalloc memory area
	VmallocTotal *uint64
	// amount of vmalloc area which is used
	VmallocUsed *uint64
	// largest contiguous block of vmalloc area which is free
	VmallocChunk      *uint64
	Percpu            *uint64
	HardwareCorrupted *uint64
	AnonHugePages     *uint64
	ShmemHugePages    *uint64
	ShmemPmdMapped    *uint64
	CmaTotal          *uint64
	CmaFree           *uint64
	HugePagesTotal    *uint64
	HugePagesFree     *uint64
	HugePagesRsvd     *uint64
	HugePagesSurp     *uint64
	Hugepagesize      *uint64
	DirectMap4k       *uint64
	DirectMap2M       *uint64
	DirectMap1G       *uint64

	// The struct fields below are the byte-normalized counterparts to the
	// existing struct fields. Values are normalized using the optional
	// unit field in the meminfo line.
	MemTotalBytes          *uint64
	MemFreeBytes           *uint64
	MemAvailableBytes      *uint64
	BuffersBytes           *uint64
	CachedBytes            *uint64
	SwapCachedBytes        *uint64
	ActiveBytes            *uint64
	InactiveBytes          *uint64
	ActiveAnonBytes        *uint64
	InactiveAnonBytes      *uint64
	ActiveFileBytes        *uint64
	InactiveFileBytes      *uint64
	UnevictableBytes       *uint64
	MlockedBytes           *uint64
	SwapTotalBytes         *uint64
	SwapFreeBytes          *uint64
	DirtyBytes             *uint64
	WritebackBytes         *uint64
	AnonPagesBytes         *uint64
	MappedBytes            *uint64
	ShmemBytes             *uint64
	SlabBytes              *uint64
	SReclaimableBytes      *uint64
	SUnreclaimBytes        *uint64
	KernelStackBytes       *uint64
	PageTablesBytes        *uint64
	NFSUnstableBytes       *uint64
	BounceBytes            *uint64
	WritebackTmpBytes      *uint64
	CommitLimitBytes       *uint64
	CommittedASBytes       *uint64
	VmallocTotalBytes      *uint64
	VmallocUsedBytes       *uint64
	VmallocChunkBytes      *uint64
	PercpuBytes            *uint64
	HardwareCorruptedBytes *uint64
	AnonHugePagesBytes     *uint64
	ShmemHugePagesBytes    *uint64
	ShmemPmdMappedBytes    *uint64
	CmaTotalBytes          *uint64
	CmaFreeBytes           *uint64
	HugepagesizeBytes      *uint64
	DirectMap4kBytes       *uint64
	DirectMap2MBytes       *uint64
	DirectMap1GBytes       *uint64
}

// Meminfo returns an information about current kernel/system memory statistics.
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
func ( FS) () (Meminfo, error) {
	,  := util.ReadFileNoStat(.proc.Path("meminfo"))
	if  != nil {
		return Meminfo{}, 
	}

	,  := parseMemInfo(bytes.NewReader())
	if  != nil {
		return Meminfo{}, fmt.Errorf("%w: %w", ErrFileParse, )
	}

	return *, nil
}

func parseMemInfo( io.Reader) (*Meminfo, error) {
	var  Meminfo
	 := bufio.NewScanner()
	for .Scan() {
		 := strings.Fields(.Text())
		var ,  uint64

		,  := strconv.ParseUint([1], 0, 64)
		if  != nil {
			return nil, 
		}

		switch len() {
		case 2:
			// No unit present, use the parsed the value as bytes directly.
			 = 
		case 3:
			// Unit present in optional 3rd field, convert it to
			// bytes. The only unit supported within the Linux
			// kernel is `kB`.
			if [2] != "kB" {
				return nil, fmt.Errorf("%w: Unsupported unit in optional 3rd field %q", ErrFileParse, [2])
			}

			 = 1024 * 

		default:
			return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, .Text())
		}

		switch [0] {
		case "MemTotal:":
			.MemTotal = &
			.MemTotalBytes = &
		case "MemFree:":
			.MemFree = &
			.MemFreeBytes = &
		case "MemAvailable:":
			.MemAvailable = &
			.MemAvailableBytes = &
		case "Buffers:":
			.Buffers = &
			.BuffersBytes = &
		case "Cached:":
			.Cached = &
			.CachedBytes = &
		case "SwapCached:":
			.SwapCached = &
			.SwapCachedBytes = &
		case "Active:":
			.Active = &
			.ActiveBytes = &
		case "Inactive:":
			.Inactive = &
			.InactiveBytes = &
		case "Active(anon):":
			.ActiveAnon = &
			.ActiveAnonBytes = &
		case "Inactive(anon):":
			.InactiveAnon = &
			.InactiveAnonBytes = &
		case "Active(file):":
			.ActiveFile = &
			.ActiveFileBytes = &
		case "Inactive(file):":
			.InactiveFile = &
			.InactiveFileBytes = &
		case "Unevictable:":
			.Unevictable = &
			.UnevictableBytes = &
		case "Mlocked:":
			.Mlocked = &
			.MlockedBytes = &
		case "SwapTotal:":
			.SwapTotal = &
			.SwapTotalBytes = &
		case "SwapFree:":
			.SwapFree = &
			.SwapFreeBytes = &
		case "Dirty:":
			.Dirty = &
			.DirtyBytes = &
		case "Writeback:":
			.Writeback = &
			.WritebackBytes = &
		case "AnonPages:":
			.AnonPages = &
			.AnonPagesBytes = &
		case "Mapped:":
			.Mapped = &
			.MappedBytes = &
		case "Shmem:":
			.Shmem = &
			.ShmemBytes = &
		case "Slab:":
			.Slab = &
			.SlabBytes = &
		case "SReclaimable:":
			.SReclaimable = &
			.SReclaimableBytes = &
		case "SUnreclaim:":
			.SUnreclaim = &
			.SUnreclaimBytes = &
		case "KernelStack:":
			.KernelStack = &
			.KernelStackBytes = &
		case "PageTables:":
			.PageTables = &
			.PageTablesBytes = &
		case "NFS_Unstable:":
			.NFSUnstable = &
			.NFSUnstableBytes = &
		case "Bounce:":
			.Bounce = &
			.BounceBytes = &
		case "WritebackTmp:":
			.WritebackTmp = &
			.WritebackTmpBytes = &
		case "CommitLimit:":
			.CommitLimit = &
			.CommitLimitBytes = &
		case "Committed_AS:":
			.CommittedAS = &
			.CommittedASBytes = &
		case "VmallocTotal:":
			.VmallocTotal = &
			.VmallocTotalBytes = &
		case "VmallocUsed:":
			.VmallocUsed = &
			.VmallocUsedBytes = &
		case "VmallocChunk:":
			.VmallocChunk = &
			.VmallocChunkBytes = &
		case "Percpu:":
			.Percpu = &
			.PercpuBytes = &
		case "HardwareCorrupted:":
			.HardwareCorrupted = &
			.HardwareCorruptedBytes = &
		case "AnonHugePages:":
			.AnonHugePages = &
			.AnonHugePagesBytes = &
		case "ShmemHugePages:":
			.ShmemHugePages = &
			.ShmemHugePagesBytes = &
		case "ShmemPmdMapped:":
			.ShmemPmdMapped = &
			.ShmemPmdMappedBytes = &
		case "CmaTotal:":
			.CmaTotal = &
			.CmaTotalBytes = &
		case "CmaFree:":
			.CmaFree = &
			.CmaFreeBytes = &
		case "HugePages_Total:":
			.HugePagesTotal = &
		case "HugePages_Free:":
			.HugePagesFree = &
		case "HugePages_Rsvd:":
			.HugePagesRsvd = &
		case "HugePages_Surp:":
			.HugePagesSurp = &
		case "Hugepagesize:":
			.Hugepagesize = &
			.HugepagesizeBytes = &
		case "DirectMap4k:":
			.DirectMap4k = &
			.DirectMap4kBytes = &
		case "DirectMap2M:":
			.DirectMap2M = &
			.DirectMap2MBytes = &
		case "DirectMap1G:":
			.DirectMap1G = &
			.DirectMap1GBytes = &
		}
	}

	return &, nil
}