示例#1
0
/*
 ***************************************************************************
 * Display stats since system startup.
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 ***************************************************************************
 */
void write_stats_startup(int curr)
{
	int i;

	/* Set to 0 previous structures corresponding to boot time */
	memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
	record_hdr[!curr].record_type = R_STATS;
	record_hdr[!curr].hour        = record_hdr[curr].hour;
	record_hdr[!curr].minute      = record_hdr[curr].minute;
	record_hdr[!curr].second      = record_hdr[curr].second;
	record_hdr[!curr].ust_time    = record_hdr[curr].ust_time;

	for (i = 0; i < NR_ACT; i++) {
		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			memset(act[i]->buf[!curr], 0, act[i]->msize * act[i]->nr * act[i]->nr2);
		}
	}

	flags |= S_F_SINCE_BOOT;
	dis = TRUE;

	write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET, ALL_ACTIVITIES);

	exit(0);
}
示例#2
0
/*
 ***************************************************************************
 * Determine if a stat header line has to be displayed.
 *
 * RETURNS:
 * TRUE if a header line has to be displayed.
 ***************************************************************************
*/
int check_line_hdr(void)
{
	int i, rc = FALSE;

	/* Get number of options entered on the command line */
	if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
		return TRUE;

	for (i = 0; i < NR_ACT; i++) {
		if (IS_SELECTED(act[i]->options)) {
			/* Special processing for activities using a bitmap */
			if (act[i]->bitmap) {
				if (count_bits(act[i]->bitmap->b_array,
					       BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
					rc = TRUE;
				}
			}
			else if (act[i]->nr > 1) {
				rc = TRUE;
			}
			/* Stop now since we have only one selected activity */
			break;
		}
	}

	return rc;
}
示例#3
0
/*
 ***************************************************************************
 * Display the field list (used eg. in database format).
 *
 * IN:
 * @act_d	Activity to display, or ~0 for all.
 ***************************************************************************
 */
void list_fields(unsigned int act_id)
{
	int i, j;
	unsigned int msk;
	char *hl;
	char hline[HEADER_LINE_LEN] = "";

	printf("# hostname;interval;timestamp");

	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			if (!HAS_MULTIPLE_OUTPUTS(act[i]->options)) {
				printf(";%s", act[i]->hdr_line);
				if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) {
					printf("[...]");
				}
			}
			else {
				msk = 1;
				strncpy(hline, act[i]->hdr_line, HEADER_LINE_LEN - 1);
				hline[HEADER_LINE_LEN - 1] = '\0';
				for (hl = strtok(hline, "|"); hl; hl = strtok(NULL, "|"), msk <<= 1) {
					if ((hl != NULL) && ((act[i]->opt_flags & 0xff) & msk)) {
						if (strchr(hl, '&')) {
							j = strcspn(hl, "&");
							if ((act[i]->opt_flags & 0xff00) & (msk << 8)) {
								/* Display whole header line */
								*(hl + j) = ';';
								printf(";%s", hl);
							}
							else {
								/* Display only the first part of the header line */
								*(hl + j) = '\0';
								printf(";%s", hl);
							}
							*(hl + j) = '&';
						}
						else {
							printf(";%s", hl);
						}
						if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) {
							printf("[...]");
						}
					}
				}
			}
		}
	}
	printf("\n");
}
示例#4
0
/*
 ***************************************************************************
 * Check that every selected activity actually belongs to the sequence list.
 * If not, then the activity should be unselected since it will not be sent
 * by sadc. An activity can be not sent if its number of items is null.
 *
 * IN:
 * @act_nr	Size of sequence list.
 ***************************************************************************
 */
void reverse_check_act(unsigned int act_nr)
{
	int i, j;

	for (i = 0; i < NR_ACT; i++) {

		if (IS_SELECTED(act[i]->options)) {

			for (j = 0; j < act_nr; j++) {
				if (id_seq[j] == act[i]->id)
					break;
			}
			if (j == act_nr)
				act[i]->options &= ~AO_SELECTED;
		}
	}
}
示例#5
0
/*
 ***************************************************************************
 * Print statistics average.
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @read_from_file	Set to TRUE if stats are read from a system activity
 * 			data file.
 * @act_id		Activity that can be displayed, or ~0 for all.
 *			Remember that when reading stats from a file, only
 *			one activity can be displayed at a time.
 ***************************************************************************
 */
void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
{
	int i;
	unsigned long long itv, g_itv;
	static __nr_t cpu_nr = -1;

	if (cpu_nr < 0)
		cpu_nr = act[get_activity_position(act, A_CPU)]->nr;

	/* Interval value in jiffies */
	g_itv = get_interval(record_hdr[2].uptime, record_hdr[curr].uptime);

	if (cpu_nr > 1)
		itv = get_interval(record_hdr[2].uptime0, record_hdr[curr].uptime0);
	else
		itv = g_itv;

	strncpy(timestamp[curr], _("Average:"), TIMESTAMP_LEN);
	timestamp[curr][TIMESTAMP_LEN - 1] = '\0';
	strcpy(timestamp[!curr], timestamp[curr]);

	/* Test stdout */
	TEST_STDOUT(STDOUT_FILENO);

	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			/* Display current average activity statistics */
			(*act[i]->f_print_avg)(act[i], 2, curr,
					       NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
		}
	}

	if (read_from_file) {
		/*
		 * Reset number of lines printed only if we read stats
		 * from a system activity file.
		 */
		avg_count = 0;
	}
}
/*
 ***************************************************************************
 * Print statistics average
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @read_from_file	Set to TRUE if stats are read from a system activity
 * 			data file.
 * @act_id		Activity that can be displayed, or ~0 for all.
 *			Remember that when reading stats from a file, only
 *			one activity can be displayed at a time.
 ***************************************************************************
 */
void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
{
	int i;
	unsigned long long itv, g_itv;
	static __nr_t cpu_nr = -1;
	
	if (cpu_nr < 0)
		cpu_nr = act[get_activity_position(act, A_CPU)]->nr;

	/* Interval value in jiffies */
	g_itv = get_interval(record_hdr[2].uptime, record_hdr[curr].uptime);

	if (cpu_nr > 1)
		itv = get_interval(record_hdr[2].uptime0, record_hdr[curr].uptime0);
	else
		itv = g_itv;

	strcpy(timestamp[curr], _("Average:"));
	strcpy(timestamp[!curr], timestamp[curr]);
	
	/* Test stdout */
	TEST_STDOUT(STDOUT_FILENO);
	
	for (i = 0; i < NR_ACT; i++) {
		
		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;
		
		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			/* Display current average activity statistics */
			if (NEEDS_GLOBAL_ITV(act[i]->options))
				(*act[i]->f_print_avg)(act[i], 2, curr, g_itv);
			else
				(*act[i]->f_print_avg)(act[i], 2, curr, itv);
		}
	}

	if (read_from_file) {
		/* Reset counters only if we read stats from a system activity file */
		memset(&asum, 0, STATS_SUM_SIZE);
	}
}
示例#7
0
/*
 ***************************************************************************
 * write_mech_stats() -
 * Replace the old write_stats_for_ppc() and write_stats_for_db(),
 * making it easier for them to remain in sync and print the same data.
 *
 * IN:
 * @curr	Index in array for current sample statistics.
 * @dt		Interval of time in seconds.
 * @itv		Interval of time in jiffies.
 * @g_itv	Interval of time in jiffies multiplied by the number of
 * 		processors.
 * @cur_date	Date string for current record.
 * @cur_time	Time string for current record.
 * @act_id	Activity to display, or ~0 for all.
 ***************************************************************************
 */
void write_mech_stats(int curr, unsigned long dt, unsigned long long itv,
		      unsigned long long g_itv, char *cur_date, char *cur_time,
		      unsigned int act_id)
{
	int i;
	char pre[80], temp[80];	/* Text at beginning of each line */
	int isdb = (format == F_DB_OUTPUT);

	/* This substring appears on every output line, preformat it here */
	snprintf(pre, 80, "%s%s%ld%s",
		 file_hdr.sa_nodename, seps[isdb], dt, seps[isdb]);
	if (strlen(cur_date)) {
		snprintf(temp, 80, "%s%s ", pre, cur_date);
	}
	else {
		strcpy(temp, pre);
	}
	snprintf(pre, 80, "%s%s%s", temp, cur_time,
		 strlen(cur_date) && !PRINT_LOCAL_TIME(flags) &&
		 !PRINT_TRUE_TIME(flags) ? " UTC" : "");
	pre[79] = '\0';

	if (DISPLAY_HORIZONTALLY(flags)) {
		printf("%s", pre);
	}

	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			(*act[i]->f_render)(act[i], isdb, pre, curr,
					    NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
		}
	}

	if (DISPLAY_HORIZONTALLY(flags)) {
		printf("\n");
	}
}
示例#8
0
/*
 ***************************************************************************
 * Display the field list (used eg. in database format).
 *
 * IN:
 * @act_d	Activity to display, or ~0 for all.
 ***************************************************************************
 */
