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