svn commit: r210794 - head/usr.sbin/pmcstat

Fabien Thomas fabient at FreeBSD.org
Tue Aug 3 09:23:53 UTC 2010


Author: fabient
Date: Tue Aug  3 09:23:53 2010
New Revision: 210794
URL: http://svn.freebsd.org/changeset/base/210794

Log:
  Allow file as a top source, it works with socket now.
  This will allow top monitoring using socket/ssh tunnelling
  of system without local symbols.
  
  client:
  pmcstat -R <ip>:<port> -T -r <symbolspath>
  monitored device:
  pmcstat -Sinstructions -O <ip>:<port>
  
  - Move the file read in the event loop
  - Initialize and clean log in all cases
  - Preserve global stats value during top refresh
  - Fix the rtld/line resolver that ignore '-r' prefix
  - Support socket for '-R' (server mode)
  - Display the statistics when exiting top mode

Modified:
  head/usr.sbin/pmcstat/pmcstat.c
  head/usr.sbin/pmcstat/pmcstat_log.c

Modified: head/usr.sbin/pmcstat/pmcstat.c
==============================================================================
--- head/usr.sbin/pmcstat/pmcstat.c	Tue Aug  3 09:21:13 2010	(r210793)
+++ head/usr.sbin/pmcstat/pmcstat.c	Tue Aug  3 09:23:53 2010	(r210794)
@@ -169,8 +169,7 @@ pmcstat_cleanup(void)
 		args.pa_logparser = NULL;
 	}
 
-	if (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE))
-		pmcstat_shutdown_logging();
+	pmcstat_shutdown_logging();
 }
 
 void
@@ -559,7 +558,7 @@ main(int argc, char **argv)
 	int do_print;
 	size_t dummy;
 	int graphdepth;
-	int pipefd[2];
+	int pipefd[2], rfd;
 	int use_cumulative_counts;
 	short cf, cb;
 	uint32_t cpumask;
@@ -1001,11 +1000,6 @@ main(int argc, char **argv)
 	    (args.pa_flags & FLAG_READ_LOGFILE) == 0)
 	    errx(EX_USAGE, "ERROR: option -M is only used with -g/-R.");
 
-	/* -T is incompatible with -R (replay logfile is a TODO) */
-	if ((args.pa_flags & FLAG_DO_TOP) &&
-	    (args.pa_flags & FLAG_READ_LOGFILE))
-		errx(EX_USAGE, "ERROR: option -T is incompatible with -R.");
-
 	/*
 	 * Disallow textual output of sampling PMCs if counting PMCs
 	 * have also been asked for, mostly because the combined output
@@ -1066,7 +1060,22 @@ main(int argc, char **argv)
 			    graphfilename);
 	}
 
-	/* if we've been asked to process a log file, do that and exit */
+	/* if we've been asked to process a log file, skip init */
+	if ((args.pa_flags & FLAG_READ_LOGFILE) == 0) {
+		if (pmc_init() < 0)
+			err(EX_UNAVAILABLE,
+			    "ERROR: Initialization of the pmc(3) library failed");
+
+		if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */
+			err(EX_OSERR, "ERROR: Cannot determine the number of PMCs "
+			    "on CPU %d", 0);
+	}
+
+	/* Allocate a kqueue */
+	if ((pmcstat_kq = kqueue()) < 0)
+		err(EX_OSERR, "ERROR: Cannot allocate kqueue");
+
+	/* Setup the logfile as the source. */
 	if (args.pa_flags & FLAG_READ_LOGFILE) {
 		/*
 		 * Print the log in textual form if we haven't been
@@ -1076,28 +1085,17 @@ main(int argc, char **argv)
 			args.pa_flags |= FLAG_DO_PRINT;
 
 		pmcstat_initialize_logging();
-		args.pa_logfd = pmcstat_open_log(args.pa_inputpath,
+		rfd = pmcstat_open_log(args.pa_inputpath,
 		    PMCSTAT_OPEN_FOR_READ);
-		if ((args.pa_logparser = pmclog_open(args.pa_logfd)) == NULL)
+		if ((args.pa_logparser = pmclog_open(rfd)) == NULL)
 			err(EX_OSERR, "ERROR: Cannot create parser");
-		pmcstat_process_log();
-		pmcstat_shutdown_logging();
-		exit(EX_OK);
+		if (fcntl(rfd, F_SETFL, O_NONBLOCK) < 0)
+			err(EX_OSERR, "ERROR: fcntl(2) failed");
+		EV_SET(&kev, rfd, EVFILT_READ, EV_ADD,
+		    0, 0, NULL);
+		if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
+			err(EX_OSERR, "ERROR: Cannot register kevent");
 	}
-
-	/* otherwise, we've been asked to collect data */
-	if (pmc_init() < 0)
-		err(EX_UNAVAILABLE,
-		    "ERROR: Initialization of the pmc(3) library failed");
-
-	if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */
-		err(EX_OSERR, "ERROR: Cannot determine the number of PMCs "
-		    "on CPU %d", 0);
-
-	/* Allocate a kqueue */
-	if ((pmcstat_kq = kqueue()) < 0)
-		err(EX_OSERR, "ERROR: Cannot allocate kqueue");
-
 	/*
 	 * Configure the specified log file or setup a default log
 	 * consumer via a pipe.
@@ -1140,6 +1138,7 @@ main(int argc, char **argv)
 	    (args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE);
 
 	/*
+	if (args.pa_flags & FLAG_READ_LOGFILE) {
 	 * Allocate PMCs.
 	 */
 
@@ -1272,10 +1271,8 @@ main(int argc, char **argv)
 	if (args.pa_flags & FLAG_HAS_COMMANDLINE)
 		pmcstat_start_process();
 
-	/* initialize logging if printing the configured log */
-	if ((args.pa_flags & (FLAG_DO_PRINT | FLAG_DO_TOP)) &&
-	    (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE)))
-		pmcstat_initialize_logging();
+	/* initialize logging */
+	pmcstat_initialize_logging();
 
 	/* Handle SIGINT using the kqueue loop */
 	sa.sa_handler = SIG_IGN;