void list_fields(unsigned int act_id)
{
	int i;
	unsigned int msk;
	char *hl;
	char hline[HEADER_LINE_LEN];
	
	printf("# hostname;interval;timestamp");
	
	for (i = 0; i < NR_ACT; i++) {
		
		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;
		
		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			if (!HAS_MULTIPLE_OUTPUTS(act[i]->options)) {
				printf(";%s", act[i]->hdr_line);
				if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) {
					printf("[...]");
				}
			}
			else {
				msk = 1;
				strcpy(hline, act[i]->hdr_line);
				for (hl = strtok(hline, "|"); hl; hl = strtok(NULL, "|"), msk <<= 1) {
					if ((hl != NULL) && (act[i]->opt_flags & msk)) {
						printf(";%s", hl);
						if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) {
							printf("[...]");
						}
					}
				}
			}
		}
	}
	printf("\n");
}
示例#9
0
/*
 ***************************************************************************
 * Main entry to the sar program.
 ***************************************************************************
 */
int main(int argc, char **argv)
{
	int i, rc, opt = 1, args_idx = 2;
	int fd[2];
	int day_offset = 0;
	char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
	char ltemp[20];

	/* Get HZ */
	get_HZ();

	/* Compute page shift in kB */
	get_kb_shift();

	from_file[0] = to_file[0] = '\0';

#ifdef USE_NLS
	/* Init National Language Support */
	init_nls();
#endif

	tm_start.use = tm_end.use = FALSE;

	/* Allocate and init activity bitmaps */
	allocate_bitmaps(act);

	init_structures();

	/* Process options */
	while (opt < argc) {

		if (!strcmp(argv[opt], "-I")) {
			if (argv[++opt]) {
				/* Parse -I option */
				if (parse_sar_I_opt(argv, &opt, act)) {
					usage(argv[0]);
				}
			}
			else {
				usage(argv[0]);
			}
		}

		else if (!strcmp(argv[opt], "-D")) {
			/* Option to tell sar to write to saYYYYMMDD data files */
			flags |= S_F_SA_YYYYMMDD;
			opt++;
		}

		else if (!strcmp(argv[opt], "-P")) {
			/* Parse -P option */
			if (parse_sa_P_opt(argv, &opt, &flags, act)) {
				usage(argv[0]);
			}
		}

		else if (!strcmp(argv[opt], "-o")) {
			if (to_file[0]) {
				/* Output file already specified */
				usage(argv[0]);
			}
			/* Save stats to a file */
			if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
			    (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
				strncpy(to_file, argv[opt++], MAX_FILE_LEN);
				to_file[MAX_FILE_LEN - 1] = '\0';
			}
			else {
				strcpy(to_file, "-");
			}
		}

		else if (!strcmp(argv[opt], "-f")) {
			if (from_file[0]) {
				/* Input file already specified */
				usage(argv[0]);
			}
			/* Read stats from a file */
			if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
			    (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
				strncpy(from_file, argv[opt++], MAX_FILE_LEN);
				from_file[MAX_FILE_LEN - 1] = '\0';
				/* Check if this is an alternate directory for sa files */
				check_alt_sa_dir(from_file, day_offset, -1);
			}
			else {
				set_default_file(from_file, day_offset, -1);
			}
		}

		else if (!strcmp(argv[opt], "-s")) {
			/* Get time start */
			if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) {
				usage(argv[0]);
			}
		}

		else if (!strcmp(argv[opt], "-e")) {
			/* Get time end */
			if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) {
				usage(argv[0]);
			}
		}

		else if (!strcmp(argv[opt], "-h")) {
			/* Display help message */
			display_help(argv[0]);
		}

		else if (!strcmp(argv[opt], "-i")) {
			if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
				usage(argv[0]);
			}
			interval = atol(argv[opt++]);
			if (interval < 1) {
				usage(argv[0]);
			}
			flags |= S_F_INTERVAL_SET;
		}

		else if (!strcmp(argv[opt], "-m")) {
			if (argv[++opt]) {
				/* Parse option -m */
				if (parse_sar_m_opt(argv, &opt, act)) {
					usage(argv[0]);
				}
			}
			else {
				usage(argv[0]);
			}
		}

		else if (!strcmp(argv[opt], "-n")) {
			if (argv[++opt]) {
				/* Parse option -n */
				if (parse_sar_n_opt(argv, &opt, act)) {
					usage(argv[0]);
				}
			}
			else {
				usage(argv[0]);
			}
		}

		else if ((strlen(argv[opt]) > 1) &&
			 (strlen(argv[opt]) < 4) &&
			 !strncmp(argv[opt], "-", 1) &&
			 (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) {
			day_offset = atoi(argv[opt++] + 1);
		}

		else if (!strncmp(argv[opt], "-", 1)) {
			/* Other options not previously tested */
			if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) {
				if (rc == 1) {
					usage(argv[0]);
				}
				exit(1);
			}
			opt++;
		}

		else if (interval < 0) {
			/* Get interval */
			if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
				usage(argv[0]);
			}
			interval = atol(argv[opt++]);
			if (interval < 0) {
				usage(argv[0]);
			}
		}

		else {
			/* Get count value */
			if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
			    !interval) {
				usage(argv[0]);
			}
			if (count) {
				/* Count parameter already set */
				usage(argv[0]);
			}
			count = atol(argv[opt++]);
			if (count < 1) {
				usage(argv[0]);
			}
		}
	}

	/* 'sar' is equivalent to 'sar -f' */
	if ((argc == 1) ||
	    ((interval < 0) && !from_file[0] && !to_file[0])) {
		set_default_file(from_file, day_offset, -1);
	}

	if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) {
		tm_end.tm_hour += 24;
	}

	/*
	 * Check option dependencies.
	 */
	/* You read from a file OR you write to it... */
	if (from_file[0] && to_file[0]) {
		fprintf(stderr, _("-f and -o options are mutually exclusive\n"));
		exit(1);
	}
	/* Use time start or option -i only when reading stats from a file */
	if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) {
		fprintf(stderr,
			_("Not reading from a system activity file (use -f option)\n"));
		exit(1);
	}
	/* Don't print stats since boot time if -o or -f options are used */
	if (!interval && (from_file[0] || to_file[0])) {
		usage(argv[0]);
	}

	/* Cannot enter a day shift with -o option */
	if (to_file[0] && day_offset) {
		usage(argv[0]);
	}

	if (USE_PRETTY_OPTION(flags)) {
		dm_major = get_devmap_major();
	}

	if (!count) {
		/*
		 * count parameter not set: Display all the contents of the file
		 * or generate a report continuously.
		 */
		count = -1;
	}

	/* Default is CPU activity... */
	select_default_activity(act);

	/* Reading stats from file: */
	if (from_file[0]) {
		if (interval < 0) {
			interval = 1;
		}

		/* Read stats from file */
		read_stats_from_file(from_file);

		/* Free stuctures and activity bitmaps */
		free_bitmaps(act);
		free_structures(act);

		return 0;
	}

	/* Reading stats from sadc: */

	/* Create anonymous pipe */
	if (pipe(fd) == -1) {
		perror("pipe");
		exit(4);
	}

	switch (fork()) {

	case -1:
		perror("fork");
		exit(4);
		break;

	case 0: /* Child */
		if (dup2(fd[1], STDOUT_FILENO) < 0) {
			perror("dup2");
			exit(4);
		}
		CLOSE_ALL(fd);

		/*
		 * Prepare options for sadc.
		 */
		/* Program name */
		salloc(0, SADC);

		/* Interval value */
		if (interval < 0) {
			usage(argv[0]);
		}
		else if (!interval) {
			strcpy(ltemp, "1");
		}
		else {
			sprintf(ltemp, "%ld", interval);
		}
		salloc(1, ltemp);

		/* Count number */
		if (count >= 0) {
			sprintf(ltemp, "%ld", count + 1);
			salloc(args_idx++, ltemp);
		}

		/* Flags to be passed to sadc */
		salloc(args_idx++, "-z");

		/* Writing data to a file (option -o) */
		if (to_file[0]) {
			/* Set option -D if entered */
			if (USE_SA_YYYYMMDD(flags)) {
				salloc(args_idx++, "-D");
			}
			/* Collect all possible activities (option -S XALL for sadc) */
			salloc(args_idx++, "-S");
			salloc(args_idx++, K_XALL);
			/* Outfile arg */
			salloc(args_idx++, to_file);
		}
		else {
			/*
			 * If option -o hasn't been used, then tell sadc
			 * to collect only activities that will be displayed.
			 */
			int act_id = 0;

			for (i = 0; i < NR_ACT; i++) {
				if (IS_SELECTED(act[i]->options)) {
					act_id |= act[i]->group;
				}
			}
			if (act_id) {
				act_id <<= 8;
				snprintf(ltemp, 19, "%d", act_id);
				ltemp[19] = '\0';
				salloc(args_idx++, "-S");
				salloc(args_idx++, ltemp);
			}
		}

		/* Last arg is NULL */
		args[args_idx] = NULL;

		/* Call now the data collector */
		execv(SADC_PATH, args);
		execvp(SADC, args);
		/*
		 * Note: Don't use execl/execlp since we don't have a fixed number of
		 * args to give to sadc.
		 */
		fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC);
		perror("exec");
		exit(4);
		break;

	default: /* Parent */
		if (dup2(fd[0], STDIN_FILENO) < 0) {
			perror("dup2");
			exit(4);
		}
		CLOSE_ALL(fd);

		/* Get now the statistics */
		read_stats();

		break;
	}

	/* Free structures and activity bitmaps */
	free_bitmaps(act);
	free_structures(act);

	return 0;
}
示例#10
0
文件: sar.c 项目: gagoel/sysstat
/*
 ***************************************************************************
 * Print system statistics.
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @read_from_file	Set to TRUE if stats are read from a system activity
 * 			data file.
 * @use_tm_start	Set to TRUE if option -s has been used.
 * @use_tm_end		Set to TRUE if option -e has been used.
 * @reset		Set to TRUE if last_uptime variable should be
 * 			reinitialized (used in next_slice() function).
 * @act_id		Activity that can be displayed or ~0 for all.
 *			Remember that when reading stats from a file, only
 *			one activity can be displayed at a time.
 * @reset_cd		TRUE if static cross_day variable should be reset
 * 			(see below).
 *
 * OUT:
 * @cnt			Number of remaining lines to display.
 *
 * RETURNS:
 * 1 if stats have been successfully displayed, and 0 otherwise.
 ***************************************************************************
 */
