• 读取proc信息的可扩展实现


    需求

    1. 将内存、线程数等信息注册到zk上进行监控

    2. 统计信息,为下一步做负载均衡做准备。

    实现

    本文只解决问题1。

    从网上查询了下,这些信息可以从proc文件系统中获取,如果不知道proc的,可以Google下。

    网上有读取proc信息的lib——libproc,即 procps , 据说htop等实现就是基于它的。

    我下载下来了,include和lib都生成了,好不容易找到一篇教程,结果在

    stackoverflow上,见有人说有内存泄露,需要如下方法做。

    int main(int argc, char** argv)
    {
     // fillarg  used for cmdline
     // fillstat used for cmd
     PROCTAB* proc = openproc(PROC_FILLARG | PROC_FILLSTAT);
    
     while (proc_t* proc_info = readproc(proc, NULL)) {
        // do something
        freeproc(proc_info)
     }
     closeproc(proc);
    }


    于是看proc_t的定义,充满了上世纪的风格,似乎迷失在信息各种信息中了,于是无奈放弃了,直接手撸吧。代码稍后附上,如下是几个关键的技术点

    1. 即然shell 命名可以获取proc信息,在C中,我们可以通过popen建立管道,获取shell命令的输出。

    2. 获取进程号,可以通过 getpid()

    3. sizeof(xx)/sizeof(xx[0]) 可以获取数组的大小。

    4. 设计了ZeroHelper 结构,方便了扩展

    5. offsetof 宏用于获取元素的偏移

    6. 函数指针的应用恰到好处。

    #include <time.h>
    #include <stddef.h>
    #include <string.h>
    #include <stdint.h>
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include<unistd.h>
    struct StatInfo
    {
        time_t   start_time;
        uint32_t duration_sec;
        uint32_t conn_cnt;
        uint32_t pmem_mb;   // peak virtual memory
        uint32_t vmem_mb;   // virtual memory
        uint32_t rmem_mb;   // real memory
        uint32_t thread_cnt;// 线程数
        uint32_t cpu_usage; // cpu
    };
    typedef int (*convert_fn)(const char* str, void* value_ptr);
    struct ZeroHelper {
        const char* key;
        uint32_t key_len;
        uint32_t value_offset;
        convert_fn fn;
    };
    
    int proc_stat_mem_convert(const char* str, void* value_ptr)
    {
        uint32_t* value = (uint32_t*)value_ptr;
        while (*str && isspace(*str))
          ++str;
        *value = atoi(str);
        return 0;
    }
    static const ZeroHelper proc_mem_convert_array[] = {
        {"VmPeak:", sizeof("VmPeak:") - 1, offsetof(StatInfo, pmem_mb), proc_stat_mem_convert},
        {"VmSize:", sizeof("VmSize:") - 1, offsetof(StatInfo, vmem_mb), proc_stat_mem_convert},
        {"VmRSS:", sizeof("VmRSS:") - 1, offsetof(StatInfo, rmem_mb),   proc_stat_mem_convert},
        {"Threads:", sizeof("Threads:") - 1, offsetof(StatInfo, thread_cnt), proc_stat_mem_convert},
    };
    int fresh_memstat_info(pid_t pid, StatInfo* info)
    {
        char proc_cmd [1024];
        snprintf(proc_cmd, sizeof(proc_cmd), "cat /proc/%d/status", pid);
        FILE* fp = popen(proc_cmd, "r");
        char proc_line[1024];
        const ZeroHelper* helper = &(proc_mem_convert_array[0]);
        const int kHelperLen = sizeof(proc_mem_convert_array)/sizeof(proc_mem_convert_array[0]);
        int j = 0;
        while (fgets(proc_line, sizeof(proc_line), fp) != NULL)
        {
            if (j >= kHelperLen)
            {
                break;
            }
            // 忽略 key 头部
            if (strncmp(proc_line,
                        helper->key, helper->key_len) == 0)
            {
                helper->fn(proc_line + helper->key_len,
                           (char*)info + helper->value_offset);
                ++helper;
                ++j;
            }
        }
        pclose(fp);
        return 0;
    }
    int main()
    {
        StatInfo info;
        pid_t pid = getpid();
        fresh_memstat_info(pid, &info);
        printf("%d	%ukB	%ukB	%ukB	%u
    ",
               pid,
               info.pmem_mb, info.vmem_mb,
               info.rmem_mb, info.thread_cnt);
        sleep(1000);
        return 0;
    }
    View Code
  • 相关阅读:
    P2016 战略游戏(没有上司的舞会变式)
    P2014 [CTSC1997]选课(树上背包)
    P2015 二叉苹果树(树上背包)
    P1122 最大子树和(简单树形DP)
    P1505 [国家集训队]旅游(树链剖分)
    linux下的几个网络流量监控工具使用
    大数据场景下数据异构之 Mysql实时写入HBase(借助canal kafka SparkStreaming)
    基于Spark Streaming + Canal + Kafka对Mysql增量数据实时进行监测分析
    sqoop安装与使用
    MongoDB各系统上安装
  • 原文地址:https://www.cnblogs.com/westfly/p/4230956.html
Copyright © 2020-2023  润新知