// SPDX-License-Identifier: GPL-2.0 /* procacct.c * * Demonstrator of fetching resource data on task exit, as a way * to accumulate accurate program resource usage statistics, without * prior identification of the programs. For that, the fields for * device and inode of the program executable binary file are also * extracted in addition to the command string. * * The TGID together with the PID and the AGROUP flag allow * identification of threads in a process and single-threaded processes. * The ac_tgetime field gives proper whole-process walltime. * * Written (changed) by Thomas Orgis, University of Hamburg in 2022 * * This is a cheap derivation (inheriting the style) of getdelays.c: * * Utility to get per-pid and per-tgid delay accounting statistics * Also illustrates usage of the taskstats interface * * Copyright (C) Shailabh Nagar, IBM Corp. 2005 * Copyright (C) Balbir Singh, IBM Corp. 2006 * Copyright (c) Jay Lan, SGI. 2006
*/
/* * Generic macros for dealing with netlink sockets. Might be duplicated * elsewhere. It is recommended that commercial grade applications use * libnl or libnetlink and use the interfaces provided by the library
*/ #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN) #define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN)) #define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
#define err(code, fmt, arg...) \ do { \
fprintf(stderr, fmt, ##arg); \ exit(code); \
} while (0)
int rcvbufsz; char name[100]; int dbg; int print_delays; int print_io_accounting; int print_task_context_switch_counts;
/* Maximum size of response requested or message sent */ #define MAX_MSG_SIZE 1024 /* Maximum number of cpus expected to be specified in a cpumask */ #define MAX_CPUS 32
if (rcvbufsz) if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
&rcvbufsz, sizeof(rcvbufsz)) < 0) {
fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
rcvbufsz); goto error;
}
/* * Probe the controller in genetlink to find the family id * for the TASKSTATS family
*/ staticint get_family_id(int sd)
{ struct { struct nlmsghdr n; struct genlmsghdr g; char buf[256];
} ans;
na = (struct nlattr *) GENLMSG_DATA(&ans);
na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len)); if (na->nla_type == CTRL_ATTR_FAMILY_ID)
id = *(__u16 *) NLA_DATA(na);
return id;
}
#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
staticvoid print_procacct(struct taskstats *t)
{ /* First letter: T is a mere thread, G the last in a group, U unknown. */
printf( "%c pid=%lu tgid=%lu uid=%lu wall=%llu gwall=%llu cpu=%llu vmpeak=%llu rsspeak=%llu dev=%lu:%lu inode=%llu comm=%s\n"
, t->version >= 12 ? (t->ac_flag & AGROUP ? 'P' : 'T') : '?'
, (unsignedlong)t->ac_pid
, (unsignedlong)(t->version >= 12 ? t->ac_tgid : 0)
, (unsignedlong)t->ac_uid
, (unsignedlonglong)t->ac_etime
, (unsignedlonglong)(t->version >= 12 ? t->ac_tgetime : 0)
, (unsignedlonglong)(t->ac_utime+t->ac_stime)
, (unsignedlonglong)t->hiwater_vm
, (unsignedlonglong)t->hiwater_rss
, (unsignedlong)(t->version >= 12 ? MAJOR(t->ac_exe_dev) : 0)
, (unsignedlong)(t->version >= 12 ? MINOR(t->ac_exe_dev) : 0)
, (unsignedlonglong)(t->version >= 12 ? t->ac_exe_inode : 0)
, t->ac_comm
);
}
void handle_aggr(int mother, struct nlattr *na, int fd)
{ int aggr_len = NLA_PAYLOAD(na->nla_len); int len2 = 0;
pid_t rtid = 0;
na = (struct nlattr *) NLA_DATA(na); while (len2 < aggr_len) { switch (na->nla_type) { case TASKSTATS_TYPE_PID:
rtid = *(int *) NLA_DATA(na);
PRINTF("PID\t%d\n", rtid); break; case TASKSTATS_TYPE_TGID:
rtid = *(int *) NLA_DATA(na);
PRINTF("TGID\t%d\n", rtid); break; case TASKSTATS_TYPE_STATS: if (mother == TASKSTATS_TYPE_AGGR_PID)
print_procacct((struct taskstats *) NLA_DATA(na)); if (fd) { if (write(fd, NLA_DATA(na), na->nla_len) < 0)
err(1, "write error\n");
} break; case TASKSTATS_TYPE_NULL: break; default:
fprintf(stderr, "Unknown nested nla_type %d\n",
na->nla_type); break;
}
len2 += NLA_ALIGN(na->nla_len);
na = (struct nlattr *)((char *)na +
NLA_ALIGN(na->nla_len));
}
}
int main(int argc, char *argv[])
{ int c, rc, rep_len;
__u16 id;
__u32 mypid;
struct nlattr *na; int nl_sd = -1; int len = 0;
int fd = 0; int write_file = 0; int maskset = 0; char *logfile = NULL; int cfd = 0;
struct msgtemplate msg;
while (1) {
c = getopt(argc, argv, "m:vr:w:"); if (c < 0) break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.