Skip to content

Commit 3c17d1b

Browse files
committed
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.
1 parent 69bfc89 commit 3c17d1b

File tree

5 files changed

+89
-36
lines changed

5 files changed

+89
-36
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Noteworthy changes in release ?.?? (????-??-??)
88
and sched_setaffinity syscalls.
99
* Enhanced decoding of getxpid, getxuid, and getxgid syscalls on alpha.
1010
* Added decoding of bind, listen, and setsockopt direct syscalls on sparc.
11+
* Implemented caching of netlink conversations to reduce amount of time
12+
spent in decoding socket details in -yy mode.
1113

1214
* Bug fixes
1315
* Fixed build on arc, metag, nios2, or1k, and tile architectures.

defs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_b
536536
#define QUOTE_0_TERMINATED 0x01
537537
#define QUOTE_OMIT_LEADING_TRAILING_QUOTES 0x02
538538

539+
extern int string_quote(const char *, char *, unsigned int, unsigned int);
539540
extern int print_quoted_string(const char *, unsigned int, unsigned int);
540541

541542
/* a refers to the lower numbered u_arg,
@@ -613,6 +614,7 @@ extern void printpathn(struct tcb *, long, unsigned int);
613614
(sizeof(intmax_t)*3 * 2 + sizeof("{tv_sec=%jd, tv_nsec=%jd}"))
614615
extern void printfd(struct tcb *, int);
615616
extern bool print_sockaddr_by_inode(const unsigned long, const char *);
617+
extern bool print_sockaddr_by_inode_cached(const unsigned long);
616618
extern void print_dirfd(struct tcb *, int);
617619
extern void printsock(struct tcb *, long, int);
618620
extern void print_sock_optmgmt(struct tcb *, long, int);

socketutils.c

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,38 @@
4545
# define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
4646
#endif
4747

48+
typedef struct {
49+
unsigned long inode;
50+
char *details;
51+
} cache_entry;
52+
53+
#define CACHE_SIZE 1024U
54+
static cache_entry cache[CACHE_SIZE];
55+
#define CACHE_MASK (CACHE_SIZE - 1)
56+
57+
static int
58+
cache_and_print_inode_details(const unsigned long inode, char *details)
59+
{
60+
cache_entry *e = &cache[inode & CACHE_MASK];
61+
free(e->details);
62+
e->inode = inode;
63+
e->details = details;
64+
65+
tprints(details);
66+
return 1;
67+
}
68+
69+
bool
70+
print_sockaddr_by_inode_cached(const unsigned long inode)
71+
{
72+
const cache_entry *e = &cache[inode & CACHE_MASK];
73+
if (e && inode == e->inode) {
74+
tprints(e->details);
75+
return true;
76+
}
77+
return false;
78+
}
79+
4880
static bool
4981
inet_send_query(const int fd, const int family, const int proto)
5082
{
@@ -114,6 +146,7 @@ inet_parse_response(const char *proto_name, const void *data,
114146
}
115147

116148
char src_buf[text_size];
149+
char *details;
117150

118151
if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
119152
src_buf, text_size))
@@ -127,16 +160,17 @@ inet_parse_response(const char *proto_name, const void *data,
127160
dst_buf, text_size))
128161
return -1;
129162

130-
tprintf("%s:[%s:%u->%s:%u]",
131-
proto_name,
132-
src_buf, ntohs(diag_msg->id.idiag_sport),
133-
dst_buf, ntohs(diag_msg->id.idiag_dport));
163+
if (asprintf(&details, "%s:[%s:%u->%s:%u]", proto_name,
164+
src_buf, ntohs(diag_msg->id.idiag_sport),
165+
dst_buf, ntohs(diag_msg->id.idiag_dport)) < 0)
166+
return false;
134167
} else {
135-
tprintf("%s:[%s:%u]", proto_name, src_buf,
136-
ntohs(diag_msg->id.idiag_sport));
168+
if (asprintf(&details, "%s:[%s:%u]", proto_name, src_buf,
169+
ntohs(diag_msg->id.idiag_sport)) < 0)
170+
return false;
137171
}
138172

139-
return 1;
173+
return cache_and_print_inode_details(inode, details);
140174
}
141175

142176
static bool
@@ -282,26 +316,39 @@ unix_parse_response(const char *proto_name, const void *data,
282316
* print obtained information in the following format:
283317
* "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
284318
*/
285-
if (peer || path_len) {
286-
tprintf("%s:[%lu", proto_name, inode);
287-
if (peer)
288-
tprintf("->%u", peer);
289-
if (path_len) {
290-
if (path[0] == '\0') {
291-
tprints(",@");
292-
print_quoted_string(path + 1, path_len,
293-
QUOTE_0_TERMINATED);
294-
} else {
295-
tprints(",");
296-
print_quoted_string(path, path_len + 1,
297-
QUOTE_0_TERMINATED);
298-
}
319+
if (!peer && !path_len)
320+
return -1;
321+
322+
char peer_str[3 + sizeof(peer) * 3];
323+
if (peer)
324+
snprintf(peer_str, sizeof(peer_str), "->%u", peer);
325+
else
326+
peer_str[0] = '\0';
327+
328+
const char *path_str;
329+
if (path_len) {
330+
char *outstr = alloca(4 * path_len + 4);
331+
332+
outstr[0] = ',';
333+
if (path[0] == '\0') {
334+
outstr[1] = '@';
335+
string_quote(path + 1, outstr + 2,
336+
path_len - 1, QUOTE_0_TERMINATED);
337+
} else {
338+
string_quote(path, outstr + 1,
339+
path_len, QUOTE_0_TERMINATED);
299340
}
300-
tprints("]");
301-
return 1;
341+
path_str = outstr;
342+
} else {
343+
path_str = "";
302344
}
303-
else
345+
346+
char *details;
347+
if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode,
348+
peer_str, path_str) < 0)
304349
return -1;
350+
351+
return cache_and_print_inode_details(inode, details);
305352
}
306353

