《ZLToolKit源码学习笔记》(8)线程模块之线程负载计算器

 系列文章目录

《ZLToolKit源码学习笔记》(1)VS2019源码编译

《ZLToolKit源码学习笔记》(2)工具模块之日志功能分析

《ZLToolKit源码学习笔记》(3)工具模块之终端命令解析

《ZLToolKit源码学习笔记》(4)工具模块之消息广播器

《ZLToolKit源码学习笔记》(5)工具模块之资源池

《ZLToolKit源码学习笔记》(6)线程模块之整体框架概述

《ZLToolKit源码学习笔记》(7)线程模块之线程池组件:任务队列与线程组

《ZLToolKit源码学习笔记》(8)线程模块之线程负载计算器(本文)

《ZLToolKit源码学习笔记》(9)线程模块之任务执行器

《ZLToolKit源码学习笔记》(10)线程模块之线程池

《ZLToolKit源码学习笔记》(11)线程模块之工作线程池WorkThreadPool

《ZLToolKit源码学习笔记》(12)事件轮询模块之整体框架概述

《ZLToolKit源码学习笔记》(13)事件轮询模块之管道的简单封装

《ZLToolKit源码学习笔记》(14)事件轮询模块之定时器

《ZLToolKit源码学习笔记》(15)事件轮询模块之事件轮询器EventPoller

《ZLToolKit源码学习笔记》(16)网络模块之整体框架概述

《ZLToolKit源码学习笔记》(17)网络模块之基础接口封装类SockUtil

《ZLToolKit源码学习笔记》(18)网络模块之Buffer缓存

《ZLToolKit源码学习笔记》(19)网络模块之套接字封装

《ZLToolKit源码学习笔记》(20)网络模块之TcpServer

《ZLToolKit源码学习笔记》(21)网络模块之TcpClient与Session

《ZLToolKit源码学习笔记》(22)网络模块之UdpServer


前言

线程负载计数器主要是统计一个线程处于休眠期与活跃期时间的占比。


目录

  系列文章目录

前言

一、ThreadLoadCounter

1.1、epoll网络模型的CPU负载统计

1.2、构造函数

1.3、startSleep

1.4、sleepWakeUp

1.5、load


一、ThreadLoadCounter

一个线程,要么处于活跃状态,在执行任务,此时占用CPU,要么处于休眠状态,等待任务的到来,此时不占用CPU,ThreadLoadCounter就是用于统计某一段时间内,线程处于活跃状态所占的比率。也可以说是该线程对CPU的使用率。

比如,上图中,假设我们统计某段时间内,当前线程的CPU使用率,其中线程处于sleep状态的总时间为t1,处于Active状态的总时间为t2,那么CPU使用率为t1/(t1+t2)。

该类提供了以下三个接口:

1.1、epoll网络模型的CPU负载统计

在看该类提供的接口之前,我们先分析下常见的epoll网络模型。使用epoll的伪代码大致如下,线程阻塞在epoll_wait上等待事件到来,当有事件触发时,epoll_wait返回,线程开始处理事件。

要统计该线程的CPU使用率,应该是事件处理占用的时间 / (事件处理占用的时间 + 阻塞在epoll_wait上的时间),即activeTime / (activeTime + sleepTime)

while循环每执行一次,对应的我们就统计了一次当前CPU负载,仅一次的数据是没有用的,为了能够让统计的数据更准确,我们需要统计多次,以一段时间范围内的n次数据来计算负载率。比如,统计距当前最近的5分钟内,最后的1000次采集的数据,这1000次数据中,totalActiveTime = activeTime1 + activeTime2 + ... + activeTime1000,totalSleepTime = sleepTime1 + sleepTime2 + ... + sleepTime1000,最终的CPU使用率:totalActiveTime / (totalActiveTime+ totalSleepTime).

void runLoop(){
    //t1 = t2 = curTime();
    while(true){
        //t1 = curTime();
        //activeTime = t1 - t2;
        epoll_wait();
        //t2 = curTime();
        //sleepTime = t2 - t1;
        /*事件处理*/
        ....
    }
}

 使用ThreadLoadCounter统计:

void runLoop(){
    while(true){
        startSleep();
        epoll_wait();
        sleepWakeUp();
        /*事件处理*/
        ....
    }
}

1.2、构造函数

ThreadLoadCounter::ThreadLoadCounter(uint64_t max_size,uint64_t max_usec){
    _last_sleep_time = _last_wake_time = getCurrentMicrosecond();
    _max_size = max_size;
    _max_usec = max_usec;
}

指定了统计的样本数量以及时间范围。样本数量是统计休眠时间的次数与活跃时间的次数之和。比如max_size = 1000,那就是500个休眠时间数据+500个活跃时间数据。

1.3、startSleep

void ThreadLoadCounter::startSleep() {
    lock_guard <mutex> lck(_mtx);
    _sleeping = true;
    auto current_time = getCurrentMicrosecond();
    auto run_time = current_time - _last_wake_time;
    _last_sleep_time = current_time;
    _time_list.emplace_back(run_time, false);
    if (_time_list.size() > _max_size) {
        _time_list.pop_front();
    }
}

在阻塞的代码之前调用该接口,计算并记录本轮统计中,线程处于活跃状态的时间,即从线程被唤醒,执行完任务,到再次进入休眠状态的时间。

1.4、sleepWakeUp

void ThreadLoadCounter::sleepWakeUp() {
    lock_guard <mutex> lck(_mtx);
    _sleeping = false;
    auto current_time = getCurrentMicrosecond();
    auto sleep_time = current_time - _last_sleep_time;
    _last_wake_time = current_time;
    _time_list.emplace_back(sleep_time, true);
    if (_time_list.size() > _max_size) {
        _time_list.pop_front();
    }
}

在阻塞的代码之后调用该接口,计算并记录本轮统计中,线程处于休眠状态的时间,即从线程开始休眠,到被唤醒的时间。

1.5、load

int ThreadLoadCounter::load() {
    lock_guard<mutex> lck(_mtx);
    uint64_t totalSleepTime = 0;
    uint64_t totalRunTime = 0;
    _time_list.for_each([&](const TimeRecord &rcd) {
        if (rcd._sleep) {
            totalSleepTime += rcd._time;
        } else {
            totalRunTime += rcd._time;
        }
    });

    if (_sleeping) {
        totalSleepTime += (getCurrentMicrosecond() - _last_sleep_time);
    } else {
        totalRunTime += (getCurrentMicrosecond() - _last_wake_time);
    }

    uint64_t totalTime = totalRunTime + totalSleepTime;
    while ((_time_list.size() != 0) && (totalTime > _max_usec || _time_list.size() > _max_size)) {
        TimeRecord &rcd = _time_list.front();
        if (rcd._sleep) {
            totalSleepTime -= rcd._time;
        } else {
            totalRunTime -= rcd._time;
        }
        totalTime -= rcd._time;
        _time_list.pop_front();
    }
    if (totalTime == 0) {
        return 0;
    }
    return (int) (totalRunTime * 100 / totalTime);
}

需要获取当前线程最近max_usec时间范围内的负载率时,调用该接口。

对统计的所有样本数据,计算总时间(运行时间总和+休眠时间总和),总时间和样本数量应该在指定的范围内,如果超过则删除最早的记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦时小

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值