💡知行合一.🐬|

BaldButStrong

园龄:2年11个月粉丝:2关注:0

2025-02-06 16:55阅读: 13评论: 0推荐: 0

linux 利用cgroups 手搓简易资源控制库

上次写了C语言实现的log模块,本次使用c++结合log,利用Linux下cgroup资源控制手写一个资源控制库,首先了解cgroup,方便理解后面代码

log参考链接

1. 目录结构

image

2. 资源控制模块代码

1) setSource.cpp
#include "setSource.h"
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <cerrno>
#include <string>
extern "C" {
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include "log.h"
}
/* 各级别乘的系数 */
#define HIGH (float)-1
#define MEDIUM (float)0.5
#define LOW (float)0.2
/* 各个子系统的路径,方便后续创建文件夹等操作 */
#define CGROUP_CPU_PATH "/sys/fs/cgroup/cpu/"
#define CGROUP_MEM_PATH "/sys/fs/cgroup/memory/"
#define CGROUP_BIO_PATH "/sys/fs/cgroup/blkio/"
#define CGROUP_NET_PATH "/sys/fs/cgroup/net_cls/"
/* 各个子系统默认值文件的路径 */
#define DEFAULT_CPU_CONF "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
#define DEFAULT_MEM_CONF "/sys/fs/cgroup/memory/memory.limit_in_bytes"
#define DEFAULT_BIOR_CONF ""
#define DEFAULT_BIOW_CONF ""
#define DEFAULT_NET_CONF ""
/* 资源限制时需要修改的配置文件名 */
#define PIDCONF "/cgroup.procs"
#define CPUCONF "/cpu.cfs_quota_us"
#define MEMCONF "/memory.limit_in_bytes"
#define BIORCONF ""
#define BIOWCONF ""
#define NETCONF ""
/*****************************************
*
* 读取配置文件的默认值
*
****************************************/
int setSource::readConfigFileToint(string config_name)
{
string buf;
int res = -1;
ifstream ifs(config_name);
if (ifs.is_open())
{
getline(ifs, buf);
if (!buf.empty())
{
res = stoi(buf);
}
ifs.close();
}
else
{
LogWrite(ERROR, "%s%s%s", "readConfigFileToint: read value from ",config_name.c_str()," error");
}
return res;
}
/*****************************************
*
* 将修改值写入配置文件
*
****************************************/
int setSource::writeConfigFile(string config_name, int set_value)
{
int res = 0;
ofstream ofs(config_name);
if (ofs.is_open())
{
ofs << set_value;
ofs.close();
}
else
{
res = -1;
LogWrite(ERROR, "%s%d%s%s%s","writeConfigFile: Set value ", set_value, " to ", config_name.c_str()," error");
}
return res;
}
/*****************************************
*
* 根据级别获取对应的系数
*
****************************************/
float setSource::sourceLevel(int level_value)
{
switch (level_value)
{
case 3:
return HIGH;
break;
case 2:
return MEDIUM;
break;
case 1:
return LOW;
break;
default:
return HIGH;
break;
}
}
/*****************************************
*
* 资源限制操作接口
*
****************************************/
void setSource::setSourceValue(string dir_path, string pName, string confName, string defauleName, int pid)
{
if (dir_path.empty() || pName.empty() || confName.empty() || defauleName.empty())
{
LogWrite(ERROR, "%s", "string is NULL");
}
string dir_name = dir_path + pName;
string pid_conf = dir_name + PIDCONF;
string change_conf = dir_name + confName;
int value = (int)(readConfigFileToint(defauleName) * sourceLevel(source_level));
if (access(dir_name.c_str(), F_OK) == -1)
{
if (mkdir(dir_name.c_str(), 0777) < 0 && errno != EEXIST)
{
LogWrite(ERROR,"%s%s%s","setSourceValue:mkdir ",dir_name.c_str()," error");
return;
}
}
if (writeConfigFile(pid_conf, pid) != 0 || writeConfigFile(change_conf, value) != 0)
{
LogWrite(ERROR,"%s%s%s%s%s","setSourceValue: set value to ", confName.c_str(), " or ", pid_conf.c_str()," error");
}
}
/*****************************************
*
* 外部调用接口入口,处理设置各类资源限制
*
****************************************/
void setSource::dealWtithSetSource(string name, int pid, int mode)
{
LogWrite(INFO, "%s", "dealWtithSetSource begin");
if (source_level == 3)
{
LogWrite(INFO, "%s", " no limited");
return;
}
if (mode & T_CPU)
{
LogWrite(DEBUG, "%s", "set cpu");
setSourceValue(CGROUP_CPU_PATH, name, CPUCONF, DEFAULT_CPU_CONF, pid);
}
if (mode & T_MEM)
{
LogWrite(DEBUG, "%s", "set memory");
setSourceValue(CGROUP_MEM_PATH, name, MEMCONF, DEFAULT_MEM_CONF, pid);
}
if (mode & T_BIOREAD)
{
LogWrite(DEBUG, "%s", "set bio read");
setSourceValue(CGROUP_BIO_PATH, name, BIORCONF, DEFAULT_BIOR_CONF, pid);
}
if (mode & T_BIOWRITE)
{
LogWrite(DEBUG, "%s", "set bio write");
setSourceValue(CGROUP_BIO_PATH, name, BIOWCONF, DEFAULT_BIOW_CONF, pid);
}
if (mode & T_NET)
{
LogWrite(DEBUG, "%s", "set net");
setSourceValue(CGROUP_NET_PATH, name, NETCONF, DEFAULT_NET_CONF, pid);
}
LogWrite(INFO, "%s", "dealWtithSetSource end");
}
/*****************************************
*
* 清理资源设置的文件夹
*
****************************************/
void setSource::clearSource(string name)
{
LogWrite(INFO,"%s", "clearSource begin");
rmdir(name.c_str());
LogWrite(INFO,"%s", "clearSource end");
}
/*****************************************
*
* 构造与析构
*
****************************************/
setSource::setSource(int mod)
{
source_level = mod;
}
setSource::~setSource()
{
}