int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
		int use_tm_end, int reset, unsigned int act_id, int reset_cd)
{
	int i;
	unsigned long long itv, g_itv;
	static int cross_day = 0;
	static __nr_t cpu_nr = -1;

	if (cpu_nr < 0)
		cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;

	if (reset_cd) {
		/*
		 * cross_day is a static variable that is set to 1 when the first
		 * record of stats from a new day is read from a unique data file
		 * (in the case where the file contains data from two consecutive
		 * days). When set to 1, every following records timestamp will
		 * have its hour value increased by 24.
		 * Yet when a new activity (being read from the file) is going to
		 * be displayed, we start reading the file from the beginning
		 * again, and so cross_day should be reset in this case.
		 */
		cross_day = 0;
	}

	/* Check time (1) */
	if (read_from_file) {
		if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
				reset, interval))
			/* Not close enough to desired interval */
			return 0;
	}

	/* Set previous timestamp */
	if (set_record_timestamp_string(!curr, timestamp[!curr], 16))
		return 0;
	/* Set current timestamp */
	if (set_record_timestamp_string(curr,  timestamp[curr],  16))
		return 0;

	/* Check if we are beginning a new day */
	if (use_tm_start && record_hdr[!curr].ust_time &&
	    (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
	    (record_hdr[curr].hour < record_hdr[!curr].hour)) {
		cross_day = 1;
	}

	if (cross_day) {
		/*
		 * This is necessary if we want to properly handle something like:
		 * sar -s time_start -e time_end with
		 * time_start(day D) > time_end(day D+1)
		 */
		rectime.tm_hour +=24;
	}

	/* Check time (2) */
	if (use_tm_start && (datecmp(&rectime, &tm_start) < 0))
		/* it's too soon... */
		return 0;

	/* Get interval values */
	get_itv_value(&record_hdr[curr], &record_hdr[!curr],
		      cpu_nr, &itv, &g_itv);

	/* Check time (3) */
	if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) {
		/* It's too late... */
		*cnt = 0;
		return 0;
	}

	avg_count++;

	/* Test stdout */
	TEST_STDOUT(STDOUT_FILENO);

	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			/* Display current activity statistics */
			(*act[i]->f_print)(act[i], !curr, curr,
					   NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
		}
	}

	return 1;
}
示例#11
0
/*
 ***************************************************************************
 * Display file contents in selected format (logic #2).
 * Logic #2:	Grouped by activity. Sorted by timestamp. Stop on RESTART
 * 		records.
 * Formats:	ppc, CSV
 *
 * IN:
 * @ifd		File descriptor of input file.
 * @file_actlst	List of (known or unknown) activities in file.
 * @cpu_nr	Number of processors for current activity data file.
 * @rectime	Structure where timestamp (expressed in local time or in UTC
 *		depending on whether options -T/-t have been used or not) can
 *		be saved for current record.
 * @loctime	Structure where timestamp (expressed in local time) can be
 *		saved for current record.
 * @file	Name of file being read.
 * @file_magic	file_magic structure filled with file magic header data.
 ***************************************************************************
 */
void logic2_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr,
			 struct tm *rectime, struct tm *loctime, char *file,
			 struct file_magic *file_magic)
{
	int i, p;
	int curr = 1, rtype;
	int eosaf = TRUE, reset = FALSE;
	long cnt = 1;
	off_t fpos;

	/* Read system statistics from file */
	do {
		/*
		 * If this record is a special (RESTART or COMMENT) one, print it and
		 * (try to) get another one.
		 */
		do {
			if (read_next_sample(ifd, IGNORE_NOTHING, 0,
					     file, &rtype, 0, file_magic, file_actlst,
					     rectime, loctime))
				/* End of sa data file */
				return;
		}
		while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
		       (tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
		       (tm_end.use && (datecmp(loctime, &tm_end) >= 0)));

		/* Save the first stats collected. Used for example in next_slice() function */
		copy_structures(act, id_seq, record_hdr, 2, 0);

		/* Set flag to reset last_uptime variable. Should be done after a LINUX RESTART record */
		reset = TRUE;

		/* Save current file position */
		if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
			perror("lseek");
			exit(2);
		}

		/* Read and write stats located between two possible Linux restarts */

		if (DISPLAY_HORIZONTALLY(flags)) {
			/*
			 * If stats are displayed horizontally, then all activities
			 * are printed on the same line.
			 */
			rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
					  ALL_ACTIVITIES, &reset, file_actlst,
					  cpu_nr, rectime, loctime, file, file_magic);
		}
		else {
			/* For each requested activity... */
			for (i = 0; i < NR_ACT; i++) {

				if (!id_seq[i])
					continue;

				p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
				if (!IS_SELECTED(act[p]->options))
					continue;

				if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
					rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
							  act[p]->id, &reset, file_actlst,
							  cpu_nr, rectime, loctime, file,
							  file_magic);
				}
				else {
					unsigned int optf, msk;

					optf = act[p]->opt_flags;

					for (msk = 1; msk < 0x100; msk <<= 1) {
						if ((act[p]->opt_flags & 0xff) & msk) {
							act[p]->opt_flags &= (0xffffff00 + msk);

							rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
									  act[p]->id, &reset, file_actlst,
									  cpu_nr, rectime, loctime, file,
									  file_magic);
							act[p]->opt_flags = optf;
						}
					}
				}
			}
		}

		if (!cnt) {
			/* Go to next Linux restart, if possible */
			do {
				eosaf = read_next_sample(ifd, IGNORE_RESTART | DONT_READ_VOLATILE,
							 curr, file, &rtype, 0, file_magic,
							 file_actlst, rectime, loctime);
			}
			while (!eosaf && (rtype != R_RESTART));
		}

		/*
		 * The last record we read was a RESTART one: Print it.
		 * NB: Unlike COMMENTS records (which are displayed for each
		 * activity), RESTART ones are only displayed once.
		 */
		if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
			print_special_record(&record_hdr[curr], flags, &tm_start, &tm_end,
					     R_RESTART, ifd, rectime, loctime, file, 0,
					     file_magic, &file_hdr, act, fmt[f_position]);
		}
	}
	while (!eosaf);
}
示例#12
0
/*
 ***************************************************************************
 * Display activities for non textual formats.
 *
 * IN:
 * @ifd		File descriptor of input file.
 * @file_actlst	List of (known or unknown) activities in file.
 * @cpu_nr	Number of processors for current activity data file.
 * @rectime	Structure where timestamp (expressed in local time or in UTC
 *		depending on whether option -t has been used or not) can be
 *		saved for current record.
 * @loctime	Structure where timestamp (expressed in local time) can be
 *		saved for current record.
 ***************************************************************************
 */
void main_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr,
		       struct tm *rectime, struct tm *loctime)
{
	int i, p;
	int curr = 1, rtype;
	int eosaf = TRUE, reset = FALSE;
	long cnt = 1;
	off_t fpos;
	
