summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pmcstat
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2006-04-02 12:52:16 +0000
committerjkoshy <jkoshy@FreeBSD.org>2006-04-02 12:52:16 +0000
commit80251d4f05948e213f6f292db20a93ad4cf36852 (patch)
treef82c027fa9baa5cc1c2c54f83529b6118bd99a57 /usr.sbin/pmcstat
parent19f9c1efe47d365dd95231c4ba6a1e467157f00a (diff)
downloadFreeBSD-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/pmcstat')
-rw-r--r--usr.sbin/pmcstat/pmcstat.841
-rw-r--r--usr.sbin/pmcstat/pmcstat.c17
-rw-r--r--usr.sbin/pmcstat/pmcstat_log.c73
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);
}
OpenPOWER on IntegriCloud