Implement caching of print_sockaddr_by_inode

As -yy parser, compared to -y, needs to do at least 5 extra syscalls
(getxattr, socket, sendmsg, recvmsg, close) to print socket details,
caching results of netlink conversations between strace and kernel
noticeably reduces amount of system time spent by strace.

The caching is safe since sockets do not change their addresses after
successful bind or connect syscall.

* defs.h (string_quote, print_sockaddr_by_inode_cached): New prototypes.
* socketutils.c (cache_entry): New type.
(CACHE_SIZE, CACHE_MASK): New macros.
(cache): New static array.
(cache_and_print_inode_details): New static function.
(print_sockaddr_by_inode_cached): New function.
(inet_parse_response, unix_parse_response): Use
cache_and_print_inode_details.
* util.c (printfd): Use string_quote and print_sockaddr_by_inode_cached.
(string_quote): Remove static qualifier.
* NEWS: Mention this improvement.
* tests/unix-yy.c (main): Update.
This commit is contained in:
Дмитрий Левин 2016-02-01 23:14:59 +00:00
parent 69bfc89770
commit 3c17d1b5e1
5 changed files with 91 additions and 38 deletions

2
NEWS
View File

@ -8,6 +8,8 @@ Noteworthy changes in release ?.?? (????-??-??)
and sched_setaffinity syscalls.
* Enhanced decoding of getxpid, getxuid, and getxgid syscalls on alpha.
* Added decoding of bind, listen, and setsockopt direct syscalls on sparc.
* Implemented caching of netlink conversations to reduce amount of time
spent in decoding socket details in -yy mode.
* Bug fixes
* Fixed build on arc, metag, nios2, or1k, and tile architectures.

2
defs.h
View File

@ -536,6 +536,7 @@ extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_b
#define QUOTE_0_TERMINATED 0x01
#define QUOTE_OMIT_LEADING_TRAILING_QUOTES 0x02
extern int string_quote(const char *, char *, unsigned int, unsigned int);
extern int print_quoted_string(const char *, unsigned int, unsigned int);
/* a refers to the lower numbered u_arg,
@ -613,6 +614,7 @@ extern void printpathn(struct tcb *, long, unsigned int);
(sizeof(intmax_t)*3 * 2 + sizeof("{tv_sec=%jd, tv_nsec=%jd}"))
extern void printfd(struct tcb *, int);
extern bool print_sockaddr_by_inode(const unsigned long, const char *);
extern bool print_sockaddr_by_inode_cached(const unsigned long);
extern void print_dirfd(struct tcb *, int);
extern void printsock(struct tcb *, long, int);
extern void print_sock_optmgmt(struct tcb *, long, int);

View File

@ -45,6 +45,38 @@
# define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
#endif
typedef struct {
unsigned long inode;
char *details;
} cache_entry;
#define CACHE_SIZE 1024U
static cache_entry cache[CACHE_SIZE];
#define CACHE_MASK (CACHE_SIZE - 1)
static int
cache_and_print_inode_details(const unsigned long inode, char *details)
{
cache_entry *e = &cache[inode & CACHE_MASK];
free(e->details);
e->inode = inode;
e->details = details;
tprints(details);
return 1;
}
bool
print_sockaddr_by_inode_cached(const unsigned long inode)
{
const cache_entry *e = &cache[inode & CACHE_MASK];
if (e && inode == e->inode) {
tprints(e->details);
return true;
}
return false;
}
static bool
inet_send_query(const int fd, const int family, const int proto)
{
@ -114,6 +146,7 @@ inet_parse_response(const char *proto_name, const void *data,
}
char src_buf[text_size];
char *details;
if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
src_buf, text_size))
@ -127,16 +160,17 @@ inet_parse_response(const char *proto_name, const void *data,
dst_buf, text_size))
return -1;
tprintf("%s:[%s:%u->%s:%u]",
proto_name,
src_buf, ntohs(diag_msg->id.idiag_sport),
dst_buf, ntohs(diag_msg->id.idiag_dport));
if (asprintf(&details, "%s:[%s:%u->%s:%u]", proto_name,
src_buf, ntohs(diag_msg->id.idiag_sport),
dst_buf, ntohs(diag_msg->id.idiag_dport)) < 0)
return false;
} else {
tprintf("%s:[%s:%u]", proto_name, src_buf,
ntohs(diag_msg->id.idiag_sport));
if (asprintf(&details, "%s:[%s:%u]", proto_name, src_buf,
ntohs(diag_msg->id.idiag_sport)) < 0)
return false;
}
return 1;
return cache_and_print_inode_details(inode, details);
}
static bool
@ -282,26 +316,39 @@ unix_parse_response(const char *proto_name, const void *data,
* print obtained information in the following format:
* "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
*/
if (peer || path_len) {
tprintf("%s:[%lu", proto_name, inode);
if (peer)
tprintf("->%u", peer);
if (path_len) {
if (path[0] == '\0') {
tprints(",@");
print_quoted_string(path + 1, path_len,
QUOTE_0_TERMINATED);
} else {
tprints(",");
print_quoted_string(path, path_len + 1,
QUOTE_0_TERMINATED);
}
}
tprints("]");
return 1;
}
else
if (!peer && !path_len)
return -1;
char peer_str[3 + sizeof(peer) * 3];
if (peer)
snprintf(peer_str, sizeof(peer_str), "->%u", peer);
else
peer_str[0] = '\0';
const char *path_str;
if (path_len) {
char *outstr = alloca(4 * path_len + 4);
outstr[0] = ',';
if (path[0] == '\0') {
outstr[1] = '@';
string_quote(path + 1, outstr + 2,
path_len - 1, QUOTE_0_TERMINATED);
} else {
string_quote(path, outstr + 1,
path_len, QUOTE_0_TERMINATED);
}
path_str = outstr;
} else {
path_str = "";
}
char *details;
if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode,
peer_str, path_str) < 0)
return -1;
return cache_and_print_inode_details(inode, details);
}
static bool