	/* Read system statistics from file */
	do {
		/*
		 * If this record is a special (RESTART or COMMENT) one, print it and
		 * (try to) get another one.
		 */
		do {
			if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE))
				/* End of sa data file */
				return;

			rtype = record_hdr[0].record_type;
			if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
				sadf_print_special(0, tm_start.use, tm_end.use, rtype, ifd,
						   rectime, loctime);
			}
			else {
				/*
				 * OK: Previous record was not a special one.
				 * So read now the extra fields.
				 */
				read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
						     file_actlst);
				sadf_get_record_timestamp_struct(0, rectime, loctime);
			}
		}
		while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
		       (tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
		       (tm_end.use && (datecmp(loctime, &tm_end) >= 0)));

		/* Save the first stats collected. Will be used to compute the average */
		copy_structures(act, id_seq, record_hdr, 2, 0);

		/* Set flag to reset last_uptime variable. Should be done after a LINUX RESTART record */
		reset = TRUE;

		/* Save current file position */
		if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
			perror("lseek");
			exit(2);
		}

		/* Read and write stats located between two possible Linux restarts */

		if (DISPLAY_HORIZONTALLY(flags)) {
			/*
			 * If stats are displayed horizontally, then all activities
			 * are printed on the same line.
			 */
			rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
					  ALL_ACTIVITIES, &reset, file_actlst,
					  cpu_nr, rectime, loctime);
		}
		else {
			/* For each requested activity... */
			for (i = 0; i < NR_ACT; i++) {
				
				if (!id_seq[i])
					continue;
				
				if ((p = get_activity_position(act, id_seq[i])) < 0) {
					/* Should never happen */
					PANIC(1);
				}
				if (!IS_SELECTED(act[p]->options))
					continue;

				if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
					rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
							  act[p]->id, &reset, file_actlst,
							  cpu_nr, rectime, loctime);
				}
				else {
					unsigned int optf, msk;
					
					optf = act[p]->opt_flags;
					
					for (msk = 1; msk < 0x10; msk <<= 1) {
						if (act[p]->opt_flags & msk) {
							act[p]->opt_flags &= msk;
							
							rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
									  act[p]->id, &reset, file_actlst,
									  cpu_nr, rectime, loctime);
							act[p]->opt_flags = optf;
						}
					}
				}
			}
		}

		if (!cnt) {
			/* Go to next Linux restart, if possible */
			do {
				eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
						 SOFT_SIZE);
				rtype = record_hdr[curr].record_type;
				if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
					read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
							     file_actlst);
				}
				else if (!eosaf && (rtype == R_COMMENT)) {
					/* This was a COMMENT record: print it */
					sadf_print_special(curr, tm_start.use, tm_end.use,
							   R_COMMENT, ifd, rectime, loctime);
				}
			}
			while (!eosaf && (rtype != R_RESTART));
		}

		/* The last record we read was a RESTART one: Print it */
		if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
			sadf_print_special(curr, tm_start.use, tm_end.use,
					   R_RESTART, ifd, rectime, loctime);
		}
	}
	while (!eosaf);
}
示例#13
0
/*
 ***************************************************************************
 * Display *one* sample of statistics for one or several activities,
 * checking that all conditions are met before printing (time start, time
 * end, interval). Current record should be a record of statistics (R_STATS),
 * not a special one (R_RESTART or R_COMMENT).
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @use_tm_start	Set to TRUE if option -s has been used.
 * @use_tm_end		Set to TRUE if option -e has been used.
 * @reset		Set to TRUE if last_uptime should be reinitialized
 *			(used in next_slice() function).
 * @parm		Pointer on parameters depending on output format
 * 			(eg.: number of tabulations to print).
 * @cpu_nr		Number of processors.
 * @rectime		Structure where timestamp (expressed in local time
 *			or in UTC depending on whether options -T/-t have
 * 			been used or not) has been saved for current record.
 * @loctime		Structure where timestamp (expressed in local time)
 *			has been saved for current record.
 * @reset_cd		TRUE if static cross_day variable should be reset.
 * @act_id		Activity to display (only for formats where
 * 			activities are displayed one at a time) or
 *			ALL_ACTIVITIES for all.
 *
 * OUT:
 * @cnt			Set to 0 to indicate that no other lines of stats
 * 			should be displayed.
 *
 * RETURNS:
 * 1 if stats have been successfully displayed.
 ***************************************************************************
 */
int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset,
			long *cnt, void *parm, __nr_t cpu_nr, struct tm *rectime,
			struct tm *loctime, int reset_cd, unsigned int act_id)
{
	int i;
	unsigned long long dt, itv, g_itv;
	char cur_date[32], cur_time[32], *pre = NULL;
	static int cross_day = FALSE;

	if (reset_cd) {
		/*
		 * See note in sar.c.
		 * NB: Reseting cross_day is needed only if datafile
		 * may be rewinded (eg. in db or ppc output formats).
		 */
		cross_day = 0;
	}

	/*
	 * Check time (1).
	 * For this first check, we use the time interval entered on
	 * the command line. This is equivalent to sar's option -i which
	 * selects records at seconds as close as possible to the number
	 * specified by the interval parameter.
	 */
	if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
			reset, interval))
		/* Not close enough to desired interval */
		return 0;

	/* Check if we are beginning a new day */
	if (use_tm_start && record_hdr[!curr].ust_time &&
	    (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
	    (record_hdr[curr].hour < record_hdr[!curr].hour)) {
		cross_day = TRUE;
	}

	if (cross_day) {
		/*
		 * This is necessary if we want to properly handle something like:
		 * sar -s time_start -e time_end with
		 * time_start(day D) > time_end(day D+1)
		 */
		loctime->tm_hour += 24;
	}

	/* Check time (2) */
	if (use_tm_start && (datecmp(loctime, &tm_start) < 0))
		/* it's too soon... */
		return 0;

	/* Get interval values */
	get_itv_value(&record_hdr[curr], &record_hdr[!curr],
		      cpu_nr, &itv, &g_itv);

	/* Check time (3) */
	if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) {
		/* It's too late... */
		*cnt = 0;
		return 0;
	}

	dt = itv / HZ;
	/* Correct rounding error for dt */
	if ((itv % HZ) >= (HZ / 2)) {
		dt++;
	}

	/* Set date and time strings for current record */
	set_record_timestamp_string(flags, &record_hdr[curr],
				    cur_date, cur_time, 32, rectime);

	if (*fmt[f_position]->f_timestamp) {
		pre = (char *) (*fmt[f_position]->f_timestamp)(parm, F_BEGIN, cur_date, cur_time,
							       dt, &file_hdr, flags);
	}

	/* Display statistics */
	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if ((TEST_MARKUP(fmt[f_position]->options) && CLOSE_MARKUP(act[i]->options)) ||
		    (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) {

			if (format == F_JSON_OUTPUT) {
				/* JSON output */
				int *tab = (int *) parm;

				if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {

					if (*fmt[f_position]->f_timestamp) {
						(*fmt[f_position]->f_timestamp)(tab, F_MAIN, cur_date, cur_time,
										dt, &file_hdr, flags);
					}
				}
				(*act[i]->f_json_print)(act[i], curr, *tab, NEED_GLOBAL_ITV(act[i]->options) ?
							g_itv : itv);
			}

			else if (format == F_XML_OUTPUT) {
				/* XML output */
				int *tab = (int *) parm;

				(*act[i]->f_xml_print)(act[i], curr, *tab, NEED_GLOBAL_ITV(act[i]->options) ?
						       g_itv : itv);
			}

			else if (format == F_SVG_OUTPUT) {
				/* SVG output */
				struct svg_parm *svg_p = (struct svg_parm *) parm;

				svg_p->dt = (unsigned long) dt;
				(*act[i]->f_svg_print)(act[i], curr, F_MAIN, svg_p,
						       NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv,
						       &record_hdr[curr]);
			}

			else {
				/* Other output formats: db, ppc */
				(*act[i]->f_render)(act[i], (format == F_DB_OUTPUT), pre, curr,
						    NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
			}
		}
	}

	if (*fmt[f_position]->f_timestamp) {
		(*fmt[f_position]->f_timestamp)(parm, F_END, cur_date, cur_time,
						dt, &file_hdr, flags);
	}

	return 1;
}
示例#14
0
/*
 ***************************************************************************
 * Compute the number of SVG graphs to display. Each activity selected may
 * have several graphs. Moreover we have to take into account volatile
 * activities (eg. CPU) for which the number of graphs will depend on the
 * highest number of items (eg. maximum number of CPU) saved in the file.
 * This number may be higher than the real number of graphs that will be
 * displayed since some items have a preallocation constant.
 *
 * IN:
 * @ifd		File descriptor of input file.
 * @file	Name of file being read.
 * @file_magic	file_magic structure filled with file magic header data.
 * @file_actlst	List of (known or unknown) activities in file.
 * @rectime	Structure where timestamp (expressed in local time or in UTC
 *		depending on whether options -T/-t have been used or not) can
 *		be saved for current record.
 * @loctime	Structure where timestamp (expressed in local time) can be
 *		saved for current record.
 *
 * RETURNS:
 * Total number of graphs to display, taking into account only activities
 * to be displayed, and selected period of time (options -s/-e).
 ***************************************************************************
 */
