# 1 项目背景
最近,本人在Github上发布了一个开源软件,名字叫“云汉烤机大师”,代码仓库地址:

这个烤机软件在设计时考虑了RK3399芯片这种既有大小核架构的CPU又有支持OpenCL的GPU的情况。程序可以通过Pthread、OpenMP和OpenCL让处理器的CPU和GPU长时间保持满载,并每隔5秒往终端打印实时的处理器温度、CPU核心在线情况、处理器大核频率、处理器小核频率、CPU计算速度和GPU计算速度。你也可以把代码中的功能局部注释,这样就可以适用于那些不支持OpenCL或者核心数量较少的处理器芯片。
# 2 测试平台
Leez 区发布了基于RK3399的P710单板电脑,这款小电脑的硬件配置已经有群友评测过了,见**《Leez-P710:火力全开》**
我也有幸获得了Leez P710的试用机会。下图是我的试用产品,可以看到我特地为它设计了散热风道。

下图是我设计并3D打印的外壳,是个小盒子,侧壁上留出了接口和风道

安装白色支脚后,盒子可以立起来,俨然是个小机箱。

今天的测试,就要在这个Leez P710上面做。
# 3 环境配置
Leez 区发布的debian固件里面已经到了GCC,自带OpenMP库。
但是,有一点要注意,Leez P710的GPU是Mali T860,但是Leez 区发布的debian固件里没有OpenCL的头文件,代码编译时候会遇到问题。我们可以去rockchip-linux的github仓库下载Mali GPU的支持库,命令:
“`shell
git clone https://github.com/rockchip-linux/libmali.git
“`
然后把include放到/usr目录里去,文件夹之间直接合并。
# 4 编译和运行
把“烤机大师”文件夹里的ickey.c和test.cl两个文件放到方便的目录,比如/home/test
编译命令如下:
“`shell
gcc -o ickey ickey.c -lpthread -lOpenCL -fopenmp
“`
执行
“`shell
./ickey
“`
程序跑起来后,下图是终端实时打印的信息。我们可以看到温度大约是70度,6个CPU核心(0到5)都在线,A53小核心频率1.42,A72大核心频率1.8。并没有发生一核有难多核围观的惨案。

其中,CPU的核心频率是动态变化的,有时候会掉到1.42。因为我们把所有处理器核心都用上了,所以温度稍微有些高,都触发主动降频了。
上图中的“cpu used = xxx”和“ocl used = xxx”是让CPU和GPU各自跑了不同的算法并测量了时间(具体算法在第5节给出)。可以观察当温度过高的情况下,CPU与GPU是否有明显降速。其中,CPU跑的是浮点乘除法算圆周率,GPU跑的是冒泡法整型数据排序
继续烤机,最后温度稳定在73度左右波动。处理器动态降频降低热量后,频率回升,然后温度升高,又发生动态降频。A72核心频率最低降到了1.2GHz,触发温度大约是72.8度。这对计算速度也有影响,降频后,CPU的浮点计算速度大约慢了15%左右。

