- 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
This commit is contained in:
Joseph Koshy 2006-04-02 12:52:16 +00:00
parent 876f7f842a
commit 302cbb9054
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157406
3 changed files with 107 additions and 24 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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);
}