int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
		     struct file_activity *file_actlst, struct tm *rectime,
		     struct tm *loctime)
{
	int i, n, p, eosaf;
	int rtype, new_tot_g_nr, tot_g_nr = 0;
	off_t fpos;
	__nr_t save_act_nr[NR_ACT] = {0};

	/* Save current file position and items number */
	if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
		perror("lseek");
		exit(2);
	}
	sr_act_nr(save_act_nr, DO_SAVE);

	/* Init total number of graphs for each activity */
	for (i = 0; i < NR_ACT; i++) {
		id_g_nr[i] = 0;
	}

	/* Look for the first record that will be displayed */
	do {
		eosaf = read_next_sample(ifd, IGNORE_RESTART | IGNORE_COMMENT | SET_TIMESTAMPS,
					 0, file, &rtype, 0, file_magic, file_actlst,
					 rectime, loctime);
		if (eosaf)
			/* No record to display => no graph too */
			return 0;
	}
	while ((tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
	       (tm_end.use && (datecmp(loctime, &tm_end) >= 0)));

	do {
		new_tot_g_nr = 0;

		for (i = 0; i < NR_ACT; i++) {
			if (!id_seq[i])
				continue;

			p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
			if (!IS_SELECTED(act[p]->options))
				continue;

			if (ONE_GRAPH_PER_ITEM(act[p]->options)) {
				 n = act[p]->g_nr * act[p]->nr;
			}
			else {
				n = act[p]->g_nr;
			}

			if (n > id_g_nr[i]) {
				 id_g_nr[i] = n;
			 }
			new_tot_g_nr += n;
		}

		if (new_tot_g_nr > tot_g_nr) {
			tot_g_nr = new_tot_g_nr;
		}

		do {
			eosaf = read_next_sample(ifd, IGNORE_RESTART | IGNORE_COMMENT | SET_TIMESTAMPS,
						 0, file, &rtype, 0, file_magic, file_actlst,
						 rectime, loctime);
			if (eosaf ||
			    (tm_end.use && (datecmp(loctime, &tm_end) >= 0)))
				/* End of data file or end time exceeded */
				break;
		}
		while (rtype != R_RESTART);

		if (eosaf ||
		    (tm_end.use && (datecmp(loctime, &tm_end) >= 0)))
			/*
			 * End of file, or end time exceeded:
			 * Current number of graphs is up-to-date.
			 */
			break;

	/*
	 * If we have found a RESTART record then we have also read the list of volatile
	 * activities following it, reallocated the structures and changed the number of
	 * items (act[p]->nr) for those volatile activities. So loop again to compute
	 * the new total number of graphs.
	 */
	}
	while (rtype == R_RESTART);

	/* Rewind file and restore items number */
	if (lseek(ifd, fpos, SEEK_SET) < fpos) {
		perror("lseek");
		exit(2);
	}
	sr_act_nr(save_act_nr, DO_RESTORE);

	return tot_g_nr;
}
示例#15
0
/*
 ***************************************************************************
 * Display file contents in selected format (logic #3).
 * Logic #3:	Special logic for SVG output format.
 * Formats:	SVG
 *
 * IN:
 * @ifd		File descriptor of input file.
 * @file_actlst	List of (known or unknown) activities in file.
 * @cpu_nr	Number of processors for current activity data file.
 * @rectime	Structure where timestamp (expressed in local time or in UTC
 *		depending on whether options -T/-t have been used or not) can
 *		be saved for current record.
 * @loctime	Structure where timestamp (expressed in local time) can be
 *		saved for current record.
 * @file	Name of file being read.
 * @file_magic	file_magic structure filled with file magic header data.
 ***************************************************************************
 */
void logic3_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr,
			 struct tm *rectime, struct tm *loctime, char *file,
			 struct file_magic *file_magic)
{
	int i, p;
	int curr = 1, rtype, g_nr = 0;
	int eosaf = TRUE, reset = TRUE;
	long cnt = 1;
	off_t fpos;
	int graph_nr = 0;
	__nr_t save_act_nr[NR_ACT] = {0};

	/* Use a decimal point to make SVG code locale independent */
	setlocale(LC_NUMERIC, "C");

	/* Calculate the number of graphs to display */
	graph_nr = get_svg_graph_nr(ifd, file, file_magic,
				    file_actlst, rectime, loctime);
	if (!graph_nr)
		/* No graph to display */
		return;

	/* Print SVG header */
	if (*fmt[f_position]->f_header) {
		(*fmt[f_position]->f_header)(&graph_nr, F_BEGIN + F_MAIN, file, file_magic,
					     &file_hdr, cpu_nr, act, id_seq);
	}

	/*
	* If this record is a special (RESTART or COMMENT) one, ignore it and
	* (try to) get another one.
	*/
	do {
		if (read_next_sample(ifd, IGNORE_RESTART | IGNORE_COMMENT, 0,
				     file, &rtype, 0, file_magic, file_actlst,
				     rectime, loctime))
			/* End of sa data file */
			return;
	}
	while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
	       (tm_start.use && (datecmp(loctime, &tm_start) < 0)) ||
	       (tm_end.use && (datecmp(loctime, &tm_end) >= 0)));

	/* Save the first stats collected. Used for example in next_slice() function */
	copy_structures(act, id_seq, record_hdr, 2, 0);

	/* Save current file position */
	if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
		perror("lseek");
		exit(2);
	}
	/* Save number of activities items for current file position */
	sr_act_nr(save_act_nr, DO_SAVE);

	/* For each requested activity, display graphs */
	for (i = 0; i < NR_ACT; i++) {

		if (!id_seq[i])
			continue;

		p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
		if (!IS_SELECTED(act[p]->options) || !act[p]->g_nr)
			continue;

		if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
			display_curr_act_graphs(ifd, fpos, &curr, &cnt, &eosaf,
						p, &reset, file_actlst,
						cpu_nr, rectime, loctime, file,
						file_magic, save_act_nr, &g_nr);
		}
		else {
			unsigned int optf, msk;

			optf = act[p]->opt_flags;

			for (msk = 1; msk < 0x100; msk <<= 1) {
				if ((act[p]->opt_flags & 0xff) & msk) {
					act[p]->opt_flags &= (0xffffff00 + msk);
					display_curr_act_graphs(ifd, fpos, &curr, &cnt, &eosaf,
								p, &reset, file_actlst,
								cpu_nr, rectime, loctime, file,
								file_magic, save_act_nr, &g_nr);
					act[p]->opt_flags = optf;
				}
			}
		}
	}

	/* Print SVG trailer */
	if (*fmt[f_position]->f_header) {
		(*fmt[f_position]->f_header)(&graph_nr, F_END, file, file_magic,
					     &file_hdr, cpu_nr, act, id_seq);
	}
}
示例#16
0
/*
 ***************************************************************************
 * Print system statistics.
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @read_from_file	Set to TRUE if stats are read from a system activity
 * 			data file.
 * @use_tm_start	Set to TRUE if option -s has been used.
 * @use_tm_end		Set to TRUE if option -e has been used.
 * @reset		Set to TRUE if last_uptime variable should be
 * 			reinitialized (used in next_slice() function).
 * @act_id		Activity that can be displayed or ~0 for all.
 *			Remember that when reading stats from a file, only
 *			one activity can be displayed at a time.
 *
 * OUT:
 * @cnt			Number of remaining lines to display.
 *
 * RETURNS:
 * 1 if stats have been successfully displayed, and 0 otherwise.
 ***************************************************************************
 */
