diff options
-rw-r--r-- | sys-utils/chmem.8 | 3 | ||||
-rw-r--r-- | sys-utils/lsmem.1 | 27 | ||||
-rw-r--r-- | sys-utils/lsmem.c | 79 |
3 files changed, 74 insertions, 35 deletions
diff --git a/sys-utils/chmem.8 b/sys-utils/chmem.8 index b37ee8382..dae7413d4 100644 --- a/sys-utils/chmem.8 +++ b/sys-utils/chmem.8 @@ -17,8 +17,7 @@ in GiB (1024 x 1024 x 1024 bytes). The default unit is MiB. .IP "\(hy" 2 Specify \fIRANGE\fP in the form 0x<start>-0x<end> as shown in the output of the \fBlsmem\fP command. <start> is the hexadecimal address of the first byte and <end> -is the hexadecimal address of the last byte in the memory range. Note that the range -as shown by \fBlsmem\fP command maybe be influenced by zones (\fBlsmem -o +ZONES\fP). +is the hexadecimal address of the last byte in the memory range. . .IP "\(hy" 2 Specify \fIBLOCKRANGE\fP in the form <first>-<last> or <block> as shown in the diff --git a/sys-utils/lsmem.1 b/sys-utils/lsmem.1 index c664273f0..af65c2abb 100644 --- a/sys-utils/lsmem.1 +++ b/sys-utils/lsmem.1 @@ -10,19 +10,29 @@ status. The listed memory blocks correspond to the memory block representation in sysfs. The command also shows the memory block size and the amount of memory in online and offline state. -The default output compatible with original implementaion from s390-tools, but +The default output compatible with original implementation from s390-tools, but it's strongly recommended to avoid using default outputs in your scripts. Always explicitly define expected columns by using the \fB\-\-output\fR option together with a columns list in environments where a stable output is required. +The \fBlsmem\fP command lists a new memory range always when the current memory +block distinguish from the previous block by STATE, REMOVABLE, NODE or ZONES +attribute. This default behavior is possible to override by the +\fB\-\-split\fR option (e.g. \fBlsmem \-\-split=STATE,ZONES\fR). The special +word "none" may be used to ignore all differences between memory blocks and to +create as large as possible continuous ranges. The opposite semantic is +\fB\-\-all\fR to list individual memory blocks. The default split policy is +subject to change. Always explicitly use \fB\-\-split\fR in environments where +a stable output is required. + +Note that some output columns may provide inaccurate information if a split policy +forces \fBlsmem\fP to ignore diffrences in some attributes. For example if you +merge removable and non-removable memory blocks to the one range than all +the range will be marked as non-removable on \fBlsmem\fP output. + Not all columns are supported on all systems. If an unsupported column is specified, \fBlsmem\fP prints the column but does not provide any data for it. -The number of output entries (memory ranges) maybe be influenced by specified -columns. The lsmem command shows larger memory ranges if the blocks in the -range do not distinguish in output columns. For example RANGE maybe be -different if the command output contains column ZONES (lsmem -o +ZONES). - Use the \fB\-\-help\fR option to see the columns description. .SH OPTIONS @@ -57,6 +67,11 @@ All potentially unsafe characters are hex-escaped (\\x<code>). Produce output in raw format. All potentially unsafe characters are hex-escaped (\\x<code>). .TP +.BR \-S , " \-\-split " \fIlist\fP +Specify which columns (attributes) use to split memory blocks to ranges. The +supported columns are STATE, REMOVABLE, NODE and ZONES, or "none". The another columns are +silently ignored. For more details see DESCRIPTION above. +.TP .BR \-s , " \-\-sysroot " \fIdirectory\fP Gather memory data for a Linux instance other than the instance from which the \fBlsmem\fP command is issued. The specified \fIdirectory\fP is the system diff --git a/sys-utils/lsmem.c b/sys-utils/lsmem.c index 6def429ec..97376de38 100644 --- a/sys-utils/lsmem.c +++ b/sys-utils/lsmem.c @@ -82,15 +82,16 @@ struct lsmem { summary : 1, list_all : 1, bytes : 1, - want_node : 1, - want_state : 1, - want_removable : 1, want_summary : 1, want_table : 1, - want_zones : 1, + split_by_node : 1, + split_by_state : 1, + split_by_removable : 1, + split_by_zones : 1, have_zones : 1; }; + enum { COL_RANGE, COL_SIZE, @@ -194,14 +195,12 @@ static inline struct coldesc *get_column_desc(int num) return &coldescs[ get_column_id(num) ]; } -static inline int has_column(int id) +static inline void reset_split_policy(struct lsmem *l, int enable) { - size_t i; - - for (i = 0; i < ncolumns; i++) - if (columns[i] == id) - return 1; - return 0; + l->split_by_state = enable; + l->split_by_node = enable; + l->split_by_removable = enable; + l->split_by_zones = enable; } static void add_scols_line(struct lsmem *lsmem, struct memory_block *blk) @@ -380,15 +379,15 @@ static int is_mergeable(struct lsmem *lsmem, struct memory_block *blk) return 0; if (curr->index + curr->count != blk->index) return 0; - if (lsmem->want_state && curr->state != blk->state) + if (lsmem->split_by_state && curr->state != blk->state) return 0; - if (lsmem->want_removable && curr->removable != blk->removable) + if (lsmem->split_by_removable && curr->removable != blk->removable) return 0; - if (lsmem->want_node && lsmem->have_nodes) { + if (lsmem->split_by_node && lsmem->have_nodes) { if (curr->node != blk->node) return 0; } - if (lsmem->want_zones && lsmem->have_zones) { + if (lsmem->split_by_zones && lsmem->have_zones) { if (curr->nr_zones != blk->nr_zones) return 0; for (i = 0; i < curr->nr_zones; i++) { @@ -455,8 +454,6 @@ static void read_basic_info(struct lsmem *lsmem) /* The valid_zones sysfs attribute was introduced with kernel 3.18 */ if (path_exist(_PATH_SYS_MEMORY "/memory0/valid_zones")) lsmem->have_zones = 1; - else if (lsmem->want_zones) - warnx(_("Cannot read zones, no valid_zones sysfs attribute present")); } static void __attribute__((__noreturn__)) usage(void) @@ -478,6 +475,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -n, --noheadings don't print headings\n"), out); fputs(_(" -o, --output <list> output columns\n"), out); fputs(_(" -r, --raw use raw output format\n"), out); + fputs(_(" -S, --split <list> split ranges by specified columns\n"), out); fputs(_(" -s, --sysroot <dir> use the specified directory as system root\n"), out); fputs(_(" --summary[=when] print summary information (never,always or only)\n"), out); @@ -500,7 +498,7 @@ int main(int argc, char **argv) .want_summary = 1 }, *lsmem = &_lsmem; - const char *outarg = NULL; + const char *outarg = NULL, *splitarg = NULL; int c; size_t i; @@ -518,12 +516,14 @@ int main(int argc, char **argv) {"pairs", no_argument, NULL, 'P'}, {"raw", no_argument, NULL, 'r'}, {"sysroot", required_argument, NULL, 's'}, + {"split", required_argument, NULL, 'S'}, {"version", no_argument, NULL, 'V'}, {"summary", optional_argument, NULL, LSMEM_OPT_SUMARRY }, {NULL, 0, NULL, 0} }; static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'J', 'P', 'r' }, + { 'S', 'a' }, { 0 } }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; @@ -533,7 +533,7 @@ int main(int argc, char **argv) textdomain(PACKAGE); atexit(close_stdout); - while ((c = getopt_long(argc, argv, "abhJno:Prs:V", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "abhJno:PrS:s:V", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -569,6 +569,9 @@ int main(int argc, char **argv) if(path_set_prefix(optarg)) err(EXIT_FAILURE, _("invalid argument to %s"), "--sysroot"); break; + case 'S': + splitarg = optarg; + break; case 'V': printf(UTIL_LINUX_VERSION); return 0; @@ -642,14 +645,36 @@ int main(int argc, char **argv) err(EXIT_FAILURE, _("Failed to initialize output column")); } - if (has_column(COL_STATE)) - lsmem->want_state = 1; - if (has_column(COL_NODE)) - lsmem->want_node = 1; - if (has_column(COL_REMOVABLE)) - lsmem->want_removable = 1; - if (has_column(COL_ZONES)) - lsmem->want_zones = 1; + if (splitarg) { + int split[ARRAY_SIZE(coldescs)] = { 0 }; + static size_t nsplits = 0; + + reset_split_policy(lsmem, 0); /* disable all */ + + if (strcasecmp(splitarg, "none") == 0) + ; + else if (string_add_to_idarray(splitarg, split, ARRAY_SIZE(split), + &nsplits, column_name_to_id) < 0) + return EXIT_FAILURE; + + for (i = 0; i < nsplits; i++) { + switch (split[i]) { + case COL_STATE: + lsmem->split_by_state = 1; + break; + case COL_NODE: + lsmem->split_by_node = 1; + break; + case COL_REMOVABLE: + lsmem->split_by_removable = 1; + break; + case COL_ZONES: + lsmem->split_by_zones = 1; + break; + } + } + } else + reset_split_policy(lsmem, 1); /* enable all */ /* * Read data and print output |