Documentation ¶
Overview ¶
Package mem provides functionality for measuring and displaying memory throughput and capacity.
Units ¶
Package mem defines two different types that represent quantities of data - Size and BitSize. The former represents an amount of data as bytes while the later represents an amount of data as bits.
Not each BitSize can be represented as Size and vice versa. For example 65 bit is neither 8 bytes (64 bit) nor 9 bytes (72 bit). However, Size and BitSize provide APIs for converting one to the other.
Some computer metrics, like networking speed, are usually measured in bits while others, like storage capacity, are measured in bytes. Large quantities of bits / bytes are commonly displayed using the decimal prefixes for powers of 10. However, some systems use binary prefixes (2^10 = 1024).
BitSize (decimal) Size (decimal) Size (binary) ┌──────┬───────────┐ ┌──────┬───────────┐ ┌──────┬───────────┐ │ Bit │ 1 │ │ Byte │ 1 │ │ Byte │ 1 │ │ Kbit │ 1000 Bit │ │ KB │ 1000 Byte │ │ KiB │ 1024 Byte │ │ Mbit │ 1000 Kbit │ │ MB │ 1000 KB │ │ MiB │ 1024 KiB │ │ Gbit │ 1000 Mbit │ │ GB │ 1000 MB │ │ GiB │ 1024 MiB │ │ Tbit │ 1000 Gbit │ │ TB │ 1000 GB │ │ TiB │ 1024 GiB │ │ │ │ │ PB │ 1000 TB │ │ PiB │ 1024 TiB │ └──────┴───────────┘ └──────┴───────────┘ └──────┴───────────┘
Formatting ¶
Sizes can be formatted and displayed in various units and with various precisions. For example:
a := mem.FormatSize(1*mem.MB, 'd', -1) // "1mb" b := mem.FormatSize(1*mem.MB, 'b', -1) // "976.5625kib" c := mem.FormatBitSize(1*mem.MBit, 'd', -1) // "1mbit"
Parsing ¶
String representation of sizes can be parsed using the corresponding Parse functions. For example:
a, err := mem.ParseSize("1mb") b, err := mem.ParseSize("976.5625KiB") c, err := mem.ParseBitSize("1mbit")
Buffers and Limits ¶
Often, code has to pre-allocate a buffer of a certain size or limit the amount of data from an io.Reader. With the mem package this can be done in a human readable way. For example:
buffer := make([]byte, 1 * mem.MB) // Allocate a 1MB buffer reader := io.LimitReader(r, 512 * mem.MB) // Limit the reader to 512MB // Limit an HTTP request body to 5 MB. req.Body = http.MaxBytesReader(w, req.Body, 5 * mem.MB)
Index ¶
- Constants
- func FormatBitSize(s BitSize, fmt byte, prec int) string
- func FormatSize(s Size, fmt byte, prec int) string
- func LimitReader(r io.Reader, n Size) *io.LimitedReader
- type BitSize
- func (b BitSize) Abs() BitSize
- func (b BitSize) Bytes() (Size, BitSize)
- func (b BitSize) Gigabits() float64
- func (b BitSize) Kilobits() float64
- func (b BitSize) Megabits() float64
- func (b BitSize) Round(m BitSize) BitSize
- func (b BitSize) String() string
- func (b BitSize) Terabits() float64
- func (b BitSize) Truncate(m BitSize) BitSize
- type Progress
- type ProgressReader
- type Size
- func (s Size) Abs() Size
- func (s Size) Bits() BitSize
- func (s Size) Gibibytes() float64
- func (s Size) Gigabytes() float64
- func (s Size) Kibibytes() float64
- func (s Size) Kilobytes() float64
- func (s Size) Mebibytes() float64
- func (s Size) Megabytes() float64
- func (s Size) Pebibytes() float64
- func (s Size) Petabytes() float64
- func (s Size) Round(m Size) Size
- func (s Size) String() string
- func (s Size) Tebibytes() float64
- func (s Size) Terabytes() float64
- func (s Size) Truncate(m Size) Size
Examples ¶
Constants ¶
const ( Bit BitSize = 1 KBit = 1000 * Bit MBit = 1000 * KBit GBit = 1000 * MBit TBit = 1000 * GBit )
Common sizes when measuring amounts of data in bits.
To count the number of units in a BitSize, divide:
mbits := mem.MBit fmt.Print(int64(mbits / mem.KBit)) // prints 1000
To convert an integer of units to a BitSize, multiply:
mbits := 10 fmt.Print(mem.BitSize(mbits)*mem.MBit) // prints 10MBit
const ( Byte Size = 1 KB Size = 1000 * Byte MB = 1000 * KB GB = 1000 * MB TB = 1000 * GB PB = 1000 * TB KiB Size = 1024 * Byte MiB = 1024 * KiB GiB = 1024 * MiB TiB = 1024 * GiB PiB = 1024 * TiB )
Common sizes for measuring memory and disk capacity.
To count the number of units in a Size, divide:
megabyte := mem.MB fmt.Print(int64(megabyte / mem.KB)) // prints 1000
To convert an integer of units to a Size, multiply:
megabytes := 10 fmt.Print(mem.Size(megabytes)*mem.MB) // prints 10MB
Variables ¶
This section is empty.
Functions ¶
func FormatBitSize ¶
FormatBitSize converts the bit size s to a string, according to the format fmt and precision prec.
The format fmt specifies how to format the size s. Valid values are:
- 'd' formats s as "-ddd.dddddmbit" using the decimal byte units.
- 'D' formats s as "-ddd.dddddMbit" using the decimal byte units.
The precision prec controls the number of digits after the decimal point printed by the 'd' and 'D' formats. The special precision -1 uses the smallest number of digits necessary such that ParseBitSize will return s exactly.
Example ¶
package main import ( "fmt" "aead.dev/mem" ) func main() { fmt.Println(mem.FormatBitSize(1*mem.MBit, 'D', -1)) fmt.Println(mem.FormatBitSize(1*mem.MBit+111*mem.KBit, 'd', 2)) fmt.Println(mem.FormatBitSize(2*mem.TBit+512*mem.MBit, 'D', 4)) }
Output: 1Mbit 1.11mbit 2.0005Tbit
func FormatSize ¶
FormatSize converts the size s to a string, according to the format fmt and precision prec.
The format fmt specifies how to format the size s. Valid values are:
- 'd' formats s as "-ddd.dddddmb" using the decimal byte units.
- 'b' formats s as "-ddd.dddddmib" using the binary byte units.
In addition, 'D' and 'B' format s similar to 'd' and 'b' but with partially uppercase unit strings. In particular:
- 'D' formats s as "-ddd.dddddMB" using the decimal byte units.
- 'B' formats s as "-ddd.dddddMiB" using the binary byte units.
The precision prec controls the number of digits after the decimal point printed by the 'd' and 'b' formats. The special precision -1 uses the smallest number of digits necessary such that ParseSize will return s exactly.
Example ¶
package main import ( "fmt" "aead.dev/mem" ) func main() { fmt.Println(mem.FormatSize(1*mem.MB, 'D', -1)) fmt.Println(mem.FormatSize(1*mem.MB+111*mem.KB, 'd', 2)) fmt.Println(mem.FormatSize(2*mem.TiB+512*mem.MiB, 'B', 4)) }
Output: 1MB 1.11mb 2.0005TiB
func LimitReader ¶ added in v0.2.0
func LimitReader(r io.Reader, n Size) *io.LimitedReader
LimitReader returns a io.LimitedReader that reads from r but stops with io.EOF after n bytes.
Types ¶
type BitSize ¶
type BitSize int64
BitSize represents an amount of data as int64 number of bits. The largest representable size is approximately 9223372 Tbit.
func ParseBitSize ¶
ParseBitSize parses a bit size string. A bit size string is a possibly signed decimal number with an optional fraction and a unit suffix, such as "64Kbit" or "1mbit".
A string may be a decimal size representation. Valid units are "bit", "kbit", "mbit", "gbit" and "tbit".
Example ¶
package main import ( "fmt" "log" "aead.dev/mem" ) func main() { a, err := mem.ParseBitSize("1.123Mbit") if err != nil { log.Fatalln(err) } b, err := mem.ParseBitSize("3.877Mbit") if err != nil { log.Fatalln(err) } fmt.Println(a + b) }
Output: 5Mbit
func (BitSize) Abs ¶
Abs returns the absolute value of b. As a special case, math.MinInt64 is converted to math.MaxInt64.
func (BitSize) Bytes ¶
Bytes returns b as number of bytes and any remaining bits, if any. It guarantees that:
bytes, bits := b.Bytes() fmt.Print(b == bytes.Bits() + bits) // true fmt.Print(-7 <= bits && bits <= 7) // true
Example ¶
package main import ( "fmt" "aead.dev/mem" ) func main() { b := mem.MBit fmt.Println(b.Bytes()) b = 1*mem.MBit + 4*mem.Bit bytes, bits := b.Bytes() fmt.Println(b == bytes.Bits()+bits && -7 <= bits && bits <= 7) }
Output: 125KB 0Bit true
func (BitSize) Round ¶
Round returns the result of rounding b to the nearest multiple of m. The rounding behavior for halfway values is to round away from zero. If the result exceeds the maximum (or minimum) value that can be stored in a Size, Round returns the maximum (or minimum) size. If m <= 0, Round returns b unchanged.
func (BitSize) String ¶
String returns a string representing the bit size in the form "1.25Mbit". The zero size formats as 0Bit.
Example ¶
package main import ( "fmt" "aead.dev/mem" ) func main() { fmt.Println(1 * mem.MBit) fmt.Println(1*mem.GBit + 500*mem.MBit) fmt.Println(5*mem.KBit + 880*mem.Bit) }
Output: 1Mbit 1.5Gbit 5.88Kbit
type Progress ¶ added in v0.2.0
type Progress struct { // N is the number of bytes since the last progress // update. N Size // Total is the number of bytes since the start // of the operation. Total Size // Err is any error that occurred during the operation. // Once the operation completes, Err is io.EOF. Err error }
Progress represents the progress of an I/O operation, like reading data from a file or network connection.
type ProgressReader ¶ added in v0.2.0
type ProgressReader struct { R io.Reader // The underlying io.Reader // Update, if non-nil, is called with the current // progress whenever a read from R completes and // either the UpdateEvery period has ellapsed // since the last update or UpdateAfter bytes have // been read. // // As a special case, Update is called after every // read from R if UpdateEvery and UpdateAfter // are both <= 0. // // The passed progress contains the number of bytes // read since the last Update call, the number of // bytes read in total so far and any error that // has occurred while reading from R. // Once reading from R returns an non-nil error, // including io.EOF, Update is called immediately // one more time and then never again. // // Update is called by the goroutine reading from // R. A long-running or blocking Update function // defers or blocks reads, and therefore, impacts // read performance. // In such cases, sending the progress to another // concurrently running goroutine via a channel // may be viable solution. Update func(Progress) // UpdateEvery is the duration that has to ellapse // between two Update calls. // // If UpdateEvery <= 0, Update may be called after // every read. UpdateEvery time.Duration // UpdateAfter is the number of bytes that have to // be read from R before Update is called again. // // If UpdateAfter <= 0, Update may be called after // every read. UpdateAfter Size // contains filtered or unexported fields }
ProgressReader wraps an io.Reader and calls Update with the current status when reading makes progress.
Example ¶
package main import ( "bytes" "fmt" "io" "log" "time" "aead.dev/mem" ) func main() { r := bytes.NewReader(make([]byte, 1*mem.MB)) p := mem.NewProgressReader(r, 500*time.Millisecond, func(p mem.Progress) { fmt.Printf("Copied %s/%s\n", p.Total, mem.Size(r.Size())) if p.Done() { fmt.Println("Done") } }) if _, err := io.Copy(io.Discard, p); err != nil { log.Fatal(err) } }
Output: Copied 8.192KB/1MB Copied 1MB/1MB Done
Example (Concurrent) ¶
package main import ( "bytes" "fmt" "io" "log" "sync" "time" "aead.dev/mem" ) func main() { r := bytes.NewReader(make([]byte, 1*mem.MB)) progress := make(chan mem.Progress, 1) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for p := range progress { fmt.Printf("Copied %s/%s\n", p.Total, mem.Size(r.Size())) if p.Done() { fmt.Println("Done") break } } }() p := mem.NewProgressReader(r, 500*time.Millisecond, func(p mem.Progress) { // Sending the progress to a channel blocks reads if the // channel is full. A select with a default cause reads // won't block but progress updates will get dropped when // the channel is full. progress <- p }) if _, err := io.Copy(io.Discard, p); err != nil { log.Fatal(err) } close(progress) wg.Wait() // Wait until all progress updates got printed }
Output: Copied 8.192KB/1MB Copied 1MB/1MB Done
func NewProgressReader ¶ added in v0.2.0
NewProgressReader returns a new ProgressReader that wraps r and calls update periodically with the current progress while reading.
func (*ProgressReader) Progress ¶ added in v0.2.0
func (r *ProgressReader) Progress() Progress
Progress returns the current progress.
It contains the number of bytes read since the last invocation of Update by Read, the total number of bytes read so far and any error that has occurred while reading from R.
type Size ¶
type Size int64
Size represents an amount of data as int64 number of bytes. The largest representable size is approximately 8192 PiB.
func ParseSize ¶
ParseSize parses a size string. A size string is a possibly signed decimal number with an optional fraction and a unit suffix, such as "64KB" or "1MiB".
A string may be a decimal or binary size representation. Valid units are:
- decimal: "b", "kb", "mb", "gb", "tb", "pb"
- binary: "b", "kib", "mib", "gib", "tib", "pib"
Example ¶
package main import ( "fmt" "log" "aead.dev/mem" ) func main() { a, err := mem.ParseSize("1.123MB") if err != nil { log.Fatalln(err) } b, err := mem.ParseSize("3.877MB") if err != nil { log.Fatalln(err) } fmt.Println(a + b) }
Output: 5MB
func (Size) Abs ¶
Abs returns the absolute value of s. As a special case, math.MinInt64 is converted to math.MaxInt64.
func (Size) Bits ¶
Bits returns s as number of bits. As special cases, if s would be greater resp. smaller than the max. resp. min. representable BitSize it returns math.MaxInt64 resp. math.MinInt64.
func (Size) Round ¶
Round returns the result of rounding s to the nearest multiple of m. The rounding behavior for halfway values is to round away from zero. If the result exceeds the maximum (or minimum) value that can be stored in a Size, Round returns the maximum (or minimum) size. If m <= 0, Round returns s unchanged.
func (Size) String ¶
String returns a string representing the size in the form "1.25MB". The zero size formats as 0B.
Example ¶
package main import ( "fmt" "aead.dev/mem" ) func main() { fmt.Println(1 * mem.MB) fmt.Println(1*mem.GB + 500*mem.MB) fmt.Println(5*mem.KiB + 880*mem.Byte) }
Output: 1MB 1.5GB 6KB