@@ -1338,16 +1335,13 @@ main(int argc, char **argv)
 
 		switch (kev.filter) {
 		case EVFILT_PROC:  /* target has exited */
-			if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
-				FLAG_HAS_PIPE))
-				runstate = pmcstat_close_log();
-			else
-				runstate = PMCSTAT_FINISHED;
+			runstate = pmcstat_close_log();
 			do_print = 1;
 			break;
 
 		case EVFILT_READ:  /* log file data is present */
-			if (kev.ident == (unsigned)fileno(stdin)) {
+			if (kev.ident == (unsigned)fileno(stdin) &&
+			    (args.pa_flags & FLAG_DO_TOP)) {
 				if (pmcstat_keypress_log())
 					runstate = pmcstat_close_log();
 			} else
@@ -1370,15 +1364,8 @@ main(int argc, char **argv)
 				 * of its targets, or if logfile
 				 * writes encounter an error.
 				 */
-				if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
-				    FLAG_HAS_PIPE)) {
-					runstate = pmcstat_close_log();
-					if (args.pa_flags &
-					    (FLAG_DO_PRINT|FLAG_DO_ANALYSIS))
-						pmcstat_process_log();
-				}
+				runstate = pmcstat_close_log();
 				do_print = 1; /* print PMCs at exit */
