diff options
Diffstat (limited to 'print_info.c')
-rw-r--r-- | print_info.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/print_info.c b/print_info.c new file mode 100644 index 0000000..6bfcd11 --- /dev/null +++ b/print_info.c @@ -0,0 +1,422 @@ +/* + * print_info.c + * + * Copyright (C) 2011 NEC Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "print_info.h" +#include <time.h> +#include <string.h> + +#define PROGRESS_MAXLEN "50" + +int message_level; +int flag_strerr_message; +int flag_ignore_r_char; /* 0: '\r' is effective. 1: not effective. */ + +void +show_version(void) +{ + MSG("makedumpfile: version " VERSION " (released on " RELEASE_DATE ")\n"); +#ifdef USELZO + MSG("lzo\tenabled\n"); +#else + MSG("lzo\tdisabled\n"); +#endif +#ifdef USESNAPPY + MSG("snappy\tenabled\n"); +#else + MSG("snappy\tdisabled\n"); +#endif + MSG("\n"); +} + +void +print_usage(void) +{ + MSG("\n"); + MSG("LZO support:\n"); +#ifdef USELZO + MSG(" enabled\n"); +#else + MSG(" disabled ('-l' option will be ignored.)\n"); +#endif + MSG("snappy support:\n"); +#ifdef USESNAPPY + MSG(" enabled\n"); +#else + MSG(" disabled ('-p' option will be ignored.)\n"); +#endif + MSG("\n"); + MSG("Usage:\n"); + MSG(" Creating DUMPFILE:\n"); + MSG(" # makedumpfile [-c|-l|-p|-E] [-d DL] [-e] [-x VMLINUX|-i VMCOREINFO] VMCORE\n"); + MSG(" DUMPFILE\n"); + MSG("\n"); + MSG(" Creating DUMPFILE with filtered kernel data specified through filter config\n"); + MSG(" file or eppic macro:\n"); + MSG(" # makedumpfile [-c|-l|-p|-E] [-d DL] -x VMLINUX [--config FILTERCONFIGFILE]\n"); + MSG(" [--eppic EPPICMACRO] VMCORE DUMPFILE\n"); + MSG("\n"); + MSG(" Outputting the dump data in the flattened format to the standard output:\n"); + MSG(" # makedumpfile -F [-c|-l|-p|-E] [-d DL] [-x VMLINUX|-i VMCOREINFO] VMCORE\n"); + MSG("\n"); + MSG(" Rearranging the dump data in the flattened format to a readable DUMPFILE:\n"); + MSG(" # makedumpfile -R DUMPFILE\n"); + MSG("\n"); + MSG(" Split the dump data to multiple DUMPFILEs in parallel:\n"); + MSG(" # makedumpfile --split [OPTION] [-x VMLINUX|-i VMCOREINFO] VMCORE DUMPFILE1\n"); + MSG(" DUMPFILE2 [DUMPFILE3 ..]\n"); + MSG("\n"); + MSG(" Using multiple threads to create DUMPFILE in parallel:\n"); + MSG(" # makedumpfile [OPTION] [-x VMLINUX|-i VMCOREINFO] --num-threads THREADNUM\n"); + MSG(" VMCORE DUMPFILE1\n"); + MSG("\n"); + MSG(" Reassemble multiple DUMPFILEs:\n"); + MSG(" # makedumpfile --reassemble DUMPFILE1 DUMPFILE2 [DUMPFILE3 ..] DUMPFILE\n"); + MSG("\n"); + MSG(" Generating VMCOREINFO:\n"); + MSG(" # makedumpfile -g VMCOREINFO -x VMLINUX\n"); + MSG("\n"); + MSG(" Extracting the dmesg log from a VMCORE:\n"); + MSG(" # makedumpfile --dump-dmesg [-x VMLINUX|-i VMCOREINFO] VMCORE LOGFILE\n"); + MSG("\n"); + MSG("\n"); + MSG(" Creating DUMPFILE of Xen:\n"); + MSG(" # makedumpfile [-c|-l|-p|-E] [--xen-syms XEN-SYMS|--xen-vmcoreinfo VMCOREINFO]\n"); + MSG(" VMCORE DUMPFILE\n"); + MSG("\n"); + MSG(" Filtering domain-0 of Xen:\n"); + MSG(" # makedumpfile [-c|-l|-p|-E] -d DL -x vmlinux VMCORE DUMPFILE\n"); + MSG("\n"); + MSG(" Generating VMCOREINFO of Xen:\n"); + MSG(" # makedumpfile -g VMCOREINFO --xen-syms XEN-SYMS\n"); + MSG("\n"); + MSG("\n"); + MSG(" Creating DUMPFILE from multiple VMCOREs generated on sadump diskset configuration:\n"); + MSG(" # makedumpfile [-c|-l|-p] [-d DL] -x VMLINUX --diskset=VMCORE1 --diskset=VMCORE2\n"); + MSG(" [--diskset=VMCORE3 ..] DUMPFILE\n"); + MSG("\n"); + MSG("\n"); + MSG("Available options:\n"); + MSG(" [-c|-l|-p]:\n"); + MSG(" Compress dump data by each page using zlib for -c option, lzo for -l option\n"); + MSG(" or snappy for -p option. A user cannot specify either of these options with\n"); + MSG(" -E option, because the ELF format does not support compressed data.\n"); + MSG(" THIS IS ONLY FOR THE CRASH UTILITY.\n"); + MSG("\n"); + MSG(" [-e]:\n"); + MSG(" Exclude the page structures (vmemmap) which represent excluded pages.\n"); + MSG(" This greatly shortens the dump of a very large memory system.\n"); + MSG(" The --work-dir option must also be specified, as it will be used\n"); + MSG(" to hold bitmaps and a file of page numbers that are to be excluded.\n"); + MSG(" The -e option will cause a noncyclic dump procedure.\n"); + MSG(" This option is only for x86_64.\n"); + MSG("\n"); + MSG(" [-d DL]:\n"); + MSG(" Specify the type of unnecessary page for analysis.\n"); + MSG(" Pages of the specified type are not copied to DUMPFILE. The page type\n"); + MSG(" marked in the following table is excluded. A user can specify multiple\n"); + MSG(" page types by setting the sum of each page type for Dump_Level (DL).\n"); + MSG(" The maximum of Dump_Level is 31.\n"); + MSG(" Note that Dump_Level for Xen dump filtering is 0 or 1 except on x86_64\n"); + MSG("\n"); + MSG(" | non-\n"); + MSG(" Dump | zero private private user free\n"); + MSG(" Level | page cache cache data page\n"); + MSG(" -------+---------------------------------------\n"); + MSG(" 0 |\n"); + MSG(" 1 | X\n"); + MSG(" 2 | X\n"); + MSG(" 4 | X X\n"); + MSG(" 8 | X\n"); + MSG(" 16 | X\n"); + MSG(" 31 | X X X X X\n"); + MSG("\n"); + MSG(" [-E]:\n"); + MSG(" Create DUMPFILE in the ELF format.\n"); + MSG(" This option cannot be specified with the -c, -l or -p options,\n"); + MSG(" because the ELF format does not support compressed data.\n"); + MSG("\n"); + MSG(" [-x VMLINUX]:\n"); + MSG(" Specify the first kernel's VMLINUX to analyze the first kernel's\n"); + MSG(" memory usage.\n"); + MSG(" The page size of the first kernel and the second kernel should match.\n"); + MSG("\n"); + MSG(" [-i VMCOREINFO]:\n"); + MSG(" Specify VMCOREINFO instead of VMLINUX for analyzing the first kernel's\n"); + MSG(" memory usage.\n"); + MSG(" VMCOREINFO should be made beforehand by makedumpfile with -g option,\n"); + MSG(" and it contains the first kernel's information. This option is necessary\n"); + MSG(" if VMCORE does not contain VMCOREINFO, [-x VMLINUX] is not specified,\n"); + MSG(" and dump_level is 2 or more.\n"); + MSG("\n"); + MSG(" [-g VMCOREINFO]:\n"); + MSG(" Generate VMCOREINFO from the first kernel's VMLINUX.\n"); + MSG(" VMCOREINFO must be generated on the system that is running the first\n"); + MSG(" kernel. With -i option, a user can specify VMCOREINFO generated on the\n"); + MSG(" other system that is running the same first kernel. [-x VMLINUX] must\n"); + MSG(" be specified.\n"); + MSG("\n"); + MSG(" [--config FILTERCONFIGFILE]:\n"); + MSG(" Used in conjunction with -x VMLINUX option, to specify the filter config\n"); + MSG(" file that contains filter commands to filter out desired kernel data\n"); + MSG(" from vmcore while creating DUMPFILE.\n"); + MSG("\n"); + MSG(" [--eppic EPPICMACRO]:\n"); + MSG(" Used in conjunction with -x VMLINUX option, to specify the eppic macro\n"); + MSG(" file that contains filter rules or directory that contains eppic macro\n"); + MSG(" files to filter out desired kernel data from vmcore while creating DUMPFILE.\n"); + MSG(" When directory is specified, all the eppic macros in the directory are\n"); + MSG(" processed\n"); + MSG("\n"); + MSG(" [-F]:\n"); + MSG(" Output the dump data in the flattened format to the standard output\n"); + MSG(" for transporting the dump data by SSH.\n"); + MSG(" Analysis tools cannot read the flattened format directly. For analysis,\n"); + MSG(" the dump data in the flattened format should be rearranged to a readable\n"); + MSG(" DUMPFILE by -R option.\n"); + MSG("\n"); + MSG(" [-R]:\n"); + MSG(" Rearrange the dump data in the flattened format from the standard input\n"); + MSG(" to a readable DUMPFILE.\n"); + MSG("\n"); + MSG(" [--split]:\n"); + MSG(" Split the dump data to multiple DUMPFILEs in parallel. If specifying\n"); + MSG(" DUMPFILEs on different storage devices, a device can share I/O load with\n"); + MSG(" other devices and it reduces time for saving the dump data. The file size\n"); + MSG(" of each DUMPFILE is smaller than the system memory size which is divided\n"); + MSG(" by the number of DUMPFILEs.\n"); + MSG(" This feature supports only the kdump-compressed format.\n"); + MSG("\n"); + MSG(" [--num-threads THREADNUM]:\n"); + MSG(" Using multiple threads to read and compress data of each page in parallel.\n"); + MSG(" And it will reduces time for saving DUMPFILE.\n"); + MSG(" Note that if the usable cpu number is less than the thread number, it may\n"); + MSG(" lead to great performance degradation.\n"); + MSG(" This feature only supports creating DUMPFILE in kdump-compressed format from\n"); + MSG(" VMCORE in kdump-compressed format or elf format.\n"); + MSG("\n"); + MSG(" [--reassemble]:\n"); + MSG(" Reassemble multiple DUMPFILEs, which are created by --split option,\n"); + MSG(" into one DUMPFILE. dumpfile1 and dumpfile2 are reassembled into dumpfile.\n"); + MSG("\n"); + MSG(" [-b <order>]\n"); + MSG(" Specify the cache 2^order pages in ram when generating DUMPFILE before\n"); + MSG(" writing to output. The default value is 4.\n"); + MSG("\n"); + MSG(" [--cyclic-buffer BUFFER_SIZE]:\n"); + MSG(" Specify the buffer size in kilo bytes for bitmap data.\n"); + MSG(" Filtering processing will be divided into multi cycles to fix the memory\n"); + MSG(" consumption, the number of cycles is represented as:\n"); + MSG("\n"); + MSG(" num_of_cycles = system_memory / \n"); + MSG(" (BUFFER_SIZE * 1024 * bit_per_bytes * page_size)\n"); + MSG("\n"); + MSG(" The lesser number of cycles, the faster working speed is expected.\n"); + MSG(" By default, BUFFER_SIZE will be calculated automatically depending on\n"); + MSG(" system memory size, so ordinary users don't need to specify this option.\n"); + MSG("\n"); + MSG(" [--splitblock-size SPLITBLOCK_SIZE]:\n"); + MSG(" Specify the splitblock size in kilo bytes for analysis with --split.\n"); + MSG(" If --splitblock N is specified, difference of each splitted dumpfile\n"); + MSG(" size is at most N kilo bytes.\n"); + MSG("\n"); + MSG(" [--work-dir]:\n"); + MSG(" Specify the working directory for the temporary bitmap file.\n"); + MSG(" If this option isn't specified, the bitmap will be saved on memory.\n"); + MSG(" Filtering processing has to do 2 pass scanning to fix the memory consumption,\n"); + MSG(" but it can be avoided by using working directory on file system.\n"); + MSG(" So if you specify this option, the filtering speed may be bit faster.\n"); + MSG("\n"); + MSG(" [--non-mmap]:\n"); + MSG(" Never use mmap(2) to read VMCORE even if it supports mmap(2).\n"); + MSG(" Generally, reading VMCORE with mmap(2) is faster than without it,\n"); + MSG(" so ordinary users don't need to specify this option.\n"); + MSG(" This option is mainly for debugging.\n"); + MSG("\n"); + MSG(" [--xen-syms XEN-SYMS]:\n"); + MSG(" Specify the XEN-SYMS to analyze Xen's memory usage.\n"); + MSG("\n"); + MSG(" [--xen-vmcoreinfo VMCOREINFO]:\n"); + MSG(" Specify the VMCOREINFO of Xen to analyze Xen's memory usage.\n"); + MSG("\n"); + MSG(" [--xen_phys_start XEN_PHYS_START_ADDRESS]:\n"); + MSG(" This option is only for x86_64.\n"); + MSG(" Specify the XEN_PHYS_START_ADDRESS, if the xen code/data is relocatable\n"); + MSG(" and VMCORE does not contain XEN_PHYS_START_ADDRESS in the CRASHINFO.\n"); + MSG("\n"); + MSG(" [-X]:\n"); + MSG(" Exclude all the user domain pages from Xen kdump's VMCORE, and extract\n"); + MSG(" the part of Xen and domain-0.\n"); + MSG("\n"); + MSG(" [--diskset=VMCORE]:\n"); + MSG(" Specify multiple VMCOREs created on sadump diskset configuration the same\n"); + MSG(" number of times as the number of VMCOREs in increasing order from left to\n"); + MSG(" right.\n"); + MSG("\n"); + MSG(" [--message-level ML]:\n"); + MSG(" Specify the message types.\n"); + MSG(" Users can restrict output printed by specifying Message_Level (ML) with\n"); + MSG(" this option. The message type marked with an X in the following table is\n"); + MSG(" printed. For example, according to the table, specifying 7 as ML means\n"); + MSG(" progress indicator, common message, and error message are printed, and\n"); + MSG(" this is a default value.\n"); + MSG(" Note that the maximum value of message_level is 31.\n"); + MSG("\n"); + MSG(" Message | progress common error debug report\n"); + MSG(" Level | indicator message message message message\n"); + MSG(" ---------+------------------------------------------------------\n"); + MSG(" 0 |\n"); + MSG(" 1 | X\n"); + MSG(" 2 | X\n"); + MSG(" 4 | X\n"); + MSG(" * 7 | X X X\n"); + MSG(" 8 | X\n"); + MSG(" 16 | X\n"); + MSG(" 31 | X X X X X\n"); + MSG("\n"); + MSG(" [--vtop VIRTUAL_ADDRESS]:\n"); + MSG(" This option is useful, when user debugs the translation problem\n"); + MSG(" of virtual address. If specifying the VIRTUAL_ADDRESS, its physical\n"); + MSG(" address is printed.\n"); + MSG("\n"); + MSG(" [--dump-dmesg]:\n"); + MSG(" This option overrides the normal behavior of makedumpfile. Instead of\n"); + MSG(" compressing and filtering a VMCORE to make it smaller, it simply\n"); + MSG(" extracts the dmesg log from a VMCORE and writes it to the specified\n"); + MSG(" LOGFILE. If a VMCORE does not contain VMCOREINFO for dmesg, it is\n"); + MSG(" necessary to specify [-x VMLINUX] or [-i VMCOREINFO].\n"); + MSG("\n"); + MSG(" [--mem-usage]:\n"); + MSG(" This option is only for x86_64.\n"); + MSG(" This option is used to show the page numbers of current system in different\n"); + MSG(" use. It should be executed in 1st kernel. By the help of this, user can know\n"); + MSG(" how many pages is dumpable when different dump_level is specified. It analyzes\n"); + MSG(" the 'System Ram' and 'kernel text' program segment of /proc/kcore excluding\n"); + MSG(" the crashkernel range, then calculates the page number of different kind per\n"); + MSG(" vmcoreinfo. So currently /proc/kcore need be specified explicitly.\n"); + MSG("\n"); + MSG(" [-D]:\n"); + MSG(" Print debugging message.\n"); + MSG("\n"); + MSG(" [-f]:\n"); + MSG(" Overwrite DUMPFILE even if it already exists.\n"); + MSG(" Force mem-usage to work with older kernel as well.\n"); + MSG("\n"); + MSG(" [-h, --help]:\n"); + MSG(" Show help message and LZO/snappy support status (enabled/disabled).\n"); + MSG("\n"); + MSG(" [-v]:\n"); + MSG(" Show the version of makedumpfile.\n"); + MSG("\n"); + MSG(" VMLINUX:\n"); + MSG(" This is a pathname to the first kernel's vmlinux.\n"); + MSG(" This file must have the debug information of the first kernel to analyze\n"); + MSG(" the first kernel's memory usage.\n"); + MSG("\n"); + MSG(" VMCORE:\n"); + MSG(" This is a pathname to the first kernel's memory core image.\n"); + MSG(" This argument is generally /proc/vmcore.\n"); + MSG("\n"); + MSG(" DUMPFILE:\n"); + MSG(" This is a pathname to a file created by this command.\n"); + MSG("\n"); + MSG(" XEN-SYMS:\n"); + MSG(" This is a pathname to the xen-syms.\n"); + MSG(" This file must have the debug information of Xen to analyze\n"); + MSG(" Xen's memory usage.\n"); + MSG("\n"); +} + +static void calc_delta(struct timeval *tv_start, struct timeval *delta) +{ + struct timeval tv_end; + + gettimeofday(&tv_end, NULL); + delta->tv_sec = tv_end.tv_sec - tv_start->tv_sec; + delta->tv_usec = tv_end.tv_usec - tv_start->tv_usec; + if (delta->tv_usec < 0) { + delta->tv_sec--; + delta->tv_usec += 1000000; + } +} + +/* produce less than 12 bytes on msg */ +static int eta_to_human_short (unsigned long secs, char* msg) +{ + strcpy(msg, "eta: "); + msg += strlen("eta: "); + if (secs < 100) + sprintf(msg, "%lus", secs); + else if (secs < 100 * 60) + sprintf(msg, "%lum%lus", secs / 60, secs % 60); + else if (secs < 48 * 3600) + sprintf(msg, "%luh%lum", secs / 3600, (secs / 60) % 60); + else if (secs < 100 * 86400) + sprintf(msg, "%lud%luh", secs / 86400, (secs / 3600) % 24); + else + sprintf(msg, ">2day"); + return 0; +} + + +void +print_progress(const char *msg, unsigned long current, unsigned long end, struct timeval *start) +{ + unsigned progress; /* in promilles (tenths of a percent) */ + time_t tm; + static time_t last_time = 0; + static unsigned int lapse = 0; + static const char *spinner = "/|\\-"; + struct timeval delta; + unsigned long eta; + char eta_msg[16] = " "; + + if (current < end) { + tm = time(NULL); + if (tm - last_time < 1) + return; + last_time = tm; + progress = current * 1000 / end; + } else + progress = 1000; + + if (start != NULL && progress != 0) { + calc_delta(start, &delta); + eta = 1000 * delta.tv_sec + delta.tv_usec / 1000; + eta = eta / progress - delta.tv_sec; + eta_to_human_short(eta, eta_msg); + } + if (flag_ignore_r_char) { + PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3u.%u %%] %c %16s\n", + msg, progress / 10, progress % 10, + spinner[lapse % 4], eta_msg); + } else { + PROGRESS_MSG("\r"); + PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3u.%u %%] %c %16s", + msg, progress / 10, progress % 10, + spinner[lapse % 4], eta_msg); + } + lapse++; +} + +void +print_execution_time(char *step_name, struct timeval *tv_start) +{ + struct timeval delta; + + calc_delta(tv_start, &delta); + REPORT_MSG("STEP [%s] : %ld.%06ld seconds\n", + step_name, delta.tv_sec, delta.tv_usec); +} + |