2) setSource.h

#ifndef _SET_SOURCE_H_
#define _SET_SOURCE_H_
#include <string>
#include <iostream>
using namespace std;
#define T_CPU 0x01
#define T_MEM 0x02
#define T_BIOREAD 0x04
#define T_BIOWRITE 0x08
#define T_NET 0x10
#define T_ALL (T_CPU | T_MEM | T_BIOREAD | T_BIOWRITE | T_NET)
class setSource
{
public:
setSource(int mod);
~setSource();
void dealWtithSetSource(string name, int pid, int mode);
void clearSource(string name);
private:
float sourceLevel(int level_value);
void setSourceValue(string dir_path, string pName, string confName, string defauleName, int pid);
int readConfigFileToint(string config_name);
int writeConfigFile(string config_name, int set_value);
int source_level;
};
#endif /* _SET_SOURCE_H_ */

3)Makefile

#
# MakeFile
#
# 编译器 gcc
CC=g++ -std=c++11
# log库与头文件目录
LIBDIR=$(PWD)/lib
INCLUDEDIR=$(PWD)/include
# 编译参数
CFLAGS=-Wall -std=c++11 -g -O0
LIBFLAGS=-llog -lsetsource -L $(LIBDIR)
# 日志模块文件
LOGSRC=setSource.cpp
LOGOBJ=$(LOGSRC:.cpp=.o)
# 编出动态库,默认使用动态库编译
LIB=libsetsource.so
# 测试程序
OBJS=test
# 测试程序文件
SOURCEFILE=test.cpp
.PHONY:all
all:$(OBJS)
$(OBJS):$(LIB) $(SOURCEFILE)
$(CC) $(SOURCEFILE) $(LIBFLAGS) $(CFLAGS) -I $(INCLUDEDIR) -o $@
@echo "compile finish"
$(LIB):$(LOGOBJ)
$(CC) -shared $(CFLAGS) -o $@ $^
@cp -r libsetsource.so ./lib
$(LOGOBJ):$(LOGSRC)
$(CC) -g -O0 -c -fPIC $^ -llog $(LIBDIR) -I $(INCLUDEDIR)
.PHONY:clean
clean:
rm -fr $(LOGOBJ) $(LIB) $(OBJS)

3. demo与控制效果

1) test.cpp

#include "setSource.h"
#include <iostream>
#include <unistd.h>
#include <cstdlib>
int main(int argc, char const *argv[])
{
int pid = fork();
if (pid == 0)
{
sleep(5);
while (1)
{
/* code */
}
}
else
{
setSource test(2);
test.dealWtithSetSource("test", pid, T_CPU);
}
return 0;
}

2) 效果

image

4. TODO LIST

目前只做了CPU和内存的并且是固定比例,bio的读写与网络带宽还没做,思路是一样的。

ps:

bio 只会限制direct io 并不会限制 buffer io,如果要限制进程读写裸设备或直接在块设备上操作等情况才适合。

本文作者:BaldButStrong

本文链接:https://www.cnblogs.com/supersimple/p/18701271

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   BaldButStrong  阅读(13)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起