int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
		int use_tm_end, int reset, unsigned int act_id)
{
	int i;
	unsigned long long itv, g_itv;
	static int cross_day = 0;
	static __nr_t cpu_nr = -1;

	if (cpu_nr < 0)
		cpu_nr = act[get_activity_position(act, A_CPU)]->nr;

	/* Check time (1) */
	if (read_from_file) {
		if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
				reset, interval))
			/* Not close enough to desired interval */
			return 0;
	}

	/* Set previous timestamp */
	if (set_record_timestamp_string(!curr, timestamp[!curr], 16))
		return 0;
	/* Set current timestamp */
	if (set_record_timestamp_string(curr,  timestamp[curr],  16))
		return 0;

	/* Check if we are beginning a new day */
	if (use_tm_start && record_hdr[!curr].ust_time &&
	    (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
	    (record_hdr[curr].hour < record_hdr[!curr].hour)) {
		cross_day = 1;
	}

	if (cross_day) {
		/*
		 * This is necessary if we want to properly handle something like:
		 * sar -s time_start -e time_end with
		 * time_start(day D) > time_end(day D+1)
		 */
		rectime.tm_hour +=24;
	}

	/* Check time (2) */
	if (use_tm_start && (datecmp(&rectime, &tm_start) < 0))
		/* it's too soon... */
		return 0;

	/* Get interval values */
	get_itv_value(&record_hdr[curr], &record_hdr[!curr],
		      cpu_nr, &itv, &g_itv);

	/* Check time (3) */
	if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) {
		/* It's too late... */
		*cnt = 0;
		return 0;
	}

	avg_count++;

	/* Test stdout */
	TEST_STDOUT(STDOUT_FILENO);

	for (i = 0; i < NR_ACT; i++) {

		if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
			continue;

		if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
			/* Display current activity statistics */
			(*act[i]->f_print)(act[i], !curr, curr,
					   NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
		}
	}

	return 1;
}
示例#17
0
/*
 ***************************************************************************
 * Display activity records for textual (XML-like) formats.
 *
 * IN:
 * @curr		Index in array for current sample statistics.
 * @use_tm_start	Set to TRUE if option -s has been used.
 * @use_tm_end		Set to TRUE if option -e has been used.
 * @reset		Set to TRUE if last_uptime should be reinitialized
 *			(used in next_slice() function).
 * @tab			Number of tabulations to print.
 * @cpu_nr		Number of processors.
 * @rectime		Structure where timestamp (expressed in local time
 *			or in UTC depending on whether option -t has been
 *			used or not) can be saved for current record.
 * @loctime		Structure where timestamp (expressed in local time)
 *			can be saved for current record.
 *
 * OUT:
 * @cnt			Set to 0 to indicate that no other lines of stats
 * 			should be displayed.
 *
 * RETURNS:
 * 1 if stats have been successfully displayed.
 ***************************************************************************
 */
int write_textual_stats(int curr, int use_tm_start, int use_tm_end, int reset,
			long *cnt, int tab, __nr_t cpu_nr, struct tm *rectime,
			struct tm *loctime)
{
	int i;
	unsigned long long dt, itv, g_itv;
	char cur_date[32], cur_time[32];
	static int cross_day = FALSE;

	/* Fill timestamp structure (rectime) for current record */
	sadf_get_record_timestamp_struct(curr, rectime, loctime);

	/*
	 * Check time (1).
	 * For this first check, we use the time interval entered on
	 * the command line. This is equivalent to sar's option -i which
	 * selects records at seconds as close as possible to the number
	 * specified by the interval parameter.
	 */
	if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
			reset, interval))
		/* Not close enough to desired interval */
		return 0;

	/* Check if we are beginning a new day */
	if (use_tm_start && record_hdr[!curr].ust_time &&
	    (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
	    (record_hdr[curr].hour < record_hdr[!curr].hour)) {
		cross_day = TRUE;
	}

	if (cross_day) {
		/*
		 * This is necessary if we want to properly handle something like:
		 * sar -s time_start -e time_end with
		 * time_start(day D) > time_end(day D+1)
		 */
		loctime->tm_hour += 24;
	}

	/* Check time (2) */
	if (use_tm_start && (datecmp(loctime, &tm_start) < 0))
		/* it's too soon... */
		return 0;

	/* Get interval values */
	get_itv_value(&record_hdr[curr], &record_hdr[!curr],
		      cpu_nr, &itv, &g_itv);

	/* Check time (3) */
	if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) {
		/* It's too late... */
		*cnt = 0;
		return 0;
	}

	dt = itv / HZ;
	/* Correct rounding error for dt */
	if ((itv % HZ) >= (HZ / 2)) {
		dt++;
	}

	/* Set date and time strings for current record */
	set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime);

	if (*fmt[f_position]->f_timestamp) {
		(*fmt[f_position]->f_timestamp)(&tab, F_BEGIN, cur_date, cur_time,
						!PRINT_TRUE_TIME(flags), dt);
	}
	if (format == F_XML_OUTPUT) {
		tab++;
	}

	/* Display textual statistics */
	for (i = 0; i < NR_ACT; i++) {

		/* This code is not generic at all...! */
		if (format == F_JSON_OUTPUT) {
			/* JSON output */
			if (CLOSE_MARKUP(act[i]->options) ||
			    (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) {
				
				if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
					printf(",");

					if (*fmt[f_position]->f_timestamp) {
						(*fmt[f_position]->f_timestamp)(&tab, F_MAIN, cur_date, cur_time,
										!PRINT_TRUE_TIME(flags), dt);
					}
				}
				(*act[i]->f_json_print)(act[i], curr, tab, NEED_GLOBAL_ITV(act[i]->options) ?
							g_itv : itv);
			}
		}
		else {
			/* XML output */
			if (CLOSE_MARKUP(act[i]->options) ||
			    (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) {
				(*act[i]->f_xml_print)(act[i], curr, tab, NEED_GLOBAL_ITV(act[i]->options) ?
						       g_itv : itv);
			}
		}
	}

	if (*fmt[f_position]->f_timestamp) {
		(*fmt[f_position]->f_timestamp)(&tab, F_END, cur_date, cur_time,
						!PRINT_TRUE_TIME(flags), dt);
	}

	return 1;
}
示例#18
0
/*
 ***************************************************************************
 * Read statistics from a system activity data file.
 *
 * IN:
 * @from_file	Input file name.
 ***************************************************************************
 */