307354
static bool

tests/net-yy-unix.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ main(int ac, const char **av)
141141
connect_fd, connect_inode, accept_inode);
142142

143143
assert(close(accept_fd) == 0);
144-
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
145-
accept_fd, accept_inode, av[1]);
144+
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
145+
accept_fd, accept_inode, connect_inode, av[1]);
146146

147147
connect_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
148148
if (connect_fd < 0)
@@ -213,8 +213,8 @@ main(int ac, const char **av)
213213
connect_fd, connect_inode, accept_inode, sun_path1);
214214

215215
assert(close(accept_fd) == 0);
216-
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
217-
accept_fd, accept_inode, av[1]);
216+
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
217+
accept_fd, accept_inode, connect_inode, av[1]);
218218

219219
assert(unlink(av[1]) == 0);
220220

util.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -512,14 +512,16 @@ printfd(struct tcb *tcp, int fd)
512512
if (show_fd_path > 1 &&
513513
strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
514514
path[path_len - 1] == ']') {
515-
unsigned long inodenr =
515+
unsigned long inode =
516516
strtoul(path + socket_prefix_len, NULL, 10);
517-
#define PROTO_NAME_LEN 32
518-
char proto_buf[PROTO_NAME_LEN];
519-
const char *proto =
520-
getfdproto(tcp, fd, proto_buf, PROTO_NAME_LEN);
521-
if (!print_sockaddr_by_inode(inodenr, proto))
522-
tprints(path);
517+
518+
if (!print_sockaddr_by_inode_cached(inode)) {
519+
char buf[256];
520+
const char *proto =
521+
getfdproto(tcp, fd, buf, sizeof(buf));
522+
if (!print_sockaddr_by_inode(inode, proto))
523+
tprints(path);
524+
}
523525
} else {
524526
print_quoted_string(path, path_len,
525527
QUOTE_OMIT_LEADING_TRAILING_QUOTES);
@@ -543,7 +545,7 @@ printfd(struct tcb *tcp, int fd)
543545
* Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
544546
* Note that if QUOTE_0_TERMINATED is not set, always returns 1.
545547
*/
546-
static int
548+
int
547549
string_quote(const char *instr, char *outstr, const unsigned int size,
548550
const unsigned int style)
549551
{

0 commit comments

Comments
 (0)