View File

@ -141,8 +141,8 @@ main(int ac, const char **av)
connect_fd, connect_inode, accept_inode);
assert(close(accept_fd) == 0);
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
accept_fd, accept_inode, av[1]);
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
accept_fd, accept_inode, connect_inode, av[1]);
connect_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
if (connect_fd < 0)
@ -213,8 +213,8 @@ main(int ac, const char **av)
connect_fd, connect_inode, accept_inode, sun_path1);
assert(close(accept_fd) == 0);
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
accept_fd, accept_inode, av[1]);
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
accept_fd, accept_inode, connect_inode, av[1]);
assert(unlink(av[1]) == 0);

18
util.c
View File

@ -512,14 +512,16 @@ printfd(struct tcb *tcp, int fd)
if (show_fd_path > 1 &&
strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
path[path_len - 1] == ']') {
unsigned long inodenr =
unsigned long inode =
strtoul(path + socket_prefix_len, NULL, 10);
#define PROTO_NAME_LEN 32
char proto_buf[PROTO_NAME_LEN];
const char *proto =
getfdproto(tcp, fd, proto_buf, PROTO_NAME_LEN);
if (!print_sockaddr_by_inode(inodenr, proto))
tprints(path);
if (!print_sockaddr_by_inode_cached(inode)) {
char buf[256];
const char *proto =
getfdproto(tcp, fd, buf, sizeof(buf));
if (!print_sockaddr_by_inode(inode, proto))
tprints(path);
}
} else {
print_quoted_string(path, path_len,
QUOTE_OMIT_LEADING_TRAILING_QUOTES);
@ -543,7 +545,7 @@ printfd(struct tcb *tcp, int fd)
* Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
* Note that if QUOTE_0_TERMINATED is not set, always returns 1.
*/
static int
int
string_quote(const char *instr, char *outstr, const unsigned int size,
const unsigned int style)
{