void read_stats_from_file(char from_file[])
{
	struct file_magic file_magic;
	struct file_activity *file_actlst = NULL;
	int curr = 1, i, p;
	int ifd, rtype;
	int rows, eosaf = TRUE, reset = FALSE;
	long cnt = 1;
	off_t fpos;

	/* Get window size */
	rows = get_win_height();

	/* Read file headers and activity list */
	check_file_actlst(&ifd, from_file, act, &file_magic, &file_hdr,
			  &file_actlst, id_seq, FALSE);

	/* Perform required allocations */
	allocate_structures(act);

	/* Print report header */
	print_report_hdr(flags, &rectime, &file_hdr,
			 act[get_activity_position(act, A_CPU)]->nr);

	/* Read system statistics from file */
	do {
		/*
		 * If this record is a special (RESTART or COMMENT) one, print it and
		 * (try to) get another one.
		 */
		do {
			if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE))
				/* End of sa data file */
				return;

			rtype = record_hdr[0].record_type;
			if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
				sar_print_special(0, tm_start.use, tm_end.use, rtype,
						  ifd, from_file, &file_magic);
			}
			else {
				/*
				 * OK: Previous record was not a special one.
				 * So read now the extra fields.
				 */
				read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
						     file_actlst);
				if (sar_get_record_timestamp_struct(0))
					/*
					 * An error was detected.
					 * The timestamp hasn't been updated.
					 */
					continue;
			}
		}
		while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
		       (tm_start.use && (datecmp(&rectime, &tm_start) < 0)) ||
		       (tm_end.use && (datecmp(&rectime, &tm_end) >=0)));

		/* Save the first stats collected. Will be used to compute the average */
		copy_structures(act, id_seq, record_hdr, 2, 0);

		reset = TRUE;	/* Set flag to reset last_uptime variable */

		/* Save current file position */
		if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
			perror("lseek");
			exit(2);
		}

		/*
		 * Read and write stats located between two possible Linux restarts.
		 * Activities that should be displayed are saved in id_seq[] array.
		 */
		for (i = 0; i < NR_ACT; i++) {

			if (!id_seq[i])
				continue;

			if ((p = get_activity_position(act, id_seq[i])) < 0) {
				/* Should never happen */
				PANIC(1);
			}
			if (!IS_SELECTED(act[p]->options))
				continue;

			if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
				handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
						      act[p]->id, &reset, file_actlst,
						      from_file, &file_magic);
			}
			else {
				unsigned int optf, msk;

				optf = act[p]->opt_flags;

				for (msk = 1; msk < 0x10; msk <<= 1) {
					if (act[p]->opt_flags & msk) {
						act[p]->opt_flags &= msk;

						handle_curr_act_stats(ifd, fpos, &curr, &cnt,
								      &eosaf, rows, act[p]->id,
								      &reset, file_actlst,
								      from_file, &file_magic);
						act[p]->opt_flags = optf;
					}
				}
			}
		}

		if (!cnt) {
			/* Go to next Linux restart, if possible */
			do {
				eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
						 SOFT_SIZE);
				rtype = record_hdr[curr].record_type;
				if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
					read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
							     file_actlst);
				}
				else if (!eosaf && (rtype == R_COMMENT)) {
					/* This was a COMMENT record: print it */
					sar_print_special(curr, tm_start.use, tm_end.use, R_COMMENT,
							  ifd, from_file, &file_magic);
				}
			}
			while (!eosaf && (rtype != R_RESTART));
		}

		/* The last record we read was a RESTART one: Print it */
		if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
			sar_print_special(curr, tm_start.use, tm_end.use, R_RESTART,
					  ifd, from_file, &file_magic);
		}
	}
	while (!eosaf);

	close(ifd);

	free(file_actlst);
}
示例#19
0
文件: mis.c 项目: erdc-cm/petsc-dev
PetscErrorCode maxIndSetAgg(IS perm,Mat Gmat,PetscBool strict_aggs,PetscInt verbose,PetscCoarsenData **a_locals_llist)
{
  PetscErrorCode   ierr;
  PetscBool        isMPI;
  Mat_SeqAIJ       *matA, *matB = 0;
  MPI_Comm         wcomm = ((PetscObject)Gmat)->comm;
  Vec              locState, ghostState;
  PetscInt         num_fine_ghosts,kk,n,ix,j,*idx,*ii,iter,Iend,my0,nremoved;
  Mat_MPIAIJ       *mpimat = 0;
  PetscScalar      *cpcol_gid,*cpcol_state;
  PetscMPIInt      mype,npe;
  const PetscInt   *perm_ix;
  PetscInt         nDone, nselected = 0;
  const PetscInt   nloc = Gmat->rmap->n;
  PetscInt         *lid_cprowID, *lid_gid;
  PetscBool        *lid_removed;
  PetscScalar      *lid_parent_gid = PETSC_NULL; /* only used for strict aggs */
  PetscScalar      *lid_state;
  PetscCoarsenData *agg_lists;

  PetscFunctionBegin;
  ierr = MPI_Comm_rank(wcomm, &mype);CHKERRQ(ierr);
  ierr = MPI_Comm_size(wcomm, &npe);CHKERRQ(ierr);

  /* get submatrices */
  ierr = PetscObjectTypeCompare((PetscObject)Gmat, MATMPIAIJ, &isMPI);CHKERRQ(ierr);
  if (isMPI) {
    mpimat = (Mat_MPIAIJ*)Gmat->data;
    matA = (Mat_SeqAIJ*)mpimat->A->data;
    matB = (Mat_SeqAIJ*)mpimat->B->data;
    /* force compressed storage of B */
    matB->compressedrow.check = PETSC_TRUE;
    ierr = MatCheckCompressedRow(mpimat->B,&matB->compressedrow,matB->i,Gmat->rmap->n,-1.0);CHKERRQ(ierr);
    assert(matB->compressedrow.use);
  } else {
    PetscBool      isAIJ;
    ierr = PetscObjectTypeCompare((PetscObject)Gmat, MATSEQAIJ, &isAIJ);CHKERRQ(ierr);
    assert(isAIJ);
    matA = (Mat_SeqAIJ*)Gmat->data;
  }
  assert(matA && !matA->compressedrow.use);
  assert(matB==0 || matB->compressedrow.use);
  /* get vector */
  ierr = MatGetVecs(Gmat, &locState, 0);CHKERRQ(ierr);

  ierr = MatGetOwnershipRange(Gmat,&my0,&Iend);CHKERRQ(ierr);

  if (mpimat) {
    PetscInt gid;
    for (kk=0,gid=my0;kk<nloc;kk++,gid++) {
      PetscScalar v = (PetscScalar)(gid);
      ierr = VecSetValues(locState, 1, &gid, &v, INSERT_VALUES);CHKERRQ(ierr); /* set with GID */
    }
    ierr = VecAssemblyBegin(locState);CHKERRQ(ierr);
    ierr = VecAssemblyEnd(locState);CHKERRQ(ierr);
    ierr = VecScatterBegin(mpimat->Mvctx,locState,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
    ierr =   VecScatterEnd(mpimat->Mvctx,locState,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
    ierr = VecGetArray(mpimat->lvec, &cpcol_gid);CHKERRQ(ierr); /* get proc ID in 'cpcol_gid' */
    ierr = VecDuplicate(mpimat->lvec, &ghostState);CHKERRQ(ierr); /* need 2nd compressed col. of off proc data */
    ierr = VecGetLocalSize(mpimat->lvec, &num_fine_ghosts);CHKERRQ(ierr);
    ierr = VecSet(ghostState, (PetscScalar)((PetscReal)NOT_DONE));CHKERRQ(ierr); /* set with UNKNOWN state */
  } else num_fine_ghosts = 0;

  ierr = PetscMalloc(nloc*sizeof(PetscInt), &lid_cprowID);CHKERRQ(ierr);
  ierr = PetscMalloc((nloc+1)*sizeof(PetscInt), &lid_gid);CHKERRQ(ierr); /* explicit array needed */
  ierr = PetscMalloc(nloc*sizeof(PetscBool), &lid_removed);CHKERRQ(ierr); /* explicit array needed */
  if (strict_aggs) {
    ierr = PetscMalloc((nloc+1)*sizeof(PetscScalar), &lid_parent_gid);CHKERRQ(ierr);
  }
  ierr = PetscMalloc((nloc+1)*sizeof(PetscScalar), &lid_state);CHKERRQ(ierr);

  /* has ghost nodes for !strict and uses local indexing (yuck) */
  ierr = PetscCDCreate(strict_aggs ? nloc : num_fine_ghosts+nloc, &agg_lists);CHKERRQ(ierr);
  if (a_locals_llist) *a_locals_llist = agg_lists;

  /* need an inverse map - locals */
  for (kk=0;kk<nloc;kk++) {
    lid_cprowID[kk] = -1; lid_removed[kk] = PETSC_FALSE;
    if (strict_aggs) {
      lid_parent_gid[kk] = -1.0;
    }
    lid_gid[kk] = kk + my0;
    lid_state[kk] =  (PetscScalar)((PetscReal)NOT_DONE);
  }
  /* set index into cmpressed row 'lid_cprowID' */
  if (matB) {
    for (ix=0; ix<matB->compressedrow.nrows; ix++) {
      PetscInt lid = matB->compressedrow.rindex[ix];
      lid_cprowID[lid] = ix;
    }
  }
  /* MIS */
  iter = nremoved = nDone = 0;
  ierr = ISGetIndices(perm, &perm_ix);CHKERRQ(ierr);
  while (nDone < nloc || PETSC_TRUE) { /* asyncronous not implemented */
    iter++;
    if (mpimat) {
      ierr = VecGetArray(ghostState, &cpcol_state);CHKERRQ(ierr);
    }
    /* check all vertices */
    for (kk=0;kk<nloc;kk++){
      PetscInt lid = perm_ix[kk];
      NState state = (NState)PetscRealPart(lid_state[lid]);
      if (lid_removed[lid]) continue;
      if (state == NOT_DONE) {
        /* parallel test, delete if selected ghost */
        PetscBool isOK = PETSC_TRUE;
        if ((ix=lid_cprowID[lid]) != -1) { /* if I have any ghost neighbors */
          ii = matB->compressedrow.i; n = ii[ix+1] - ii[ix];
          idx = matB->j + ii[ix];
          for (j=0 ; j<n ; j++) {
            PetscInt cpid = idx[j]; /* compressed row ID in B mat */
            PetscInt gid = (PetscInt)PetscRealPart(cpcol_gid[cpid]);
            NState statej = (NState)PetscRealPart(cpcol_state[cpid]);
            if (statej == NOT_DONE && gid >= Iend) { /* should be (pe>mype), use gid as pe proxy */
              isOK = PETSC_FALSE; /* can not delete */
              break;
            } else assert(!IS_SELECTED(statej)); /* lid is now deleted, do it */
          }
        } /* parallel test */
        if (isOK){ /* select or remove this vertex */
          nDone++;
          /* check for singleton */
          ii = matA->i; n = ii[lid+1] - ii[lid];
          if (n < 2) {
            /* if I have any ghost adj then not a sing */
            ix = lid_cprowID[lid];
            if (ix==-1 || (matB->compressedrow.i[ix+1]-matB->compressedrow.i[ix])==0){
              nremoved++;
              lid_removed[lid] = PETSC_TRUE;
              /* should select this because it is technically in the MIS but lets not */
              /* lid_state[lid] = (PetscScalar)(lid+my0); */
              continue; /* one local adj (me) and no ghost - singleton */
            }
          }
          /* SELECTED state encoded with global index */
          lid_state[lid] = (PetscScalar)(lid+my0); /* needed???? */
          nselected++;
          if (strict_aggs) {
            ierr = PetscCDAppendID(agg_lists, lid, lid+my0);CHKERRQ(ierr);
          } else {
            ierr = PetscCDAppendID(agg_lists, lid, lid);CHKERRQ(ierr);
          }
          /* delete local adj */
          idx = matA->j + ii[lid];
          for (j=0; j<n; j++) {
            PetscInt lidj = idx[j];
            NState statej = (NState)PetscRealPart(lid_state[lidj]);
            if (statej == NOT_DONE){
              nDone++;
              /* id_llist[lidj] = id_llist[lid]; id_llist[lid] = lidj; */ /* insert 'lidj' into head of llist */
              if (strict_aggs) {
                ierr = PetscCDAppendID(agg_lists, lid, lidj+my0);CHKERRQ(ierr);
              } else {
                ierr = PetscCDAppendID(agg_lists, lid, lidj);CHKERRQ(ierr);
              }
              lid_state[lidj] = (PetscScalar)(PetscReal)DELETED;  /* delete this */
            }
          }

          /* delete ghost adj of lid - deleted ghost done later for strict_aggs */
          if (!strict_aggs) {
            if ((ix=lid_cprowID[lid]) != -1) { /* if I have any ghost neighbors */
              ii = matB->compressedrow.i; n = ii[ix+1] - ii[ix];
              idx = matB->j + ii[ix];
              for (j=0 ; j<n ; j++) {
                PetscInt cpid = idx[j]; /* compressed row ID in B mat */
                NState statej = (NState)PetscRealPart(cpcol_state[cpid]);        assert(!IS_SELECTED(statej));
                if (statej == NOT_DONE) {
                  /* cpcol_state[cpid] = (PetscScalar)DELETED; this should happen later ... */
                  /* id_llist[lidj] = id_llist[lid]; id_llist[lid] = lidj; */ /* insert 'lidj' into head of llist */
                  ierr = PetscCDAppendID(agg_lists, lid, nloc+cpid);CHKERRQ(ierr);
                }
              }
            }
          }
        } /* selected */
      } /* not done vertex */
    } /* vertex loop */

    /* update ghost states and count todos */
    if (mpimat) {
      ierr = VecRestoreArray(ghostState, &cpcol_state);CHKERRQ(ierr);
      /* put lid state in 'locState' */
      ierr = VecSetValues(locState, nloc, lid_gid, lid_state, INSERT_VALUES);CHKERRQ(ierr);
      ierr = VecAssemblyBegin(locState);CHKERRQ(ierr);
      ierr = VecAssemblyEnd(locState);CHKERRQ(ierr);
      /* scatter states, check for done */
      ierr = VecScatterBegin(mpimat->Mvctx,locState,ghostState,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
      ierr =   VecScatterEnd(mpimat->Mvctx,locState,ghostState,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
      /* delete locals from selected ghosts */
      ierr = VecGetArray(ghostState, &cpcol_state);CHKERRQ(ierr);
      ii = matB->compressedrow.i;
      for (ix=0; ix<matB->compressedrow.nrows; ix++) {
        PetscInt lid = matB->compressedrow.rindex[ix]; /* local boundary node */
        NState   state = (NState)PetscRealPart(lid_state[lid]);
        if (state == NOT_DONE) {
          /* look at ghosts */
          n = ii[ix+1] - ii[ix];
          idx = matB->j + ii[ix];
          for (j=0 ; j<n ; j++) {
            PetscInt cpid = idx[j]; /* compressed row ID in B mat */
            NState statej = (NState)PetscRealPart(cpcol_state[cpid]);
            if (IS_SELECTED(statej)) { /* lid is now deleted, do it */
              nDone++;
              lid_state[lid] = (PetscScalar)(PetscReal)DELETED; /* delete this */
              if (!strict_aggs) {
                PetscInt lidj = nloc + cpid;
                /* id_llist[lid] = id_llist[lidj]; id_llist[lidj] = lid; */ /* insert 'lid' into head of ghost llist */
                ierr = PetscCDAppendID(agg_lists, lidj, lid);CHKERRQ(ierr);
              } else {
                PetscInt sgid = (PetscInt)PetscRealPart(cpcol_gid[cpid]);
                lid_parent_gid[lid] = (PetscScalar)sgid; /* keep track of proc that I belong to */
              }
              break;
            }
          }
        }
      }
      ierr = VecRestoreArray(ghostState, &cpcol_state);CHKERRQ(ierr);

      /* all done? */
      {
        PetscInt t1, t2;
        t1 = nloc - nDone; assert(t1>=0);
        ierr = MPI_Allreduce(&t1, &t2, 1, MPIU_INT, MPI_SUM, wcomm);CHKERRQ(ierr); /* synchronous version */
        if (t2 == 0) break;
      }
    } else break; /* all done */
  } /* outer parallel MIS loop */
  ierr = ISRestoreIndices(perm,&perm_ix);CHKERRQ(ierr);

  if (verbose) {
    if (verbose == 1) {
      ierr = PetscPrintf(wcomm,"\t[%d]%s removed %d of %d vertices.  %d selected.\n",mype,__FUNCT__,nremoved,nloc,nselected);CHKERRQ(ierr);
    } else {
      ierr = MPI_Allreduce(&nremoved, &n, 1, MPIU_INT, MPI_SUM, wcomm);CHKERRQ(ierr);
      ierr = MatGetSize(Gmat, &kk, &j);CHKERRQ(ierr);
      ierr = MPI_Allreduce(&nselected, &j, 1, MPIU_INT, MPI_SUM, wcomm);CHKERRQ(ierr);
      ierr = PetscPrintf(wcomm,"\t[%d]%s removed %d of %d vertices. (%d local)  %d selected.\n",mype,__FUNCT__,n,kk,nremoved,j);CHKERRQ(ierr);
    }
  }

  /* tell adj who my lid_parent_gid vertices belong to - fill in agg_lists selected ghost lists */
  if (strict_aggs && matB) {
    PetscScalar *cpcol_sel_gid;
    PetscInt cpid,*icpcol_gid;

    /* need to copy this to free buffer -- should do this globaly */
    ierr = PetscMalloc(num_fine_ghosts*sizeof(PetscInt), &icpcol_gid);CHKERRQ(ierr);
    for (cpid=0; cpid<num_fine_ghosts; cpid++) icpcol_gid[cpid] = (PetscInt)PetscRealPart(cpcol_gid[cpid]);

    /* get proc of deleted ghost */
    ierr = VecSetValues(locState, nloc, lid_gid, lid_parent_gid, INSERT_VALUES);CHKERRQ(ierr);
    ierr = VecAssemblyBegin(locState);CHKERRQ(ierr);
    ierr = VecAssemblyEnd(locState);CHKERRQ(ierr);
    ierr = VecScatterBegin(mpimat->Mvctx,locState,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
    ierr =   VecScatterEnd(mpimat->Mvctx,locState,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
    ierr = VecGetArray(mpimat->lvec, &cpcol_sel_gid);CHKERRQ(ierr); /* has pe that owns ghost */
    for (cpid=0; cpid<num_fine_ghosts; cpid++) {
      PetscInt sgid = (PetscInt)PetscRealPart(cpcol_sel_gid[cpid]);
      PetscInt gid = icpcol_gid[cpid];
      if (sgid >= my0 && sgid < Iend) { /* I own this deleted */
        PetscInt slid = sgid - my0;
        /* id_llist[lidj] = id_llist[lid]; id_llist[lid] = lidj; */ /* insert 'lidj' into head of llist */
        ierr = PetscCDAppendID(agg_lists, slid, gid);CHKERRQ(ierr);
        assert(IS_SELECTED((NState)PetscRealPart(lid_state[slid])));
      }
    }
    ierr = VecRestoreArray(mpimat->lvec, &cpcol_sel_gid);CHKERRQ(ierr);
    ierr = PetscFree(icpcol_gid);CHKERRQ(ierr);
  } else if (matB) {
    ierr = VecRestoreArray(mpimat->lvec, &cpcol_gid);CHKERRQ(ierr);
  }

  /* cache IS of removed nodes, use 'lid_gid' */
  /* for (kk=n=0,ix=my0;kk<nloc;kk++,ix++) { */
  /*   if (lid_removed[kk]) lid_gid[n++] = ix; */
  /* } */
  /* assert(n==nremoved); */
  /* ierr = PetscCDSetRemovedIS(agg_lists, wcomm, n, lid_gid);CHKERRQ(ierr); */

  ierr = PetscFree(lid_cprowID);CHKERRQ(ierr);
  ierr = PetscFree(lid_gid);CHKERRQ(ierr);
  ierr = PetscFree(lid_removed);CHKERRQ(ierr);
  if (strict_aggs) {
    ierr = PetscFree(lid_parent_gid);CHKERRQ(ierr);
  }
  ierr = PetscFree(lid_state);CHKERRQ(ierr);

  if (mpimat){
    ierr = VecDestroy(&ghostState);CHKERRQ(ierr);
  }
  ierr = VecDestroy(&locState);CHKERRQ(ierr);

  PetscFunctionReturn(0);
}