-				runstate = PMCSTAT_FINISHED;
 			} else if (kev.ident == SIGINT) {
 				/* Kill the child process if we started it */
 				if (args.pa_flags & FLAG_HAS_COMMANDLINE)
@@ -1386,7 +1373,7 @@ main(int argc, char **argv)
 				/* Close the pipe to self, if present. */
 				if (args.pa_flags & FLAG_HAS_PIPE)
 					(void) close(pipefd[READPIPEFD]);
-				runstate = PMCSTAT_FINISHED;
+				runstate = pmcstat_close_log();
 			} else if (kev.ident == SIGWINCH) {
 				if (ioctl(fileno(args.pa_printfile),
 					TIOCGWINSZ, &ws) < 0)

Modified: head/usr.sbin/pmcstat/pmcstat_log.c
==============================================================================
--- head/usr.sbin/pmcstat/pmcstat_log.c	Tue Aug  3 09:21:13 2010	(r210793)
+++ head/usr.sbin/pmcstat/pmcstat_log.c	Tue Aug  3 09:23:53 2010	(r210794)
@@ -141,6 +141,7 @@ struct pmcstat_image_hash_list pmcstat_i
 struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
 
 struct pmcstat_stats pmcstat_stats; /* statistics */
+int ps_samples_period; /* samples count between top refresh. */
 
 struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
 
@@ -247,7 +248,7 @@ static int	pmcstat_string_compute_hash(c
 static void pmcstat_string_initialize(void);
 static int	pmcstat_string_lookup_hash(pmcstat_interned_string _is);
 static void pmcstat_string_shutdown(void);
-static void pmcstat_stats_reset(void);
+static void pmcstat_stats_reset(int _reset_global);
 
 /*
  * A simple implementation of interned strings.  Each interned string
@@ -276,7 +277,7 @@ int pmcstat_npmcs;
 int pmcstat_pause;
 
 static void
-pmcstat_stats_reset(void)
+pmcstat_stats_reset(int reset_global)
 {
 	struct pmcstat_pmcrecord *pr;
 
@@ -285,9 +286,11 @@ pmcstat_stats_reset(void)
 		pr->pr_samples = 0;
 		pr->pr_dubious_frames = 0;
 	}
+	ps_samples_period = 0;
 
 	/* Flush global stats. */
-	bzero(&pmcstat_stats, sizeof(struct pmcstat_stats));
+	if (reset_global)
+		bzero(&pmcstat_stats, sizeof(struct pmcstat_stats));
 }
 
 /*
@@ -606,7 +609,7 @@ pmcstat_image_get_elf_params(struct pmcs
 	GElf_Phdr ph;
 	GElf_Shdr sh;
 	enum pmcstat_image_type image_type;
-	char buffer[PATH_MAX];
+	char buffer[PATH_MAX], rtldpath[PATH_MAX];
 
 	assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
 
@@ -686,9 +689,10 @@ pmcstat_image_get_elf_params(struct pmcs
 					    buffer, elf_errmsg(-1));
 					goto done;
 				}
+				snprintf(rtldpath, sizeof(rtldpath), "%s%s",
+				    args.pa_fsroot, elfbase + ph.p_offset);
 				image->pi_dynlinkerpath =
-				    pmcstat_string_intern(elfbase +
-					ph.p_offset);
+				    pmcstat_string_intern(rtldpath);
 				break;
 			case PT_LOAD:
 				if (ph.p_offset == 0)
@@ -944,11 +948,13 @@ pmcstat_image_addr2line(struct pmcstat_i
 	int fd;
 
 	if (image->pi_addr2line == NULL) {
-		snprintf(imagepath, sizeof(imagepath), "%s.symbols",
+		snprintf(imagepath, sizeof(imagepath), "%s%s.symbols",
+		    args.pa_fsroot,
 		    pmcstat_string_unintern(image->pi_fullpath));
 		fd = open(imagepath, O_RDONLY);
 		if (fd < 0) {
-			snprintf(imagepath, sizeof(imagepath), "%s",
+			snprintf(imagepath, sizeof(imagepath), "%s%s",
+			    args.pa_fsroot,
 			    pmcstat_string_unintern(image->pi_fullpath));
 		} else
 			close(fd);
@@ -1397,6 +1403,7 @@ pmcstat_analyze_log(void)
 			 * bin inside this.
 			 */
 			pmcstat_stats.ps_samples_total++;
+			ps_samples_period++;
 
 			pc = ev.pl_u.pl_s.pl_pc;
 			pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid,
@@ -1423,6 +1430,7 @@ pmcstat_analyze_log(void)
 
 		case PMCLOG_TYPE_CALLCHAIN:
 			pmcstat_stats.ps_samples_total++;
+			ps_samples_period++;
 
 			cpuflags = ev.pl_u.pl_cc.pl_cpuflags;
 			cpu = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(cpuflags);
@@ -1689,8 +1697,15 @@ pmcstat_print_log(void)
 int
 pmcstat_close_log(void)
 {
-	if (pmc_flush_logfile() < 0)
-		err(EX_OSERR, "ERROR: logging failed");
+	/* If a local logfile is configured ask the kernel to stop
+	 * and flush data. Kernel will close the file when data is flushed
+	 * so keep the status to EXITING.
+	 */
+	if (args.pa_logfd != -1) {
+		if (pmc_flush_logfile() < 0)
+			err(EX_OSERR, "ERROR: logging failed");
+	}
+
 	return (args.pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING :
 	    PMCSTAT_FINISHED);
 }
@@ -1707,7 +1722,7 @@ pmcstat_close_log(void)
 int
 pmcstat_open_log(const char *path, int mode)
 {
-	int error, fd;
+	int error, fd, cfd;
 	size_t hlen;
 	const char *p, *errstr;
 	struct addrinfo hints, *res, *res0;
@@ -1728,7 +1743,7 @@ pmcstat_open_log(const char *path, int m
 	 */
 	if (path[0] == '-' && path[1] == '\0')
 		fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1;
-	else if (mode == PMCSTAT_OPEN_FOR_WRITE && path[0] != '/' &&
+	else if (path[0] != '/' &&
 	    path[0] != '.' && strchr(path, ':') != NULL) {
 
 		p = strrchr(path, ':');
@@ -1757,11 +1772,29 @@ pmcstat_open_log(const char *path, int m
 				errstr = strerror(errno);
 				continue;
 			}
-			if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
-				errstr = strerror(errno);
+			if (mode == PMCSTAT_OPEN_FOR_READ) {
+				if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
+					errstr = strerror(errno);
+					(void) close(fd);
+					fd = -1;
+					continue;
+				}
+				listen(fd, 1);
+				cfd = accept(fd, NULL, NULL);
 				(void) close(fd);
-				fd = -1;
-				continue;
+				if (cfd < 0) {
+					errstr = strerror(errno);
+					fd = -1;
+					break;
+				}
+				fd = cfd;
+			} else {
+				if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
+					errstr = strerror(errno);
+					(void) close(fd);
+					fd = -1;
+					continue;
+				}
 			}
 			errstr = NULL;
 			break;
@@ -1831,9 +1864,8 @@ pmcstat_refresh_top(void)
 		    pmcstat_pmcinfilter);
 
 	/* Format samples count. */
-	if (pmcstat_stats.ps_samples_total > 0)
-		v = (pmcpr->pr_samples * 100.0) /
-		    pmcstat_stats.ps_samples_total;
+	if (ps_samples_period > 0)
+		v = (pmcpr->pr_samples * 100.0) / ps_samples_period;
 	else
 		v = 0.;
 	v_attrs = PMCSTAT_ATTRPERCENT(v);
@@ -1870,7 +1902,7 @@ pmcstat_changefilter(void)
 
 		do {
 			pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter);
-			if (pmcr == pmcr->pr_merge)
+			if (pmcr == NULL || pmcr == pmcr->pr_merge)
 				break;
 
 			pmcstat_pmcinfilter++;
@@ -1913,7 +1945,7 @@ pmcstat_keypress_log(void)
 		 */
 		if (plugins[args.pa_plugin].pl_shutdown != NULL)
 			plugins[args.pa_plugin].pl_shutdown(NULL);
-		pmcstat_stats_reset();
+		pmcstat_stats_reset(0);
 		if (plugins[args.pa_plugin].pl_init != NULL)
 			plugins[args.pa_plugin].pl_init();
 
@@ -1934,7 +1966,7 @@ pmcstat_keypress_log(void)
 		} while (plugins[args.pa_plugin].pl_topdisplay == NULL);
 
 		/* Open new plugin. */
-		pmcstat_stats_reset();
+		pmcstat_stats_reset(0);
 		if (plugins[args.pa_plugin].pl_init != NULL)
 			plugins[args.pa_plugin].pl_init();
 		wprintw(w, "switching to plugin %s",
@@ -1984,7 +2016,7 @@ pmcstat_display_log(void)
 	if (args.pa_topmode == PMCSTAT_TOP_DELTA) {
 		if (plugins[args.pa_plugin].pl_shutdown != NULL)
 			plugins[args.pa_plugin].pl_shutdown(NULL);
-		pmcstat_stats_reset();
+		pmcstat_stats_reset(0);
 		if (plugins[args.pa_plugin].pl_init != NULL)
 			plugins[args.pa_plugin].pl_init();
 	}
@@ -2128,8 +2160,7 @@ pmcstat_shutdown_logging(void)
 			    N, pmcstat_stats.ps_##V);			\
 	} while (0)
 
-	if (args.pa_verbosity >= 1 && (args.pa_flags & FLAG_DO_ANALYSIS) &&
-	    (args.pa_flags & FLAG_DO_TOP) == 0) {
+	if (args.pa_verbosity >= 1 && (args.pa_flags & FLAG_DO_ANALYSIS)) {
 		(void) fprintf(args.pa_printfile, "CONVERSION STATISTICS:\n");
 		PRINT("#exec/a.out", exec_aout);
 		PRINT("#exec/elf", exec_elf);


More information about the svn-src-all mailing list