getdelays.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* getdelays.c
  3. *
  4. * Utility to get per-pid and per-tgid delay accounting statistics
  5. * Also illustrates usage of the taskstats interface
  6. *
  7. * Copyright (C) Shailabh Nagar, IBM Corp. 2005
  8. * Copyright (C) Balbir Singh, IBM Corp. 2006
  9. * Copyright (c) Jay Lan, SGI. 2006
  10. *
  11. * Compile with
  12. * gcc -I/usr/src/linux/include getdelays.c -o getdelays
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <errno.h>
  17. #include <unistd.h>
  18. #include <poll.h>
  19. #include <string.h>
  20. #include <fcntl.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <sys/socket.h>
  24. #include <sys/wait.h>
  25. #include <signal.h>
  26. #include <time.h>
  27. #include <linux/genetlink.h>
  28. #include <linux/taskstats.h>
  29. #include <linux/cgroupstats.h>
  30. /*
  31. * Generic macros for dealing with netlink sockets. Might be duplicated
  32. * elsewhere. It is recommended that commercial grade applications use
  33. * libnl or libnetlink and use the interfaces provided by the library
  34. */
  35. #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
  36. #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
  37. #define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
  38. #define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
  39. #define err(code, fmt, arg...) \
  40. do { \
  41. fprintf(stderr, fmt, ##arg); \
  42. exit(code); \
  43. } while (0)
  44. int rcvbufsz;
  45. char name[100];
  46. int dbg;
  47. int print_delays;
  48. int print_io_accounting;
  49. int print_task_context_switch_counts;
  50. #define PRINTF(fmt, arg...) { \
  51. if (dbg) { \
  52. printf(fmt, ##arg); \
  53. } \
  54. }
  55. /* Maximum size of response requested or message sent */
  56. #define MAX_MSG_SIZE 1024
  57. /* Maximum number of cpus expected to be specified in a cpumask */
  58. #define MAX_CPUS 32
  59. struct msgtemplate {
  60. struct nlmsghdr n;
  61. struct genlmsghdr g;
  62. char buf[MAX_MSG_SIZE];
  63. };
  64. char cpumask[100+6*MAX_CPUS];
  65. static void usage(void)
  66. {
  67. fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
  68. "[-m cpumask] [-t tgid] [-p pid]\n");
  69. fprintf(stderr, " -d: print delayacct stats\n");
  70. fprintf(stderr, " -i: print IO accounting (works only with -p)\n");
  71. fprintf(stderr, " -l: listen forever\n");
  72. fprintf(stderr, " -v: debug on\n");
  73. fprintf(stderr, " -C: container path\n");
  74. }
  75. /*
  76. * Create a raw netlink socket and bind
  77. */
  78. static int create_nl_socket(int protocol)
  79. {
  80. int fd;
  81. struct sockaddr_nl local;
  82. fd = socket(AF_NETLINK, SOCK_RAW, protocol);
  83. if (fd < 0)
  84. return -1;
  85. if (rcvbufsz)
  86. if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
  87. &rcvbufsz, sizeof(rcvbufsz)) < 0) {
  88. fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
  89. rcvbufsz);
  90. goto error;
  91. }
  92. memset(&local, 0, sizeof(local));
  93. local.nl_family = AF_NETLINK;
  94. if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
  95. goto error;
  96. return fd;
  97. error:
  98. close(fd);
  99. return -1;
  100. }
  101. static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
  102. __u8 genl_cmd, __u16 nla_type,
  103. void *nla_data, int nla_len)
  104. {
  105. struct nlattr *na;
  106. struct sockaddr_nl nladdr;
  107. int r, buflen;
  108. char *buf;
  109. struct msgtemplate msg;
  110. msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
  111. msg.n.nlmsg_type = nlmsg_type;
  112. msg.n.nlmsg_flags = NLM_F_REQUEST;
  113. msg.n.nlmsg_seq = 0;
  114. msg.n.nlmsg_pid = nlmsg_pid;
  115. msg.g.cmd = genl_cmd;
  116. msg.g.version = 0x1;
  117. na = (struct nlattr *) GENLMSG_DATA(&msg);
  118. na->nla_type = nla_type;
  119. na->nla_len = nla_len + NLA_HDRLEN;
  120. memcpy(NLA_DATA(na), nla_data, nla_len);
  121. msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
  122. buf = (char *) &msg;
  123. buflen = msg.n.nlmsg_len ;
  124. memset(&nladdr, 0, sizeof(nladdr));
  125. nladdr.nl_family = AF_NETLINK;
  126. while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
  127. sizeof(nladdr))) < buflen) {
  128. if (r > 0) {
  129. buf += r;
  130. buflen -= r;
  131. } else if (errno != EAGAIN)
  132. return -1;
  133. }
  134. return 0;
  135. }
  136. /*
  137. * Probe the controller in genetlink to find the family id
  138. * for the TASKSTATS family
  139. */
  140. static int get_family_id(int sd)
  141. {
  142. struct {
  143. struct nlmsghdr n;
  144. struct genlmsghdr g;
  145. char buf[256];
  146. } ans;
  147. int id = 0, rc;
  148. struct nlattr *na;
  149. int rep_len;
  150. strcpy(name, TASKSTATS_GENL_NAME);
  151. rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
  152. CTRL_ATTR_FAMILY_NAME, (void *)name,
  153. strlen(TASKSTATS_GENL_NAME)+1);
  154. if (rc < 0)
  155. return 0; /* sendto() failure? */
  156. rep_len = recv(sd, &ans, sizeof(ans), 0);
  157. if (ans.n.nlmsg_type == NLMSG_ERROR ||
  158. (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
  159. return 0;
  160. na = (struct nlattr *) GENLMSG_DATA(&ans);
  161. na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
  162. if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
  163. id = *(__u16 *) NLA_DATA(na);
  164. }
  165. return id;
  166. }
  167. #define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
  168. #define delay_ms(t) (t / 1000000ULL)
  169. /*
  170. * Format __kernel_timespec to human readable string (YYYY-MM-DD HH:MM:SS)
  171. * Returns formatted string or "N/A" if timestamp is zero
  172. */
  173. static const char *format_timespec(struct __kernel_timespec *ts)
  174. {
  175. static char buffer[32];
  176. struct tm tm_info;
  177. __kernel_time_t time_sec;
  178. /* Check if timestamp is zero (not set) */
  179. if (ts->tv_sec == 0 && ts->tv_nsec == 0)
  180. return "N/A";
  181. time_sec = ts->tv_sec;
  182. /* Use thread-safe localtime_r */
  183. if (localtime_r(&time_sec, &tm_info) == NULL)
  184. return "N/A";
  185. snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d",
  186. tm_info.tm_year + 1900,
  187. tm_info.tm_mon + 1,
  188. tm_info.tm_mday,
  189. tm_info.tm_hour,
  190. tm_info.tm_min,
  191. tm_info.tm_sec);
  192. return buffer;
  193. }
  194. /*
  195. * Version compatibility note:
  196. * Field availability depends on taskstats version (t->version),
  197. * corresponding to TASKSTATS_VERSION in kernel headers
  198. * see include/uapi/linux/taskstats.h
  199. *
  200. * Version feature mapping:
  201. * version >= 11 - supports COMPACT statistics
  202. * version >= 13 - supports WPCOPY statistics
  203. * version >= 14 - supports IRQ statistics
  204. * version >= 16 - supports *_max and *_min delay statistics
  205. * version >= 17 - supports delay max timestamp statistics
  206. *
  207. * Always verify version before accessing version-dependent fields
  208. * to maintain backward compatibility.
  209. */
  210. #define PRINT_CPU_DELAY(version, t) \
  211. do { \
  212. if (version >= 17) { \
  213. printf("%-10s%15s%15s%15s%15s%15s%15s%15s%25s\n", \
  214. "CPU", "count", "real total", "virtual total", \
  215. "delay total", "delay average", "delay max", \
  216. "delay min", "delay max timestamp"); \
  217. printf(" %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms%23s\n", \
  218. (unsigned long long)(t)->cpu_count, \
  219. (unsigned long long)(t)->cpu_run_real_total, \
  220. (unsigned long long)(t)->cpu_run_virtual_total, \
  221. (unsigned long long)(t)->cpu_delay_total, \
  222. average_ms((double)(t)->cpu_delay_total, (t)->cpu_count), \
  223. delay_ms((double)(t)->cpu_delay_max), \
  224. delay_ms((double)(t)->cpu_delay_min), \
  225. format_timespec(&(t)->cpu_delay_max_ts)); \
  226. } else if (version >= 16) { \
  227. printf("%-10s%15s%15s%15s%15s%15s%15s%15s\n", \
  228. "CPU", "count", "real total", "virtual total", \
  229. "delay total", "delay average", "delay max", "delay min"); \
  230. printf(" %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n", \
  231. (unsigned long long)(t)->cpu_count, \
  232. (unsigned long long)(t)->cpu_run_real_total, \
  233. (unsigned long long)(t)->cpu_run_virtual_total, \
  234. (unsigned long long)(t)->cpu_delay_total, \
  235. average_ms((double)(t)->cpu_delay_total, (t)->cpu_count), \
  236. delay_ms((double)(t)->cpu_delay_max), \
  237. delay_ms((double)(t)->cpu_delay_min)); \
  238. } else { \
  239. printf("%-10s%15s%15s%15s%15s%15s\n", \
  240. "CPU", "count", "real total", "virtual total", \
  241. "delay total", "delay average"); \
  242. printf(" %15llu%15llu%15llu%15llu%15.3fms\n", \
  243. (unsigned long long)(t)->cpu_count, \
  244. (unsigned long long)(t)->cpu_run_real_total, \
  245. (unsigned long long)(t)->cpu_run_virtual_total, \
  246. (unsigned long long)(t)->cpu_delay_total, \
  247. average_ms((double)(t)->cpu_delay_total, (t)->cpu_count)); \
  248. } \
  249. } while (0)
  250. #define PRINT_FILED_DELAY(name, version, t, count, total, max, min) \
  251. do { \
  252. if (version >= 16) { \
  253. printf("%-10s%15s%15s%15s%15s%15s\n", \
  254. name, "count", "delay total", "delay average", \
  255. "delay max", "delay min"); \
  256. printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms\n", \
  257. (unsigned long long)(t)->count, \
  258. (unsigned long long)(t)->total, \
  259. average_ms((double)(t)->total, (t)->count), \
  260. delay_ms((double)(t)->max), \
  261. delay_ms((double)(t)->min)); \
  262. } else { \
  263. printf("%-10s%15s%15s%15s\n", \
  264. name, "count", "delay total", "delay average"); \
  265. printf(" %15llu%15llu%15.3fms\n", \
  266. (unsigned long long)(t)->count, \
  267. (unsigned long long)(t)->total, \
  268. average_ms((double)(t)->total, (t)->count)); \
  269. } \
  270. } while (0)
  271. #define PRINT_FILED_DELAY_WITH_TS(name, version, t, count, total, max, min, max_ts) \
  272. do { \
  273. if (version >= 17) { \
  274. printf("%-10s%15s%15s%15s%15s%15s%25s\n", \
  275. name, "count", "delay total", "delay average", \
  276. "delay max", "delay min", "delay max timestamp"); \
  277. printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms%23s\n", \
  278. (unsigned long long)(t)->count, \
  279. (unsigned long long)(t)->total, \
  280. average_ms((double)(t)->total, (t)->count), \
  281. delay_ms((double)(t)->max), \
  282. delay_ms((double)(t)->min), \
  283. format_timespec(&(t)->max_ts)); \
  284. } else if (version >= 16) { \
  285. printf("%-10s%15s%15s%15s%15s%15s\n", \
  286. name, "count", "delay total", "delay average", \
  287. "delay max", "delay min"); \
  288. printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms\n", \
  289. (unsigned long long)(t)->count, \
  290. (unsigned long long)(t)->total, \
  291. average_ms((double)(t)->total, (t)->count), \
  292. delay_ms((double)(t)->max), \
  293. delay_ms((double)(t)->min)); \
  294. } else { \
  295. printf("%-10s%15s%15s%15s\n", \
  296. name, "count", "delay total", "delay average"); \
  297. printf(" %15llu%15llu%15.3fms\n", \
  298. (unsigned long long)(t)->count, \
  299. (unsigned long long)(t)->total, \
  300. average_ms((double)(t)->total, (t)->count)); \
  301. } \
  302. } while (0)
  303. static void print_delayacct(struct taskstats *t)
  304. {
  305. printf("\n\n");
  306. PRINT_CPU_DELAY(t->version, t);
  307. /* Use new macro with timestamp support for version >= 17 */
  308. if (t->version >= 17) {
  309. PRINT_FILED_DELAY_WITH_TS("IO", t->version, t,
  310. blkio_count, blkio_delay_total,
  311. blkio_delay_max, blkio_delay_min, blkio_delay_max_ts);
  312. PRINT_FILED_DELAY_WITH_TS("SWAP", t->version, t,
  313. swapin_count, swapin_delay_total,
  314. swapin_delay_max, swapin_delay_min, swapin_delay_max_ts);
  315. PRINT_FILED_DELAY_WITH_TS("RECLAIM", t->version, t,
  316. freepages_count, freepages_delay_total,
  317. freepages_delay_max, freepages_delay_min, freepages_delay_max_ts);
  318. PRINT_FILED_DELAY_WITH_TS("THRASHING", t->version, t,
  319. thrashing_count, thrashing_delay_total,
  320. thrashing_delay_max, thrashing_delay_min, thrashing_delay_max_ts);
  321. if (t->version >= 11) {
  322. PRINT_FILED_DELAY_WITH_TS("COMPACT", t->version, t,
  323. compact_count, compact_delay_total,
  324. compact_delay_max, compact_delay_min, compact_delay_max_ts);
  325. }
  326. if (t->version >= 13) {
  327. PRINT_FILED_DELAY_WITH_TS("WPCOPY", t->version, t,
  328. wpcopy_count, wpcopy_delay_total,
  329. wpcopy_delay_max, wpcopy_delay_min, wpcopy_delay_max_ts);
  330. }
  331. if (t->version >= 14) {
  332. PRINT_FILED_DELAY_WITH_TS("IRQ", t->version, t,
  333. irq_count, irq_delay_total,
  334. irq_delay_max, irq_delay_min, irq_delay_max_ts);
  335. }
  336. } else {
  337. /* Use original macro for older versions */
  338. PRINT_FILED_DELAY("IO", t->version, t,
  339. blkio_count, blkio_delay_total,
  340. blkio_delay_max, blkio_delay_min);
  341. PRINT_FILED_DELAY("SWAP", t->version, t,
  342. swapin_count, swapin_delay_total,
  343. swapin_delay_max, swapin_delay_min);
  344. PRINT_FILED_DELAY("RECLAIM", t->version, t,
  345. freepages_count, freepages_delay_total,
  346. freepages_delay_max, freepages_delay_min);
  347. PRINT_FILED_DELAY("THRASHING", t->version, t,
  348. thrashing_count, thrashing_delay_total,
  349. thrashing_delay_max, thrashing_delay_min);
  350. if (t->version >= 11) {
  351. PRINT_FILED_DELAY("COMPACT", t->version, t,
  352. compact_count, compact_delay_total,
  353. compact_delay_max, compact_delay_min);
  354. }
  355. if (t->version >= 13) {
  356. PRINT_FILED_DELAY("WPCOPY", t->version, t,
  357. wpcopy_count, wpcopy_delay_total,
  358. wpcopy_delay_max, wpcopy_delay_min);
  359. }
  360. if (t->version >= 14) {
  361. PRINT_FILED_DELAY("IRQ", t->version, t,
  362. irq_count, irq_delay_total,
  363. irq_delay_max, irq_delay_min);
  364. }
  365. }
  366. }
  367. static void task_context_switch_counts(struct taskstats *t)
  368. {
  369. printf("\n\nTask %15s%15s\n"
  370. " %15llu%15llu\n",
  371. "voluntary", "nonvoluntary",
  372. (unsigned long long)t->nvcsw, (unsigned long long)t->nivcsw);
  373. }
  374. static void print_cgroupstats(struct cgroupstats *c)
  375. {
  376. printf("sleeping %llu, blocked %llu, running %llu, stopped %llu, "
  377. "uninterruptible %llu\n", (unsigned long long)c->nr_sleeping,
  378. (unsigned long long)c->nr_io_wait,
  379. (unsigned long long)c->nr_running,
  380. (unsigned long long)c->nr_stopped,
  381. (unsigned long long)c->nr_uninterruptible);
  382. }
  383. static void print_ioacct(struct taskstats *t)
  384. {
  385. printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
  386. t->ac_comm,
  387. (unsigned long long)t->read_bytes,
  388. (unsigned long long)t->write_bytes,
  389. (unsigned long long)t->cancelled_write_bytes);
  390. }
  391. int main(int argc, char *argv[])
  392. {
  393. int c, rc, rep_len, aggr_len, len2;
  394. int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
  395. __u16 id;
  396. __u32 mypid;
  397. struct nlattr *na;
  398. int nl_sd = -1;
  399. int len = 0;
  400. pid_t tid = 0;
  401. pid_t rtid = 0;
  402. int fd = 0;
  403. int write_file = 0;
  404. int maskset = 0;
  405. char *logfile = NULL;
  406. int loop = 0;
  407. int containerset = 0;
  408. char *containerpath = NULL;
  409. int cfd = 0;
  410. int forking = 0;
  411. sigset_t sigset;
  412. struct msgtemplate msg;
  413. while (!forking) {
  414. c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
  415. if (c < 0)
  416. break;
  417. switch (c) {
  418. case 'd':
  419. printf("print delayacct stats ON\n");
  420. print_delays = 1;
  421. break;
  422. case 'i':
  423. printf("printing IO accounting\n");
  424. print_io_accounting = 1;
  425. break;
  426. case 'q':
  427. printf("printing task/process context switch rates\n");
  428. print_task_context_switch_counts = 1;
  429. break;
  430. case 'C':
  431. containerset = 1;
  432. containerpath = optarg;
  433. break;
  434. case 'w':
  435. logfile = strdup(optarg);
  436. printf("write to file %s\n", logfile);
  437. write_file = 1;
  438. break;
  439. case 'r':
  440. rcvbufsz = atoi(optarg);
  441. printf("receive buf size %d\n", rcvbufsz);
  442. if (rcvbufsz < 0)
  443. err(1, "Invalid rcv buf size\n");
  444. break;
  445. case 'm':
  446. strncpy(cpumask, optarg, sizeof(cpumask));
  447. cpumask[sizeof(cpumask) - 1] = '\0';
  448. maskset = 1;
  449. printf("cpumask %s maskset %d\n", cpumask, maskset);
  450. break;
  451. case 't':
  452. tid = atoi(optarg);
  453. if (!tid)
  454. err(1, "Invalid tgid\n");
  455. cmd_type = TASKSTATS_CMD_ATTR_TGID;
  456. break;
  457. case 'p':
  458. tid = atoi(optarg);
  459. if (!tid)
  460. err(1, "Invalid pid\n");
  461. cmd_type = TASKSTATS_CMD_ATTR_PID;
  462. break;
  463. case 'c':
  464. /* Block SIGCHLD for sigwait() later */
  465. if (sigemptyset(&sigset) == -1)
  466. err(1, "Failed to empty sigset");
  467. if (sigaddset(&sigset, SIGCHLD))
  468. err(1, "Failed to set sigchld in sigset");
  469. sigprocmask(SIG_BLOCK, &sigset, NULL);
  470. /* fork/exec a child */
  471. tid = fork();
  472. if (tid < 0)
  473. err(1, "Fork failed\n");
  474. if (tid == 0)
  475. if (execvp(argv[optind - 1],
  476. &argv[optind - 1]) < 0)
  477. exit(-1);
  478. /* Set the command type and avoid further processing */
  479. cmd_type = TASKSTATS_CMD_ATTR_PID;
  480. forking = 1;
  481. break;
  482. case 'v':
  483. printf("debug on\n");
  484. dbg = 1;
  485. break;
  486. case 'l':
  487. printf("listen forever\n");
  488. loop = 1;
  489. break;
  490. default:
  491. usage();
  492. exit(-1);
  493. }
  494. }
  495. if (write_file) {
  496. fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC,
  497. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  498. if (fd == -1) {
  499. perror("Cannot open output file\n");
  500. exit(1);
  501. }
  502. }
  503. nl_sd = create_nl_socket(NETLINK_GENERIC);
  504. if (nl_sd < 0)
  505. err(1, "error creating Netlink socket\n");
  506. mypid = getpid();
  507. id = get_family_id(nl_sd);
  508. if (!id) {
  509. fprintf(stderr, "Error getting family id, errno %d\n", errno);
  510. goto err;
  511. }
  512. PRINTF("family id %d\n", id);
  513. if (maskset) {
  514. rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
  515. TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
  516. &cpumask, strlen(cpumask) + 1);
  517. PRINTF("Sent register cpumask, retval %d\n", rc);
  518. if (rc < 0) {
  519. fprintf(stderr, "error sending register cpumask\n");
  520. goto err;
  521. }
  522. }
  523. if (tid && containerset) {
  524. fprintf(stderr, "Select either -t or -C, not both\n");
  525. goto err;
  526. }
  527. /*
  528. * If we forked a child, wait for it to exit. Cannot use waitpid()
  529. * as all the delicious data would be reaped as part of the wait
  530. */
  531. if (tid && forking) {
  532. int sig_received;
  533. sigwait(&sigset, &sig_received);
  534. }
  535. if (tid) {
  536. rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
  537. cmd_type, &tid, sizeof(__u32));
  538. PRINTF("Sent pid/tgid, retval %d\n", rc);
  539. if (rc < 0) {
  540. fprintf(stderr, "error sending tid/tgid cmd\n");
  541. goto done;
  542. }
  543. }
  544. if (containerset) {
  545. cfd = open(containerpath, O_RDONLY);
  546. if (cfd < 0) {
  547. perror("error opening container file");
  548. goto err;
  549. }
  550. rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
  551. CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32));
  552. if (rc < 0) {
  553. perror("error sending cgroupstats command");
  554. goto err;
  555. }
  556. }
  557. if (!maskset && !tid && !containerset) {
  558. usage();
  559. goto err;
  560. }
  561. do {
  562. rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
  563. PRINTF("received %d bytes\n", rep_len);
  564. if (rep_len < 0) {
  565. fprintf(stderr, "nonfatal reply error: errno %d\n",
  566. errno);
  567. continue;
  568. }
  569. if (msg.n.nlmsg_type == NLMSG_ERROR ||
  570. !NLMSG_OK((&msg.n), rep_len)) {
  571. struct nlmsgerr *err = NLMSG_DATA(&msg);
  572. fprintf(stderr, "fatal reply error, errno %d\n",
  573. err->error);
  574. goto done;
  575. }
  576. PRINTF("nlmsghdr size=%zu, nlmsg_len=%d, rep_len=%d\n",
  577. sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);
  578. rep_len = GENLMSG_PAYLOAD(&msg.n);
  579. na = (struct nlattr *) GENLMSG_DATA(&msg);
  580. len = 0;
  581. while (len < rep_len) {
  582. len += NLA_ALIGN(na->nla_len);
  583. switch (na->nla_type) {
  584. case TASKSTATS_TYPE_AGGR_TGID:
  585. /* Fall through */
  586. case TASKSTATS_TYPE_AGGR_PID:
  587. aggr_len = NLA_PAYLOAD(na->nla_len);
  588. len2 = 0;
  589. /* For nested attributes, na follows */
  590. na = (struct nlattr *) NLA_DATA(na);
  591. while (len2 < aggr_len) {
  592. switch (na->nla_type) {
  593. case TASKSTATS_TYPE_PID:
  594. rtid = *(int *) NLA_DATA(na);
  595. if (print_delays)
  596. printf("PID\t%d\n", rtid);
  597. break;
  598. case TASKSTATS_TYPE_TGID:
  599. rtid = *(int *) NLA_DATA(na);
  600. if (print_delays)
  601. printf("TGID\t%d\n", rtid);
  602. break;
  603. case TASKSTATS_TYPE_STATS:
  604. if (print_delays)
  605. print_delayacct((struct taskstats *) NLA_DATA(na));
  606. if (print_io_accounting)
  607. print_ioacct((struct taskstats *) NLA_DATA(na));
  608. if (print_task_context_switch_counts)
  609. task_context_switch_counts((struct taskstats *) NLA_DATA(na));
  610. if (fd) {
  611. if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
  612. err(1,"write error\n");
  613. }
  614. }
  615. if (!loop)
  616. goto done;
  617. break;
  618. case TASKSTATS_TYPE_NULL:
  619. break;
  620. default:
  621. fprintf(stderr, "Unknown nested"
  622. " nla_type %d\n",
  623. na->nla_type);
  624. break;
  625. }
  626. len2 += NLA_ALIGN(na->nla_len);
  627. na = (struct nlattr *)((char *)na +
  628. NLA_ALIGN(na->nla_len));
  629. }
  630. break;
  631. case CGROUPSTATS_TYPE_CGROUP_STATS:
  632. print_cgroupstats(NLA_DATA(na));
  633. break;
  634. default:
  635. fprintf(stderr, "Unknown nla_type %d\n",
  636. na->nla_type);
  637. case TASKSTATS_TYPE_NULL:
  638. break;
  639. }
  640. na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
  641. }
  642. } while (loop);
  643. done:
  644. if (maskset) {
  645. rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
  646. TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
  647. &cpumask, strlen(cpumask) + 1);
  648. printf("Sent deregister mask, retval %d\n", rc);
  649. if (rc < 0)
  650. err(rc, "error sending deregister cpumask\n");
  651. }
  652. err:
  653. close(nl_sd);
  654. if (fd)
  655. close(fd);
  656. if (cfd)
  657. close(cfd);
  658. return 0;
  659. }