chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
//
|
||||
// getPerformance.cpp
|
||||
// MNN
|
||||
//
|
||||
// Created by MNN on 2019/03/12.
|
||||
// Copyright © 2018, Alibaba Group Holding Limited
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <MNN/AutoTime.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <MNN/MNNDefine.h>
|
||||
#include "core/Macro.h"
|
||||
#ifdef MNN_USE_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
class Timer {
|
||||
private:
|
||||
std::chrono::high_resolution_clock::time_point inTime, outTime;
|
||||
|
||||
public:
|
||||
void startTimer() {
|
||||
inTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// unit ms
|
||||
float getCostTimer() {
|
||||
outTime = std::chrono::high_resolution_clock::now();
|
||||
return (float)(std::chrono::duration_cast<std::chrono::microseconds>(outTime - inTime).count());
|
||||
}
|
||||
};
|
||||
|
||||
int getCpuCounts() {
|
||||
FILE* fp = fopen("/proc/cpuinfo", "rb");
|
||||
if (fp == nullptr) {
|
||||
MNN_PRINT("fopen error ! \n");
|
||||
return 0;
|
||||
}
|
||||
int cpuCounts = 0;
|
||||
char data[1024];
|
||||
while (!feof(fp)) {
|
||||
char* a = fgets(data, 1024, fp);
|
||||
|
||||
if (a == nullptr) {
|
||||
break;
|
||||
}
|
||||
if (memcmp(data, "processor", 9) == 0) {
|
||||
cpuCounts++;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
return cpuCounts;
|
||||
}
|
||||
|
||||
// 0 max 1 min 2 cur
|
||||
void getFreqKhz(int cpuid, std::vector<int>& freqVector) {
|
||||
char path[256];
|
||||
int freqKhz = -1;
|
||||
// max
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpuid);
|
||||
FILE* fp = fopen(path, "rb");
|
||||
if (nullptr == fp) {
|
||||
MNN_PRINT("cpuinfo_max_freq fopen error ! \n");
|
||||
freqVector.emplace_back(0);
|
||||
} else {
|
||||
fscanf(fp, "%d", &freqKhz);
|
||||
fclose(fp);
|
||||
freqVector.push_back(freqKhz);
|
||||
}
|
||||
|
||||
// min
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_min_freq", cpuid);
|
||||
fp = fopen(path, "rb");
|
||||
if (nullptr == fp) {
|
||||
MNN_PRINT("cpuinfo_min_freq fopen error ! \n");
|
||||
freqVector.emplace_back(0);
|
||||
} else {
|
||||
freqKhz = -1;
|
||||
fscanf(fp, "%d", &freqKhz);
|
||||
fclose(fp);
|
||||
freqVector.push_back(freqKhz);
|
||||
}
|
||||
|
||||
// cur
|
||||
// sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", cpuid);
|
||||
// fp = fopen(path, "rb");
|
||||
// if(nullptr == fp){
|
||||
// MNN_PRINT("cpuinfo_cur_freq fopen error ! \n");
|
||||
// }else{
|
||||
// freqKhz = -1;
|
||||
// fscanf(fp, "%d", &freqKhz);
|
||||
// fclose(fp);
|
||||
// freqVector.push_back(freqKhz);
|
||||
// }
|
||||
}
|
||||
|
||||
void cpuFloatMlaTest(int32_t loopCounts) {
|
||||
#ifdef MNN_USE_NEON
|
||||
#ifndef __aarch64__
|
||||
|
||||
__asm__ __volatile__(
|
||||
"mov r12, %0\n"
|
||||
"0: \n"
|
||||
"vmla.f32 q15, q15, d0[0] \n"
|
||||
"vmla.f32 q14, q14, d0[1] \n"
|
||||
"vmla.f32 q13, q13, d1[0] \n"
|
||||
"vmla.f32 q12, q12, d1[1] \n"
|
||||
"vmla.f32 q11, q11, d2[0] \n"
|
||||
"vmla.f32 q10, q10, d2[1] \n"
|
||||
"vmla.f32 q9, q9, d3[0] \n"
|
||||
"vmla.f32 q8, q8, d3[1] \n"
|
||||
"vmla.f32 q7, q7, d4[0] \n"
|
||||
"vmla.f32 q6, q6, d4[1] \n"
|
||||
"vmla.f32 q5, q5, d5[0] \n"
|
||||
"vmla.f32 q4, q4, d5[1] \n"
|
||||
"vmla.f32 q3, q3, d6[0] \n"
|
||||
"subs r12, r12, #1 \n"
|
||||
"bne 0b \n"
|
||||
:
|
||||
: "r"(loopCounts)
|
||||
: "cc", "memory", "r12", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q14", "q15"
|
||||
);
|
||||
|
||||
#else
|
||||
__asm__ __volatile__(
|
||||
"mov w9, %w0\n"
|
||||
"0: \n"
|
||||
"fmla v31.4s, v31.4s, v0.s[0]\n"
|
||||
"fmla v30.4s, v30.4s, v0.s[1]\n"
|
||||
"fmla v29.4s, v29.4s, v0.s[2]\n"
|
||||
"fmla v28.4s, v28.4s, v0.s[3]\n"
|
||||
"fmla v27.4s, v27.4s, v1.s[0]\n"
|
||||
"fmla v26.4s, v26.4s, v1.s[1]\n"
|
||||
"fmla v25.4s, v25.4s, v1.s[2]\n"
|
||||
"fmla v24.4s, v24.4s, v1.s[3]\n"
|
||||
"fmla v23.4s, v23.4s, v3.s[0]\n"
|
||||
"fmla v22.4s, v22.4s, v3.s[1]\n"
|
||||
"fmla v21.4s, v21.4s, v3.s[2]\n"
|
||||
"fmla v20.4s, v20.4s, v3.s[3]\n"
|
||||
"fmla v19.4s, v19.4s, v4.s[0]\n"
|
||||
"fmla v18.4s, v18.4s, v4.s[1]\n"
|
||||
"fmla v17.4s, v17.4s, v4.s[2]\n"
|
||||
"fmla v16.4s, v16.4s, v4.s[3]\n"
|
||||
"fmla v15.4s, v15.4s, v5.s[0]\n"
|
||||
"fmla v14.4s, v14.4s, v5.s[1]\n"
|
||||
"fmla v13.4s, v13.4s, v5.s[2]\n"
|
||||
"fmla v12.4s, v12.4s, v5.s[3]\n"
|
||||
"fmla v11.4s, v11.4s, v6.s[0]\n"
|
||||
"fmla v10.4s, v10.4s, v6.s[1]\n"
|
||||
"fmla v9.4s, v9.4s, v6.s[2]\n"
|
||||
"fmla v8.4s, v8.4s, v6.s[3]\n"
|
||||
"fmla v7.4s, v7.4s, v2.s[0]\n"
|
||||
"subs w9, w9, #1 \n"
|
||||
"bne 0b \n"
|
||||
:
|
||||
: "r"(loopCounts)
|
||||
: "cc", "memory", "w9", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15"
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpuFLOPSPerformance() {
|
||||
int32_t loopCounts = 100000000;
|
||||
MNN_PRINT("CPU PERFORMANCE -> loopCounts : %d \n", loopCounts);
|
||||
|
||||
std::vector<int> freqVector;
|
||||
for (int i = 0; i < getCpuCounts(); i++) {
|
||||
freqVector.clear();
|
||||
getFreqKhz(i, freqVector);
|
||||
MNN_PRINT("core %d : max : %d, min : %d \n",i, freqVector.at(0), freqVector.at(1));
|
||||
}
|
||||
|
||||
// warm up
|
||||
cpuFloatMlaTest(loopCounts);
|
||||
|
||||
Timer timeInstance;
|
||||
timeInstance.startTimer();
|
||||
cpuFloatMlaTest(loopCounts);
|
||||
#ifdef MNN_USE_NEON
|
||||
#ifndef __aarch64__
|
||||
auto number = (double)loopCounts * 13;
|
||||
#else
|
||||
auto number = (double)loopCounts * 25;
|
||||
#endif
|
||||
#else
|
||||
auto number = 0.0;
|
||||
#endif
|
||||
//FUNC_PRINT(number);
|
||||
float costTime_ms = timeInstance.getCostTimer();
|
||||
double costTime_s = (double)(costTime_ms) / 1000000.0f;
|
||||
// MNN_PRINT("cost time : %f \n", costTime_s);
|
||||
double mlaCounts_g = number * 4 / 1000000000.0f;
|
||||
float gflops = mlaCounts_g / costTime_s;
|
||||
MNN_PRINT(" ======================== float ===============================\n");
|
||||
MNN_PRINT("CPU float gflops : %f\n", gflops);
|
||||
}
|
||||
|
||||
static void _testMemcpy() {
|
||||
int size = 1024 * 1024;
|
||||
int loop = 10000;
|
||||
std::vector<std::thread> threads;
|
||||
int threadNumber = 2;
|
||||
std::vector<std::vector<int8_t>> tmp(threadNumber);
|
||||
for (int i=0; i<threadNumber; ++i) {
|
||||
tmp[i].resize(size);
|
||||
}
|
||||
MNN::Timer _t;
|
||||
for (int i=0; i<threadNumber; ++i) {
|
||||
threads.emplace_back(std::thread([size, loop, i, &tmp]() {
|
||||
auto t0 = tmp[i].data();
|
||||
for (int i=0; i<loop; ++i) {
|
||||
::memset(t0, 0, size);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
float timeInS = (float)_t.durationInUs() / 1000.0f / 1000.0f;
|
||||
float speed = (float)size * (float)threads.size() / 1024.0f / 1024.0f / 1024.0f * (float)loop / timeInS;
|
||||
MNN_PRINT("Memcpy speed: %f GB / s\n", speed);
|
||||
|
||||
}
|
||||
int main(int argc, const char* argv[]) {
|
||||
MNN_PRINT("Start PERFORMANCE !!! \n");
|
||||
|
||||
cpuFLOPSPerformance();
|
||||
_testMemcpy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user