svn commit: r211099 - stable/7/usr.sbin/pmcstat
Fabien Thomas
fabient at FreeBSD.org
Mon Aug 9 14:30:45 UTC 2010
Author: fabient
Date: Mon Aug 9 14:30:45 2010
New Revision: 211099
URL: http://svn.freebsd.org/changeset/base/211099
Log:
MFC r210794:
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:
stable/7/usr.sbin/pmcstat/pmcstat.c
stable/7/usr.sbin/pmcstat/pmcstat_log.c
Directory Properties:
stable/7/usr.sbin/pmcstat/ (props changed)
Modified: stable/7/usr.sbin/pmcstat/pmcstat.c
==============================================================================
--- stable/7/usr.sbin/pmcstat/pmcstat.c Mon Aug 9 14:29:23 2010 (r211098)
+++ stable/7/usr.sbin/pmcstat/pmcstat.c Mon Aug 9 14:30:45 2010 (r211099)
@@ -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: stable/7/usr.sbin/pmcstat/pmcstat_log.c
==============================================================================
--- stable/7/usr.sbin/pmcstat/pmcstat_log.c Mon Aug 9 14:29:23 2010 (r211098)
+++ stable/7/usr.sbin/pmcstat/pmcstat_log.c Mon Aug 9 14:30:45 2010 (r211099)
@@ -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);
@@ -1399,6 +1405,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,
@@ -1425,6 +1432,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);
@@ -1691,8 +1699,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);
}
@@ -1709,7 +1724,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;
@@ -1730,7 +1745,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, ':');
@@ -1759,11 +1774,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;
@@ -1833,9 +1866,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);
@@ -1872,7 +1904,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++;
@@ -1915,7 +1947,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();
@@ -1936,7 +1968,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",
@@ -1986,7 +2018,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();
}
@@ -2130,8 +2162,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-stable-7
mailing list