272 lines
8.4 KiB
C++
272 lines
8.4 KiB
C++
|
// CPUSpeed v1.20
|
|||
|
// 17/11/2021
|
|||
|
// https://t.me/ssleg © 2020 – 2021
|
|||
|
|
|||
|
#include <iostream>
|
|||
|
#include <random>
|
|||
|
#include <thread>
|
|||
|
#include <sys/sysinfo.h>
|
|||
|
#include <mutex>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
const int max_gen_value = 2147483647;
|
|||
|
const int MB = 1048576;
|
|||
|
mutex print_lock;
|
|||
|
|
|||
|
double cpu_time() {
|
|||
|
clockid_t id = CLOCK_THREAD_CPUTIME_ID;
|
|||
|
struct timespec ts{};
|
|||
|
|
|||
|
clock_gettime(id, &ts);
|
|||
|
return (double) ts.tv_sec + (double) ts.tv_nsec / 1000000000.0;
|
|||
|
}
|
|||
|
|
|||
|
void rnd_generator(int th_num, int start, int end, float *array, double *times) {
|
|||
|
print_lock.lock();
|
|||
|
cout << "поток #" << th_num << " " << start << " " << end << endl;
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
random_device rd;
|
|||
|
mt19937 gen(rd());
|
|||
|
uniform_int_distribution<> dist(0, max_gen_value);
|
|||
|
|
|||
|
double start_time = cpu_time();
|
|||
|
int interval = (end - start) / 5;
|
|||
|
double cycle_time;
|
|||
|
double old_cycle_time = start_time;
|
|||
|
|
|||
|
int i;
|
|||
|
for (i = start; i < end; i++) {
|
|||
|
array[i] = dist(gen);
|
|||
|
if (i % interval == 0 and i > 0) {
|
|||
|
cycle_time = cpu_time();
|
|||
|
|
|||
|
print_lock.lock();
|
|||
|
printf("поток #%u, %uМб. время %3.5f сек.\n", th_num, i / MB * 16, cycle_time - old_cycle_time);
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
old_cycle_time = cycle_time;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
double end_time = cpu_time();
|
|||
|
double th_time = end_time - start_time;
|
|||
|
|
|||
|
print_lock.lock();
|
|||
|
printf("поток #%u, всего времени генератора %3.5f сек.\n", th_num, th_time);
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
times[th_num] = th_time;
|
|||
|
}
|
|||
|
|
|||
|
void zero_fill(int th_num, int arr_size, double *array, double *times) {
|
|||
|
print_lock.lock();
|
|||
|
cout << "поток #" << th_num << ", zero_fill." << endl;
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
double start_time = cpu_time();
|
|||
|
int interval = arr_size / 5;
|
|||
|
double cycle_time;
|
|||
|
double old_cycle_time = start_time;
|
|||
|
|
|||
|
int i;
|
|||
|
for (i = 0; i < arr_size; i++) {
|
|||
|
array[i] = 0;
|
|||
|
if (i % interval == 0 and i > 0) {
|
|||
|
cycle_time = cpu_time();
|
|||
|
|
|||
|
print_lock.lock();
|
|||
|
printf("поток #%u, %uМб. время %3.5f сек.\n", th_num, i / MB * 16, cycle_time - old_cycle_time);
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
old_cycle_time = cycle_time;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
double end_time = cpu_time();
|
|||
|
double th_time = end_time - start_time;
|
|||
|
|
|||
|
print_lock.lock();
|
|||
|
printf("поток #%u, всего времени стирания %3.5f сек.\n", th_num, th_time);
|
|||
|
print_lock.unlock();
|
|||
|
|
|||
|
times[th_num] = th_time;
|
|||
|
}
|
|||
|
|
|||
|
void compute(int th_num, int start, int end, const float *a, const float *b, double *rez, double *times) {
|
|||
|
int i;
|
|||
|
double r1, r2, r3, r4, r5, r6, r7, r8;
|
|||
|
double start_time = cpu_time();
|
|||
|
double end_time;
|
|||
|
for (i = start; i < end - 7; i++) {
|
|||
|
r1 = a[i] * b[i];
|
|||
|
r2 = a[i] * b[i + 1];
|
|||
|
r3 = a[i] * b[i + 2];
|
|||
|
r4 = a[i] * b[i + 3];
|
|||
|
r5 = a[i] * b[i + 4];
|
|||
|
r6 = a[i] * b[i + 5];
|
|||
|
r7 = a[i] * b[i + 6];
|
|||
|
r8 = a[i] * b[i + 7];
|
|||
|
rez[i] = (r1 + r2 + r3 + r4 + r5 + r6 + r7 + r8) / 8;
|
|||
|
}
|
|||
|
end_time = cpu_time();
|
|||
|
times[th_num] = end_time - start_time;
|
|||
|
}
|
|||
|
|
|||
|
void thread_starter(int start_num, int th_number, int arr_size, float *array, thread *threads, double *times) {
|
|||
|
int i;
|
|||
|
int start, end, block;
|
|||
|
block = arr_size / th_number;
|
|||
|
|
|||
|
for (i = 0; i < th_number; i++) {
|
|||
|
start = i * block;
|
|||
|
if (i + 1 != th_number) {
|
|||
|
end = (i + 1) * block;
|
|||
|
} else {
|
|||
|
end = arr_size;
|
|||
|
}
|
|||
|
|
|||
|
threads[start_num + i] = thread(rnd_generator, start_num + i, start, end, array, times);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
int input_integer(int low, int high) {
|
|||
|
bool flag = false;
|
|||
|
int input;
|
|||
|
|
|||
|
do {
|
|||
|
cin >> input;
|
|||
|
if (input > low and input <= high) {
|
|||
|
flag = true;
|
|||
|
} else {
|
|||
|
cin.clear();
|
|||
|
cin.ignore(32767, '\n');
|
|||
|
cout << "неверный ввод, попробуйте снова:";
|
|||
|
}
|
|||
|
} while (!flag);
|
|||
|
cin.ignore(32767, '\n');
|
|||
|
|
|||
|
return input;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int main() {
|
|||
|
struct sysinfo info{};
|
|||
|
sysinfo(&info);
|
|||
|
long total_ram = info.totalram;
|
|||
|
long free_ram = info.freeram;
|
|||
|
int max_array_size = int(double(free_ram) / 16 / MB);
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
cout << "CPUSpeed v1.20" << endl;
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
printf("оперативной памяти всего - %3.1f Gb\n", float(total_ram) / 1024 / MB);
|
|||
|
printf("свободно - %3.2f Gb\n", float(free_ram) / 1024 / MB);
|
|||
|
|
|||
|
int cores_count = int(thread::hardware_concurrency());
|
|||
|
|
|||
|
printf("введите количество потоков [1-%u]:", cores_count);
|
|||
|
int threads = input_integer(0, cores_count);
|
|||
|
|
|||
|
printf("введите размер массива данных [8-%u]:", max_array_size);
|
|||
|
int arr = input_integer(7, max_array_size);
|
|||
|
|
|||
|
cout << "введите количество тестов [1-1000]:";
|
|||
|
int test_count = input_integer(0, 1000);
|
|||
|
|
|||
|
const int arr_size = arr * MB;
|
|||
|
const float real_mem_size = float(arr_size) * 16 / 1024 / MB;
|
|||
|
auto *a = new float[arr_size];
|
|||
|
auto *b = new float[arr_size];
|
|||
|
auto *rez = new double[arr_size];
|
|||
|
|
|||
|
printf("запуск бенчмарка. реальный необходимый обьем RAM - %3.1f Gb\n", real_mem_size);
|
|||
|
|
|||
|
int i;
|
|||
|
auto *thr = new thread[threads];
|
|||
|
auto *times = new double[threads];
|
|||
|
auto *sum_times = new double[threads];
|
|||
|
auto *sum_flops = new double[threads];
|
|||
|
|
|||
|
if (threads == 1) {
|
|||
|
thread_starter(0, threads, arr_size, a, thr, times);
|
|||
|
thr[0].join();
|
|||
|
thread_starter(0, threads, arr_size, b, thr, times);
|
|||
|
thr[0].join();
|
|||
|
thr[0] = thread(zero_fill, 0, arr_size, rez, times);
|
|||
|
thr[0].join();
|
|||
|
}
|
|||
|
if (threads == 2) {
|
|||
|
thread_starter(0, 1, arr_size, a, thr, times);
|
|||
|
thread_starter(1, 1, arr_size, b, thr, times);
|
|||
|
thr[0].join();
|
|||
|
thr[1].join();
|
|||
|
thr[0] = thread(zero_fill, 0, arr_size, rez, times);
|
|||
|
thr[0].join();
|
|||
|
}
|
|||
|
if (threads > 2) {
|
|||
|
int a_threads = (threads - 1) / 2;
|
|||
|
int b_threads = threads - 1 - a_threads;
|
|||
|
thread_starter(0, a_threads, arr_size, a, thr, times);
|
|||
|
thread_starter(a_threads, b_threads, arr_size, b, thr, times);
|
|||
|
thr[threads - 1] = thread(zero_fill, threads - 1, arr_size, rez, times);
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
thr[i].join();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
printf("поток %u, время - %3.5f сек.\n", i, times[i]);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int k, start, end, block;
|
|||
|
int64_t operations;
|
|||
|
double flops;
|
|||
|
block = arr_size / threads;
|
|||
|
for (k = 0; k < test_count; k++) {
|
|||
|
cout << "запуск теста #" << k + 1 << endl;
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
start = i * block;
|
|||
|
if (i + 1 != threads) {
|
|||
|
end = (i + 1) * block;
|
|||
|
} else {
|
|||
|
end = arr_size;
|
|||
|
}
|
|||
|
|
|||
|
thr[i] = thread(compute, i, start, end, a, b, rez, times);
|
|||
|
}
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
thr[i].join();
|
|||
|
}
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
sum_times[i] += times[i];
|
|||
|
operations = (int64_t(end) - int64_t(start) - 7) * 16;
|
|||
|
flops = (operations / times[i]) / 1000000;
|
|||
|
sum_flops[i] += flops;
|
|||
|
printf("поток %u, время - %3.5f сек. (%3.2f MFlops)\n", i, times[i], flops);
|
|||
|
}
|
|||
|
}
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
cout << "Итоговая производительность." << endl;
|
|||
|
cout << "потоков - " << threads << ", размер массива - " << arr << ", тестов - " << test_count << endl;
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
double medium_speed, medium_flops, sys_flops;
|
|||
|
sys_flops = 0;
|
|||
|
for (i = 0; i < threads; i++) {
|
|||
|
medium_speed = sum_times[i] / test_count;
|
|||
|
medium_flops = sum_flops[i] / test_count;
|
|||
|
sys_flops += medium_flops;
|
|||
|
printf("поток %u, время - %3.5f сек. (%3.2f MFlops)\n", i, medium_speed, medium_flops);
|
|||
|
}
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
printf("Система всего - %3.2f MFlops\n", sys_flops);
|
|||
|
cout << "-----------------------------------------------" << endl;
|
|||
|
|
|||
|
free(a);
|
|||
|
free(b);
|
|||
|
free(rez);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|