使用libnl-3发送Netlink Taskstats消息 [英] Sending Netlink Taskstats message using libnl-3

查看:278
本文介绍了使用libnl-3发送Netlink Taskstats消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用netlink套接字和taskstats读取单个线程的Linux内核统计信息.

I want to read out linux kernel statistics of a single thread using netlink socket and taskstats.

我可以使用python包装器来使taskstats正常工作( https://github.com/facebook/gnlpy),但我想执行C语言实现.

I could get taskstats to work using a python wrapper (https://github.com/facebook/gnlpy) but I want to do a C implementation.

设置套接字后,消息参数并发送,接收

After setting up the socket, the message parameters and sending, the receiving

nl_recvmsgs_default(sock)

根据我如何创建要发送的消息,总是返回错误代码-7(无效的输入数据或参数")或-12(找不到对象").

always returns an error code -7 ("Invalid input data or parameter") or -12 ("Object not found") depending on how I create the message to send.

我在nl_recvmsgs_default(sock)之前检查了所有方法调用,但是没有收到任何错误.我想我在设置消息或套接字时缺少一部分,但是不知道它是哪一部分.

I checked all method invocations before nl_recvmsgs_default(sock) but dont get any error back. I guess I am missing a part in setting up the message or socket, but dont know what part it is.

#include <stdlib.h>
#include <unistd.h>
#include <linux/taskstats.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>

int callback_message(struct nl_msg *, void *);

int main(int argc, char ** argv) {
    struct nl_sock * sock;
    struct nl_msg * msg;
    int family;

    sock = nl_socket_alloc();

    // Connect to generic netlink socket on kernel side
    genl_connect(sock);

    // get the id for the TASKSTATS generic family
    family = genl_ctrl_resolve(sock, "TASKSTATS");

    // Allocate a new netlink message and inherit netlink message header. 
    msg = nlmsg_alloc();

    genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION))

    //error code: -7 NLE_INVAL "Invalid input data or parameter",
    nla_put_string(msg, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, "0");

    //error code: -12 NLE_OBJ_NOTFOUND "Obj not found"
    //nla_put_string(msg, TASKSTATS_CMD_ATTR_PID, "583");

    nl_send_auto(sock, msg);

    nlmsg_free(msg);

    // specify a callback for inbound messages
    nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, callback_message, NULL);

    // gives error code -7 or -12 depending on the two nla_put_string alternatives above
    printf("recv code (0 = success): %d", nl_recvmsgs_default(sock));
}

int callback_message(struct nl_msg * nlmsg, void * arg) {

    struct nlmsghdr * nlhdr;
    struct nlattr * nlattrs[TASKSTATS_TYPE_MAX + 1];
    struct nlattr * nlattr;
    struct taskstats * stats;
    int rem;

    nlhdr = nlmsg_hdr(nlmsg);
    int answer;

    if ((answer = genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL))
            < 0) {
        printf("error parsing msg\n");
    }

    if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_TGID]) || (nlattr =
            nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr =
            nlattrs[TASKSTATS_TYPE_NULL])) {
        stats = nla_data(nla_next(nla_data(nlattr), &rem));

        printf("---\n");
        printf("pid: %u\n", stats->ac_pid);
        printf("command: %s\n", stats->ac_comm);
        printf("status: %u\n", stats->ac_exitcode);
        printf("time:\n");
        printf("  start: %u\n", stats->ac_btime);
        printf("  elapsed: %llu\n", stats->ac_etime);
        printf("  user: %llu\n", stats->ac_utime);
        printf("  system: %llu\n", stats->ac_stime);
        printf("memory:\n");
        printf("  bytetime:\n");
        printf("    rss: %llu\n", stats->coremem);
        printf("    vsz: %llu\n", stats->virtmem);
        printf("  peak:\n");
        printf("    rss: %llu\n", stats->hiwater_rss);
        printf("    vsz: %llu\n", stats->hiwater_vm);
        printf("io:\n");
        printf("  bytes:\n");
        printf("    read: %llu\n", stats->read_char);
        printf("    write: %llu\n", stats->write_char);
        printf("  syscalls:\n");
        printf("    read: %llu\n", stats->read_syscalls);
        printf("    write: %llu\n", stats->write_syscalls);
    } else {
        printf("unknown attribute format received\n");
    }
    return 0;
}

推荐答案

您提供的代码对我来说很好用,除了第26行中的语法错误.请确保您以root用户身份运行程序.请注意,您正在创建用于退出任务的侦听器,但正在读取一条消息,据我所知,这是一个ACK.每当任务在CPU 0上退出时,在while(1)循环中从套接字读取都会显示已解析的消息.

The code you provided works fine for me, except for a syntax error in line 26. Make sure you are running the program as root. Note that you are creating a listener for exiting tasks, yet reading a single message, which is, as far as I understand, an ACK. Reading from the socket in a while(1) loop shows parsed messages whenever a task exits on CPU 0.

如果要获取单个PID的统计信息,则应改用nla_put_u32:

In the case where you are getting stats for a single PID, you should use nla_put_u32 instead:

nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 583);

其中583是现有的进程ID.

where 583 is an existing process id.

这篇关于使用libnl-3发送Netlink Taskstats消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