Skip to content

Instantly share code, notes, and snippets.

@wiedi
Created June 22, 2017 13:41
Show Gist options
  • Save wiedi/4f5ed76cb004d67691b2262e2d0f4446 to your computer and use it in GitHub Desktop.
Save wiedi/4f5ed76cb004d67691b2262e2d0f4446 to your computer and use it in GitHub Desktop.
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