3 * Utility to get per-pid and per-tgid delay accounting statistics
4 * Also illustrates usage of the taskstats interface
6 * Copyright (C) Shailabh Nagar, IBM Corp. 2005
7 * Copyright (C) Balbir Singh, IBM Corp. 2006
18 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
24 #include <linux/genetlink.h>
25 #include <linux/taskstats.h>
28 * Generic macros for dealing with netlink sockets. Might be duplicated
29 * elsewhere. It is recommended that commercial grade applications use
30 * libnl or libnetlink and use the interfaces provided by the library
32 #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
33 #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
34 #define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
35 #define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
37 #define err(code, fmt, arg...) do { printf(fmt, ##arg); exit(code); } while (0)
41 * Create a raw netlink socket and bind
43 static int create_nl_socket(int protocol
, int groups
)
47 struct sockaddr_nl local
;
49 fd
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
53 memset(&local
, 0, sizeof(local
));
54 local
.nl_family
= AF_NETLINK
;
55 local
.nl_groups
= groups
;
57 if (bind(fd
, (struct sockaddr
*) &local
, sizeof(local
)) < 0)
66 int sendto_fd(int s
, const char *buf
, int bufLen
)
68 struct sockaddr_nl nladdr
;
71 memset(&nladdr
, 0, sizeof(nladdr
));
72 nladdr
.nl_family
= AF_NETLINK
;
74 while ((r
= sendto(s
, buf
, bufLen
, 0, (struct sockaddr
*) &nladdr
,
75 sizeof(nladdr
))) < bufLen
) {
79 } else if (errno
!= EAGAIN
)
86 * Probe the controller in genetlink to find the family id
87 * for the TASKSTATS family
89 int get_family_id(int sd
)
106 /* Get family name */
107 family_req
.n
.nlmsg_type
= GENL_ID_CTRL
;
108 family_req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
109 family_req
.n
.nlmsg_seq
= 0;
110 family_req
.n
.nlmsg_pid
= getpid();
111 family_req
.n
.nlmsg_len
= NLMSG_LENGTH(GENL_HDRLEN
);
112 family_req
.g
.cmd
= CTRL_CMD_GETFAMILY
;
113 family_req
.g
.version
= 0x1;
114 na
= (struct nlattr
*) GENLMSG_DATA(&family_req
);
115 na
->nla_type
= CTRL_ATTR_FAMILY_NAME
;
116 na
->nla_len
= strlen(TASKSTATS_GENL_NAME
) + 1 + NLA_HDRLEN
;
117 strcpy(NLA_DATA(na
), TASKSTATS_GENL_NAME
);
118 family_req
.n
.nlmsg_len
+= NLMSG_ALIGN(na
->nla_len
);
120 if (sendto_fd(sd
, (char *) &family_req
, family_req
.n
.nlmsg_len
) < 0)
121 err(1, "error sending message via Netlink\n");
123 rep_len
= recv(sd
, &ans
, sizeof(ans
), 0);
126 err(1, "error receiving reply message via Netlink\n");
129 /* Validate response message */
130 if (!NLMSG_OK((&ans
.n
), rep_len
))
131 err(1, "invalid reply message received via Netlink\n");
133 if (ans
.n
.nlmsg_type
== NLMSG_ERROR
) { /* error */
134 printf("error received NACK - leaving\n");
139 na
= (struct nlattr
*) GENLMSG_DATA(&ans
);
140 na
= (struct nlattr
*) ((char *) na
+ NLA_ALIGN(na
->nla_len
));
141 if (na
->nla_type
== CTRL_ATTR_FAMILY_ID
) {
142 id
= *(__u16
*) NLA_DATA(na
);
147 void print_taskstats(struct taskstats
*t
)
149 printf("\n\nCPU %15s%15s%15s%15s\n"
150 " %15llu%15llu%15llu%15llu\n"
155 "count", "real total", "virtual total", "delay total",
156 t
->cpu_count
, t
->cpu_run_real_total
, t
->cpu_run_virtual_total
,
158 "count", "delay total",
159 t
->blkio_count
, t
->blkio_delay_total
,
160 "count", "delay total", t
->swapin_count
, t
->swapin_delay_total
);
163 void sigchld(int sig
)
168 int main(int argc
, char *argv
[])
172 struct nlmsghdr
*nlh
;
173 struct genlmsghdr
*genlhdr
;
175 struct taskstats_cmd_param
*param
;
180 struct sockaddr_nl kern_nla
, from_nla
;
181 socklen_t from_nla_len
;
183 struct taskstats_reply
*reply
;
201 struct sockaddr_nl nladdr
;
204 int cmd_type
= TASKSTATS_TYPE_TGID
;
207 struct sigaction act
= {
208 .sa_handler
= SIG_IGN
,
209 .sa_mask
= SA_NOMASK
,
211 struct sigaction tact
;
214 printf("usage %s [-t tgid][-p pid][-c cmd]\n", argv
[0]);
218 tact
.sa_handler
= sigchld
;
219 sigemptyset(&tact
.sa_mask
);
220 if (sigaction(SIGCHLD
, &tact
, NULL
) < 0)
221 err(1, "sigaction failed for SIGCHLD\n");
225 c
= getopt(argc
, argv
, "t:p:c:");
233 err(1, "Invalid tgid\n");
234 cmd_type
= TASKSTATS_CMD_ATTR_TGID
;
239 err(1, "Invalid pid\n");
240 cmd_type
= TASKSTATS_CMD_ATTR_TGID
;
246 err(1, "fork failed\n");
248 if (tid
== 0) { /* child process */
249 if (execvp(argv
[optind
- 1], &argv
[optind
- 1]) < 0) {
256 printf("usage %s [-t tgid][-p pid][-c cmd]\n", argv
[0]);
264 /* Construct Netlink request message */
266 /* Send Netlink request message & get reply */
269 create_nl_socket(NETLINK_GENERIC
, TASKSTATS_LISTEN_GROUP
)) < 0)
270 err(1, "error creating Netlink socket\n");
273 id
= get_family_id(nl_sd
);
275 /* Send command needed */
276 req
.n
.nlmsg_len
= NLMSG_LENGTH(GENL_HDRLEN
);
277 req
.n
.nlmsg_type
= id
;
278 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
280 req
.n
.nlmsg_pid
= tid
;
281 req
.g
.cmd
= TASKSTATS_CMD_GET
;
282 na
= (struct nlattr
*) GENLMSG_DATA(&req
);
283 na
->nla_type
= cmd_type
;
284 na
->nla_len
= sizeof(unsigned int) + NLA_HDRLEN
;
285 *(__u32
*) NLA_DATA(na
) = tid
;
286 req
.n
.nlmsg_len
+= NLMSG_ALIGN(na
->nla_len
);
289 if (!forking
&& sendto_fd(nl_sd
, (char *) &req
, req
.n
.nlmsg_len
) < 0)
290 err(1, "error sending message via Netlink\n");
292 act
.sa_handler
= SIG_IGN
;
293 sigemptyset(&act
.sa_mask
);
294 if (sigaction(SIGINT
, &act
, NULL
) < 0)
295 err(1, "sigaction failed for SIGINT\n");
302 pfd
.events
= 0xffff & ~POLLOUT
;
304 pollres
= poll(&pfd
, 1, 5000);
305 if (pollres
< 0 || done
) {
309 rep_len
= recv(nl_sd
, &ans
, sizeof(ans
), 0);
310 nladdr
.nl_family
= AF_NETLINK
;
311 nladdr
.nl_groups
= TASKSTATS_LISTEN_GROUP
;
313 if (ans
.n
.nlmsg_type
== NLMSG_ERROR
) { /* error */
314 printf("error received NACK - leaving\n");
319 err(1, "error receiving reply message via Netlink\n");
323 /* Validate response message */
324 if (!NLMSG_OK((&ans
.n
), rep_len
))
325 err(1, "invalid reply message received via Netlink\n");
327 rep_len
= GENLMSG_PAYLOAD(&ans
.n
);
329 na
= (struct nlattr
*) GENLMSG_DATA(&ans
);
332 while (len
< rep_len
) {
333 len
+= NLA_ALIGN(na
->nla_len
);
334 switch (na
->nla_type
) {
335 case TASKSTATS_TYPE_AGGR_PID
:
337 case TASKSTATS_TYPE_AGGR_TGID
:
338 aggr_len
= NLA_PAYLOAD(na
->nla_len
);
340 /* For nested attributes, na follows */
341 na
= (struct nlattr
*) NLA_DATA(na
);
343 while (len2
< aggr_len
) {
344 switch (na
->nla_type
) {
345 case TASKSTATS_TYPE_PID
:
346 rtid
= *(int *) NLA_DATA(na
);
348 case TASKSTATS_TYPE_TGID
:
349 rtid
= *(int *) NLA_DATA(na
);
351 case TASKSTATS_TYPE_STATS
:
353 print_taskstats((struct taskstats
*)
359 len2
+= NLA_ALIGN(na
->nla_len
);
360 na
= (struct nlattr
*) ((char *) na
+ len2
);
365 na
= (struct nlattr
*) (GENLMSG_DATA(&ans
) + len
);