# 5 程序原理说明
在主函数里,开启3个线程。
线程1每间隔一定的时间就读取并打印处理器温度、处理器核心的频率、处理器核心的在线情况(看看是否会发生一核有难多核围观的惨案),并把线程2和3得到的运行速度也打印到终端。
线程2通过while(1)里面放入圆周率计算代码让CPU满载。
线程3通过while(1)里放入冒泡法排序代码让GPU满载。
“`c
int main()
{
pthread_t tid_term;
char* p_term = NULL;
pthread_create(&tid_term, NULL, thread_term, NULL);
pthread_t tid_cpu;
char* p_cpu = NULL;
pthread_create(&tid_cpu, NULL, thread_cpu, NULL);
pthread_t tid_ocl;
char* p_ocl = NULL;
pthread_create(&tid_ocl, NULL, thread_ocl, NULL);
sleep(1);
pthread_join(tid_term, (void **)&p_term);
pthread_join(tid_cpu, (void **)&p_cpu);
pthread_join(tid_ocl, (void **)&p_ocl);;
return 0;
}
“`
线程1要跑的温度信息读取和打印
“`c
void *thread_term(void *arg)
{
int fd;
while (1)
{
fd = open(TEMP_PATH, O_RDONLY);
char buf[20];
read(fd, buf, 20);
double temp;
temp = atoi(buf) / 1000.0;
printf(“temperature: %.1lfn”,temp);
close(fd);
system(“cat /sys/devices/system/cpu/online”);
fd = open(CPU0_PATH, O_RDONLY);
char buf1[20];
read(fd, buf1, 20);
temp = atoi(buf1) / 1000000.0;
printf(“A53 Freq: %.2lfn”, temp);
close(fd);
fd = open(CPU4_PATH, O_RDONLY);
char buf2[20];
read(fd, buf2, 20);
temp = atoi(buf2) / 1000000.0;
printf(“A72 Freq: %.2lfn”, temp);
close(fd);
printf(“n”);
if (iscpu == 1)
{
printf(“cpu used = %lf sn”, timecpu);
iscpu = 0;
}
if (isocl == 1)
{
printf(“ocl used = %lf sn”, timeocl);
isocl = 0;
}
sleep(5);
}
}
“`
线程2要跑的OpenMP烤机函数(让CPU满载)
“`c
void *thread_cpu(void *arg)
{
while (1)
{
double s = 1;
double pi = 0;
double i = 1.0;
double n = 1.0;
double dt;
double start_time;
int cnt = 0;
start_time = microtime();
#pragma omp parallel for num_threads(6)
for (cnt = 0; cnt
{
pi += i;
n = n + 2;
s = -s;
i = s / n;
}
pi = 4 * pi;
dt = microtime() – start_time;
timecpu = dt;
iscpu = 1;
}
}
“`
线程3要跑的OpenCL烤机函数(让GPU满载)
“`c
void *thread_ocl(void *arg)
{
int array_a[20] = { 0, 1, 8, 7, 6, 2, 3, 5, 4, 9,17,19,15,10,18,16,14,13,12,11 };
int array_b[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,0 };
size_t datasize = 20 * sizeof(int);
size_t ocl_string_size;
char *ocl_string;
double start_time, dt, dt_err;
start_time = microtime();
dt_err = microtime() – start_time;
ocl_string = (char *)malloc(400);
//ocl_string = (char *)malloc(20);
cl_platform_id platform_id;
cl_device_id device_id;
cl_context context;
cl_command_queue command_queue;
cl_mem buffer_a, buffer_b;
cl_program program;
cl_kernel kernel;
cl_event kernelEvent;
clGetPlatformIDs(1, &platform_id, NULL);
clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, NULL);
command_queue = clCreateCommandQueue(context, device_id, 0, NULL);
buffer_a = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, NULL);
buffer_b = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, NULL);
ocl_string_size = get_ocl_string(“test.cl”, ocl_string);
clEnqueueWriteBuffer(command_queue, buffer_a, CL_FALSE, 0,
datasize, array_a, 0, NULL, NULL);
clEnqueueWriteBuffer(command_queue, buffer_b, CL_FALSE, 0,
datasize, array_b, 0, NULL, NULL);
program = clCreateProgramWithSource(context, 1, (const char **)&ocl_string,
&ocl_string_size, NULL);
clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
kernel = clCreateKernel(program, “test”, NULL);
clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer_a);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &buffer_b);
size_t global_work_size[1] = { 20 };
while (1)
{
start_time = microtime();
clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL,
global_work_size, NULL, 0, NULL, &kernelEvent);
clWaitForEvents(1, &kernelEvent);
clEnqueueReadBuffer(command_queue, buffer_b, CL_TRUE, 0,
datasize, array_b, 0, NULL, NULL);
dt = microtime() – start_time – dt_err;
timeocl = dt;
isocl = 1;
}
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(command_queue);
clReleaseMemObject(buffer_a);
clReleaseMemObject(buffer_b);
clReleaseContext(context);
free(ocl_string);
}
“`
因为用了OpenCL,所以还要写个OpenCL的cl文件,可以叫test.cl

#小结
群友的那篇**《leez-p710:火力全开》**文章里也展示了用stressapptest做压力测试的截图,
展示了rk3399的a72大核降频时的几个档位,分别是1.8g、1.6g、1.4g、1.2g等。
本测试发现,当达到73度左右时,rk3399的a72核心频率降了3挡,降到了1.2ghz,然后保持稳定。总得来说,
“云汉烤机大师”测试出来的情况与预期差别不大,虽然有些过热降频,但至少是没降到树莓派3的那种只有几百兆hz的夸张程度。
我觉得1.2ghz的主频对性能影响还能忍受。实际使用时,很少有cpu和gpu同时满载的情况a72核心可以长时间保持1.8ghz。
相关资源:烤机软件SP2004-管理软件工具类资源-CSDN文库
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!