- 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:
parent
876f7f842a
commit
302cbb9054
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157406
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user