Created
June 22, 2017 13:41
-
-
Save wiedi/4f5ed76cb004d67691b2262e2d0f4446 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 604c6e890ca495364fc5b5cce2861ce1f0c2d3e3 Mon Sep 17 00:00:00 2001 | |
From: Sebastian Wiedenroth <sebastian.wiedenroth@skylime.net> | |
Date: Thu, 22 Jun 2017 15:37:42 +0200 | |
Subject: [PATCH] 5838 a Linux-like free(1M) would probably not be a bad thing | |
--- | |
usr/src/cmd/Makefile | 1 + | |
usr/src/cmd/free/Makefile | 33 +++++ | |
usr/src/cmd/free/free.c | 255 ++++++++++++++++++++++++++++++++++ | |
usr/src/man/man1/Makefile | 1 + | |
usr/src/man/man1/free.1 | 50 +++++++ | |
usr/src/pkg/manifests/SUNWcs.man1.inc | 1 + | |
usr/src/pkg/manifests/SUNWcs.mf | 1 + | |
7 files changed, 342 insertions(+) | |
create mode 100644 usr/src/cmd/free/Makefile | |
create mode 100644 usr/src/cmd/free/free.c | |
create mode 100644 usr/src/man/man1/free.1 | |
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile | |
index 08841eb06d2532dd7591c7732f4d07f0d9f093a9..b99c8f519016ad6c723ecf4db74cea5458ce86dd 100644 | |
--- a/usr/src/cmd/Makefile | |
+++ b/usr/src/cmd/Makefile | |
@@ -170,6 +170,7 @@ COMMON_SUBDIRS= \ | |
fmtmsg \ | |
fold \ | |
format \ | |
+ free \ | |
fs.d \ | |
fstyp \ | |
fuser \ | |
diff --git a/usr/src/cmd/free/Makefile b/usr/src/cmd/free/Makefile | |
new file mode 100644 | |
index 0000000000000000000000000000000000000000..dc7e39a827e472fcd0d28d274a4262e5d40887d8 | |
--- /dev/null | |
+++ b/usr/src/cmd/free/Makefile | |
@@ -0,0 +1,33 @@ | |
+# | |
+# This file and its contents are supplied under the terms of the | |
+# Common Development and Distribution License ("CDDL"), version 1.0. | |
+# You may only use this file in accordance with the terms of version | |
+# 1.0 of the CDDL. | |
+# | |
+# A full copy of the text of the CDDL should have accompanied this | |
+# source. A copy of the CDDL is also available via the Internet at | |
+# http://www.illumos.org/license/CDDL. | |
+# | |
+ | |
+# | |
+# Copyright 2017 Sebastian Wiedenroth | |
+# | |
+ | |
+PROG= free | |
+ | |
+include ../Makefile.cmd | |
+ | |
+CFLAGS += $(CCVERBOSE) | |
+LDLIBS += -lkstat -lcmdutils | |
+ | |
+.KEEP_STATE: | |
+ | |
+all: $(PROG) | |
+ | |
+install: all $(ROOTPROG) | |
+ | |
+clean: | |
+ | |
+lint: lint_PROG | |
+ | |
+include ../Makefile.targ | |
diff --git a/usr/src/cmd/free/free.c b/usr/src/cmd/free/free.c | |
new file mode 100644 | |
index 0000000000000000000000000000000000000000..0c51bc24c28f73a519522b15d154f02d25a6f175 | |
--- /dev/null | |
+++ b/usr/src/cmd/free/free.c | |
@@ -0,0 +1,255 @@ | |
+/* | |
+ * This file and its contents are supplied under the terms of the | |
+ * Common Development and Distribution License ("CDDL"), version 1.0. | |
+ * You may only use this file in accordance with the terms of version | |
+ * 1.0 of the CDDL. | |
+ * | |
+ * A full copy of the text of the CDDL should have accompanied this | |
+ * source. A copy of the CDDL is also available via the Internet at | |
+ * http://www.illumos.org/license/CDDL. | |
+ */ | |
+ | |
+/* | |
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved. | |
+ * Copyright 2017 Sebastian Wiedenroth | |
+ */ | |
+ | |
+/* Based on Brendan Gregg's swapinfo */ | |
+ | |
+#include <stdio.h> | |
+#include <sys/sysinfo.h> | |
+#include <kstat.h> | |
+#include <sys/swap.h> | |
+#include <zone.h> | |
+#include <errno.h> | |
+#include <stdlib.h> | |
+#include <libgen.h> | |
+#include <unistd.h> | |
+#include <locale.h> | |
+#include <strings.h> | |
+#include <libcmdutils.h> | |
+ | |
+static char *progname; | |
+ | |
+typedef struct free_info { | |
+ uint64_t mem_total; | |
+ uint64_t mem_used; | |
+ uint64_t mem_free; | |
+ uint64_t mem_locked; | |
+ uint64_t mem_kernel; | |
+ uint64_t mem_cached; | |
+ uint64_t swap_total; | |
+ uint64_t swap_used; | |
+ uint64_t swap_free; | |
+} free_info_t; | |
+ | |
+ | |
+int | |
+get_free_info(free_info_t *fi) | |
+{ | |
+ struct anoninfo ai; | |
+ kstat_ctl_t *kc = NULL; | |
+ kstat_named_t *knp = NULL; | |
+ | |
+ bzero(fi, sizeof (free_info_t)); | |
+ | |
+ uint64_t pagesize = getpagesize(); | |
+ uint64_t pages = sysconf(_SC_PHYS_PAGES); | |
+ | |
+ fi->mem_total = pagesize * pages; | |
+ | |
+ | |
+ if ((kc = kstat_open()) == NULL) { | |
+ fprintf(stderr, "kstat_open() failed\n"); | |
+ return (-1); | |
+ } | |
+ | |
+ kstat_t *ks = kstat_lookup(kc, "unix", 0, "system_pages"); | |
+ if (ks == NULL) | |
+ goto err; | |
+ | |
+ kstat_read(kc, ks, 0); | |
+ knp = kstat_data_lookup(ks, "pp_kernel"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ uint64_t pp_kernel = (uint64_t)knp->value.ui64 * pagesize; | |
+ | |
+ knp = kstat_data_lookup(ks, "pageslocked"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ uint64_t pageslocked = (uint64_t)knp->value.ui64 * pagesize; | |
+ | |
+ zoneid_t zid = getzoneid(); | |
+ if (zid > 0) { | |
+ /* local zone */ | |
+ ks = kstat_lookup(kc, "memory_cap", zid, NULL); | |
+ if (ks == NULL) | |
+ goto err; | |
+ kstat_read(kc, ks, 0); | |
+ | |
+ knp = kstat_data_lookup(ks, "rss"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ fi->mem_used = (uint64_t)knp->value.ui64; | |
+ fi->mem_free = fi->mem_total - fi->mem_used; | |
+ } else { | |
+ /* global zone */ | |
+ knp = kstat_data_lookup(ks, "freemem"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ fi->mem_free = (uint64_t)knp->value.ui64 * pagesize; | |
+ | |
+ knp = kstat_data_lookup(ks, "availrmem"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ fi->mem_used = ((uint64_t)knp->value.ui64 * pagesize) | |
+ - fi->mem_free; | |
+ } | |
+ | |
+ ks = kstat_lookup(kc, "zfs", 0, "arcstats"); | |
+ if (ks == NULL) | |
+ goto err; | |
+ kstat_read(kc, ks, 0); | |
+ | |
+ knp = kstat_data_lookup(ks, "size"); | |
+ if (knp == NULL) | |
+ goto err; | |
+ fi->mem_cached = (uint64_t)knp->value.ui64; | |
+ | |
+ kstat_close(kc); | |
+ | |
+ if (pp_kernel < pageslocked) { | |
+ fi->mem_kernel = pp_kernel - fi->mem_cached; | |
+ fi->mem_locked = pageslocked - pp_kernel; | |
+ } else { | |
+ fi->mem_kernel = pageslocked - fi->mem_cached; | |
+ fi->mem_locked = 0; | |
+ } | |
+ | |
+ if (swapctl(SC_AINFO, &ai) == -1) | |
+ goto err; | |
+ fi->swap_total = ai.ani_max * pagesize; | |
+ fi->swap_used = ai.ani_resv * pagesize; | |
+ fi->swap_free = (ai.ani_max - ai.ani_resv) * pagesize; | |
+ | |
+ return (0); | |
+ | |
+err: | |
+ (void) kstat_close(kc); | |
+ return (-1); | |
+} | |
+ | |
+void | |
+print_human_free_info(free_info_t *fi) | |
+{ | |
+ char mem_total[NN_NUMBUF_SZ] = {0}; | |
+ char mem_used[NN_NUMBUF_SZ] = {0}; | |
+ char mem_free[NN_NUMBUF_SZ] = {0}; | |
+ char mem_locked[NN_NUMBUF_SZ] = {0}; | |
+ char mem_kernel[NN_NUMBUF_SZ] = {0}; | |
+ char mem_cached[NN_NUMBUF_SZ] = {0}; | |
+ char swap_total[NN_NUMBUF_SZ] = {0}; | |
+ char swap_used[NN_NUMBUF_SZ] = {0}; | |
+ char swap_free[NN_NUMBUF_SZ] = {0}; | |
+ | |
+ nicenum(fi->mem_total, mem_total, sizeof (mem_total)); | |
+ nicenum(fi->mem_used, mem_used, sizeof (mem_used)); | |
+ nicenum(fi->mem_free, mem_free, sizeof (mem_free)); | |
+ nicenum(fi->mem_locked, mem_locked, sizeof (mem_locked)); | |
+ nicenum(fi->mem_kernel, mem_kernel, sizeof (mem_kernel)); | |
+ nicenum(fi->mem_cached, mem_cached, sizeof (mem_cached)); | |
+ nicenum(fi->swap_total, swap_total, sizeof (swap_total)); | |
+ nicenum(fi->swap_used, swap_used, sizeof (swap_used)); | |
+ nicenum(fi->swap_free, swap_free, sizeof (swap_free)); | |
+ | |
+ printf("%16s %10s %10s %10s %10s %10s\n", | |
+ "total", "used", "free", "locked", "kernel", "cached"); | |
+ printf("Mem: %10s %10s %10s %10s %10s %10s\n", | |
+ mem_total, mem_used, mem_free, | |
+ mem_locked, mem_kernel, mem_cached); | |
+ printf("Swap: %10s %10s %10s\n", swap_total, swap_used, swap_free); | |
+} | |
+ | |
+void | |
+print_numeric_free_info(free_info_t *fi, int div) | |
+{ | |
+ printf("%16s %10s %10s %10s %10s %10s\n", | |
+ "total", "used", "free", "locked", "kernel", "cached"); | |
+ printf("Mem: %10llu %10llu %10llu %10llu %10llu %10llu\n", | |
+ fi->mem_total / div, | |
+ fi->mem_used / div, | |
+ fi->mem_free / div, | |
+ fi->mem_locked / div, | |
+ fi->mem_kernel / div, | |
+ fi->mem_cached / div); | |
+ printf("Swap: %10llu %10llu %10llu\n", | |
+ fi->swap_total / div, | |
+ fi->swap_used / div, | |
+ fi->swap_free / div); | |
+} | |
+ | |
+static void | |
+usage(void) | |
+{ | |
+ (void) fprintf(stderr, gettext( | |
+ "Usage: %s [-b|-k|-m|-g|-h]\n" | |
+ "Display the amount of free and used system memory\n"), | |
+ progname); | |
+ exit(2); | |
+} | |
+ | |
+int main(int argc, char *argv[]) { | |
+ int c; | |
+ int div = 1; | |
+ free_info_t fi; | |
+ boolean_t human = B_TRUE; | |
+ | |
+ (void) setlocale(LC_ALL, ""); | |
+ | |
+#if !defined(TEXT_DOMAIN) | |
+#define TEXT_DOMAIN "SYS_TEST" | |
+#endif | |
+ (void) textdomain(TEXT_DOMAIN); | |
+ | |
+ progname = basename(argv[0]); | |
+ while ((c = getopt(argc, argv, "hbkmg?")) != -1) { | |
+ switch (c) { | |
+ case 'h': | |
+ human = B_TRUE; | |
+ break; | |
+ case 'b': | |
+ div = 1; | |
+ human = B_FALSE; | |
+ break; | |
+ case 'k': | |
+ div = 1024; | |
+ human = B_FALSE; | |
+ break; | |
+ case 'm': | |
+ div = 1024 * 1024; | |
+ human = B_FALSE; | |
+ break; | |
+ case 'g': | |
+ div = 1024 * 1024 * 1024; | |
+ human = B_FALSE; | |
+ break; | |
+ case '?': /* fallthrough */ | |
+ default: | |
+ usage(); | |
+ exit(1); | |
+ } | |
+ } | |
+ | |
+ if (get_free_info(&fi) < 0) { | |
+ perror("get_free_info"); | |
+ return (-1); | |
+ } | |
+ | |
+ if (human) { | |
+ print_human_free_info(&fi); | |
+ } else { | |
+ print_numeric_free_info(&fi, div); | |
+ } | |
+ | |
+ return (0); | |
+} | |
diff --git a/usr/src/man/man1/Makefile b/usr/src/man/man1/Makefile | |
index b8e90a22d1dac93ff10a5f90e7fb5061ed6e2a08..46cb71729099e0555ae8e01bb99a71b56676fb36 100644 | |
--- a/usr/src/man/man1/Makefile | |
+++ b/usr/src/man/man1/Makefile | |
@@ -137,6 +137,7 @@ MANFILES= acctcom.1 \ | |
fmt.1 \ | |
fmtmsg.1 \ | |
fold.1 \ | |
+ free.1 \ | |
ftp.1 \ | |
gcore.1 \ | |
gencat.1 \ | |
diff --git a/usr/src/man/man1/free.1 b/usr/src/man/man1/free.1 | |
new file mode 100644 | |
index 0000000000000000000000000000000000000000..9a0203a5977b84993777bcc8646f2839e27fbd1d | |
--- /dev/null | |
+++ b/usr/src/man/man1/free.1 | |
@@ -0,0 +1,50 @@ | |
+.\" | |
+.\" This file and its contents are supplied under the terms of the | |
+.\" Common Development and Distribution License ("CDDL"), version 1.0. | |
+.\" You may only use this file in accordance with the terms of version | |
+.\" 1.0 of the CDDL. | |
+.\" | |
+.\" A full copy of the text of the CDDL should have accompanied this | |
+.\" source. A copy of the CDDL is also available via the Internet at | |
+.\" http://www.illumos.org/license/CDDL. | |
+.\" | |
+.\" | |
+.\" Copyright 2017 Sebastian Wiedenroth | |
+.\" | |
+.Dd $Mdocdate: June 18 2017 $ | |
+.Dt FREE 1 | |
+.Os | |
+.Sh NAME | |
+.Nm free | |
+.Nd report free and used memory | |
+.Sh SYNOPSIS | |
+.Nm free | |
+.Op -b | -k | -m | -g | -h | |
+.Sh DESCRIPTION | |
+The | |
+.Nm | |
+utility shows free and used physical and swap memory. | |
+It also reports the amount of memory the system has locked, uses for the kernel, | |
+and is used for cache in the ZFS ARC. | |
+ | |
+For zones with \fBcapped-memory\fR (see \fBzonecfg\fR(1M)) usage is calculated | |
+relative to these limits. | |
+.Sh OPTIONS | |
+.Bl -tag -width Ds | |
+.It Fl b | |
+Display numbers in bytes. | |
+.It Fl g | |
+Display numbers in gigabytes. | |
+.It Fl h | |
+Display numbers in human-readable form with a suffix of K, M, G, T, P, E (for | |
+kilobytes, megabytes, gigabytes, terabytes, petabytes or exabytes, | |
+respectively). This is the default format. | |
+.It Fl k | |
+Display numbers in kilbytes. | |
+.It Fl m | |
+Display numbers in megabytes. | |
+.El | |
+.Sh SEE ALSO | |
+.Xr vmstat 1M , | |
+.Xr swap 1M | |
+ | |
diff --git a/usr/src/pkg/manifests/SUNWcs.man1.inc b/usr/src/pkg/manifests/SUNWcs.man1.inc | |
index 39248dcdf4fd7db4f5e5a75ebca32e14beca93c0..c57ac3a908743a86e139fb284403da10e58bef52 100644 | |
--- a/usr/src/pkg/manifests/SUNWcs.man1.inc | |
+++ b/usr/src/pkg/manifests/SUNWcs.man1.inc | |
@@ -82,6 +82,7 @@ file path=usr/share/man/man1/find.1 | |
file path=usr/share/man/man1/fmt.1 | |
file path=usr/share/man/man1/fmtmsg.1 | |
file path=usr/share/man/man1/fold.1 | |
+file path=usr/share/man/man1/free.1 | |
file path=usr/share/man/man1/getconf.1 | |
file path=usr/share/man/man1/getfacl.1 | |
file path=usr/share/man/man1/getopt.1 | |
diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf | |
index 7833f7ef96e562ef6b865729072b227c727feb36..9f801a97e7dbe7df1f6610535e25dbb87c30c6fb 100644 | |
--- a/usr/src/pkg/manifests/SUNWcs.mf | |
+++ b/usr/src/pkg/manifests/SUNWcs.mf | |
@@ -752,6 +752,7 @@ file path=usr/bin/find mode=0555 | |
file path=usr/bin/fmt mode=0555 | |
file path=usr/bin/fmtmsg mode=0555 | |
file path=usr/bin/fold mode=0555 | |
+file path=usr/bin/free mode=0555 | |
file path=usr/bin/fsstat mode=0555 | |
file path=usr/bin/geniconvtbl mode=0555 | |
file path=usr/bin/getconf mode=0555 | |
-- | |
2.13.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment