diff options
author | jkoshy <jkoshy@FreeBSD.org> | 2006-04-02 12:52:16 +0000 |
---|---|---|
committer | jkoshy <jkoshy@FreeBSD.org> | 2006-04-02 12:52:16 +0000 |
commit | 80251d4f05948e213f6f292db20a93ad4cf36852 (patch) | |
tree | f82c027fa9baa5cc1c2c54f83529b6118bd99a57 /usr.sbin | |
parent | 19f9c1efe47d365dd95231c4ba6a1e467157f00a (diff) | |
download | FreeBSD-src-80251d4f05948e213f6f292db20a93ad4cf36852.zip FreeBSD-src-80251d4f05948e213f6f292db20a93ad4cf36852.tar.gz |
- Teach pmcstat(8) to log over the network; the -O option now
takes a host:port specification.
- Update the manual page and add an example showing how log
over the network using pmcstat(8) and nc(1). Document the
current inability to process logs in cross-platform manner.
- Have pmcstat_open_log() call err(3) directly in case
of an error; this simplifies error handling in its caller.
MFC after: 1 week
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/pmcstat/pmcstat.8 | 41 | ||||
-rw-r--r-- | usr.sbin/pmcstat/pmcstat.c | 17 | ||||
-rw-r--r-- | usr.sbin/pmcstat/pmcstat_log.c | 73 |
3 files changed, 107 insertions, 24 deletions
diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8 index 692216f..5a3e3ec 100644 --- a/usr.sbin/pmcstat/pmcstat.8 +++ b/usr.sbin/pmcstat/pmcstat.8 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 26, 2006 +.Dd April 2, 2006 .Os .Dt PMCSTAT 8 .Sh NAME @@ -138,8 +138,27 @@ option. .It Fl O Ar logfilename Send logging output to file .Ar logfilename . -If this option is not specified and one of the logging options -is requested, then +If +.Ar logfilename +is of the form +.Ar hostname Ns : Ns Ar port , +where +.Ar hostname +does not start with a +.Sq \&. +or a +.Sq / , +then +.Nm +will open a network socket to host +.Ar hostname +on port +.Ar port . +.Pp +If the +.Fl O +option is not specified and one of the logging options is requested, +then .Nm will print a textual form of the logged events to the configured output file. @@ -249,10 +268,16 @@ and measure the number of data cache misses suffered by it and its children every 12 seconds on an AMD Athlon, use: .Dl "pmcstat -d -w 12 -p k7-dc-misses mozilla" .Pp -To collect a system-wide samples driven by processor instructions executed -use: +To perform system-wide sampling based on processor instructions +retired use: .Dl "pmcstat -S instructions -O /tmp/sample.out" .Pp +To send the generated event log to a remote machine use: +.Dl "pmcstat -S instructions -O remotehost:port" +On the remote machine, the sample log can be collected using +.Xr nc 1 : +.Dl "nc -l remotehost port > /tmp/sample.out" +.Pp To generate .Xr gprof 1 compatible flat profiles from a sample file use: @@ -261,6 +286,7 @@ compatible flat profiles from a sample file use: .Ex -std .Sh SEE ALSO .Xr gprof 1 , +.Xr nc 1 , .Xr execvp 3 , .Xr pmc 3 , .Xr pmclog 3 , @@ -277,6 +303,7 @@ It is .Sh AUTHORS .An Joseph Koshy Aq jkoshy@FreeBSD.org .Sh BUGS -On AMD64 platforms .Nm -does not yet handle profiles with samples from 32 bit executables. +cannot yet analyse +.Xr hwpmc 4 +logs generated by non-native architectures. diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c index dd78bcd..9027a39 100644 --- a/usr.sbin/pmcstat/pmcstat.c +++ b/usr.sbin/pmcstat/pmcstat.c @@ -751,10 +751,8 @@ main(int argc, char **argv) args.pa_flags |= FLAG_DO_PRINT; pmcstat_initialize_logging(&args); - if ((args.pa_logfd = pmcstat_open_log(args.pa_inputpath, - PMCSTAT_OPEN_FOR_READ)) < 0) - err(EX_OSERR, "ERROR: Cannot open \"%s\" for " - "reading", args.pa_inputpath); + args.pa_logfd = pmcstat_open_log(args.pa_inputpath, + PMCSTAT_OPEN_FOR_READ); if ((args.pa_logparser = pmclog_open(args.pa_logfd)) == NULL) err(EX_OSERR, "ERROR: Cannot create parser"); pmcstat_process_log(&args); @@ -784,13 +782,10 @@ main(int argc, char **argv) * consumer via a pipe. */ if (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) { - if (args.pa_outputpath) { - if ((args.pa_logfd = - pmcstat_open_log(args.pa_outputpath, - PMCSTAT_OPEN_FOR_WRITE)) < 0) - err(EX_OSERR, "ERROR: Cannot open \"%s\" for " - "writing", args.pa_outputpath); - } else { + if (args.pa_outputpath) + args.pa_logfd = pmcstat_open_log(args.pa_outputpath, + PMCSTAT_OPEN_FOR_WRITE); + else { /* * process the log on the fly by reading it in * through a pipe. diff --git a/usr.sbin/pmcstat/pmcstat_log.c b/usr.sbin/pmcstat/pmcstat_log.c index 8cf3087..0beb7c7 100644 --- a/usr.sbin/pmcstat/pmcstat_log.c +++ b/usr.sbin/pmcstat/pmcstat_log.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mman.h> #include <sys/pmc.h> #include <sys/queue.h> +#include <sys/socket.h> #include <sys/stat.h> #include <sys/wait.h> @@ -47,9 +48,11 @@ __FBSDID("$FreeBSD$"); #include <assert.h> #include <err.h> +#include <errno.h> #include <fcntl.h> #include <libgen.h> #include <limits.h> +#include <netdb.h> #include <pmc.h> #include <pmclog.h> #include <sysexits.h> @@ -1639,19 +1642,77 @@ pmcstat_close_log(struct pmcstat_args *a) int pmcstat_open_log(const char *path, int mode) { - int fd; + int error, fd; + size_t hlen; + const char *p, *errstr; + struct addrinfo hints, *res, *res0; + char hostname[MAXHOSTNAMELEN]; + + errstr = NULL; + fd = -1; /* * If 'path' is "-" then open one of stdin or stdout depending - * on the value of 'mode'. Otherwise, treat 'path' as a file - * name and open that. + * on the value of 'mode'. + * + * If 'path' contains a ':' and does not start with a '/' or '.', + * and is being opened for writing, treat it as a "host:port" + * specification and open a network socket. + * + * Otherwise, treat 'path' as a file name and open that. */ if (path[0] == '-' && path[1] == '\0') fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; - else - fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? + else if (mode == PMCSTAT_OPEN_FOR_WRITE && path[0] != '/' && + path[0] != '.' && strchr(path, ':') != NULL) { + + p = strrchr(path, ':'); + hlen = p - path; + if (p == path || hlen >= sizeof(hostname)) { + errstr = strerror(EINVAL); + goto done; + } + + assert(hlen < sizeof(hostname)); + (void) strncpy(hostname, path, hlen); + hostname[hlen] = '\0'; + + (void) memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if ((error = getaddrinfo(hostname, p+1, &hints, &res0)) != 0) { + errstr = gai_strerror(error); + goto done; + } + + fd = -1; + for (res = res0; res; res = res->ai_next) { + if ((fd = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) { + errstr = strerror(errno); + continue; + } + if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { + errstr = strerror(errno); + (void) close(fd); + fd = -1; + continue; + } + errstr = NULL; + break; + } + freeaddrinfo(res0); + + } else if ((fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), - S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) + errstr = strerror(errno); + + done: + if (errstr) + errx(EX_OSERR, "ERROR: Cannot open \"%s\" for %s: %s.", path, + (mode == PMCSTAT_OPEN_FOR_READ ? "reading" : "writing"), + errstr); return (fd); } |