Задать вопрос
Dyikot
@Dyikot

Почему умножение матрицы 8x8 медленнее чем 10x10?

Именно в одном потоке всегда 10x10 быстрее 8x8.

main

#include <iostream>
#include <format>
#include <chrono>
#include <vector>
#include <functional>

#include "Random.h"
#include "MatrixOperations.h"

int main()
{   
	setlocale(LC_ALL, "ru");

	auto& random = Random::Current();

	auto GenerateSquareMatrix = [&random](int size)
	{
		std::vector<int> matrix(size * size);

		for(auto& element : matrix)
		{
			element = random.GenerateNumber(1, 9);
		}

		return matrix;
	};

	auto MeasureTaskTime = [](std::function<void()> action)
	{
		auto startTime = std::chrono::high_resolution_clock::now();
		action();
		auto endTime = std::chrono::high_resolution_clock::now();

		return endTime - startTime;
	};

	auto PrintMultiplyMatrixTime = [](int matrixSize, int threadsAmount, auto time)
	{
		std::cout << std::format(
			"Время умножения матрицы {} x {} при числе потоков {} = {}\n",
			matrixSize,
			matrixSize,
			threadsAmount,
			time
		);
	};

	const int OneThread = 1;
	const int FourThreads = 4;
	const int MatrixSize8x8 = 8;
	const int MatrixSize10x10 = 10;

	// Умножение матриц 8x8

	std::vector<int> matrixA = GenerateSquareMatrix(MatrixSize8x8);
	std::vector<int> matrixB = GenerateSquareMatrix(MatrixSize8x8);
	
	auto timeMultiplying8x8By1Thread = MeasureTaskTime([&]()
	{
		MatrixOperations::Multiply(matrixA, matrixB);
	});

	auto timeMultiplying8x8By4Thread = MeasureTaskTime([&]()
	{
		MatrixOperations::Multiply(matrixA, matrixB, FourThreads);
	});

	// Умножение матриц 10x10

	matrixA = GenerateSquareMatrix(MatrixSize10x10);
	matrixB = GenerateSquareMatrix(MatrixSize10x10);

	auto timeMultiplying10x10By1Thread = MeasureTaskTime([&]()
	{
		MatrixOperations::Multiply(matrixA, matrixB);
	});

	auto timeMultiplying10x10By4Thread = MeasureTaskTime([&]()
	{
		MatrixOperations::Multiply(matrixA, matrixB, FourThreads);
	});

	// Вывод результата

	PrintMultiplyMatrixTime(
		MatrixSize8x8,
		OneThread,
		std::chrono::duration_cast<std::chrono::microseconds>(timeMultiplying8x8By1Thread)
	);

	PrintMultiplyMatrixTime(
		MatrixSize8x8,
		FourThreads,
		std::chrono::duration_cast<std::chrono::microseconds>(timeMultiplying8x8By4Thread)
	);

	PrintMultiplyMatrixTime(
		MatrixSize10x10,
		OneThread,
		std::chrono::duration_cast<std::chrono::microseconds>(timeMultiplying10x10By1Thread)
	);

	PrintMultiplyMatrixTime(
		MatrixSize10x10,
		FourThreads,
		std::chrono::duration_cast<std::chrono::microseconds>(timeMultiplying10x10By4Thread)
	);
}


Метод умножения матриц

#include "MatrixOperations.h"

std::vector<int> MatrixOperations::Multiply(
	const std::vector<int>& first, 
	const std::vector<int>& second,
	const int threadAmount
)
{
	const int Size = sqrt(first.size());	
	const int Step = float(Size) / threadAmount == Size / threadAmount ?
					 Size / threadAmount :
					 Size / threadAmount + 1;
	int row = 0;

	std::vector<int> result(first.size());
	std::vector<std::thread> threads;
	
	auto CalculateCellValue = [&](int row, int column)
	{
		int cellValue = 0;

		for(int i = 0; i < Size; i++)
		{
			cellValue += first[row * Size + i] * second[i * Size + column];
		}

		return cellValue;
	};

	auto MultiplyMatrix = [&](int startRow, int lastRow)
	{
		for(int row = startRow; row < lastRow; row++)
		{
			for(int column = 0; column < Size; column++)
			{
				result[row * Size + column] = CalculateCellValue(row, column);
			}
		}
	};

	// Запуск потоков
	int lastRow;
	for(int i = 0; i < threadAmount; i++)
	{
		lastRow = row + Step <= Size ? row + Step : Size;
		threads.emplace_back(MultiplyMatrix, row, lastRow);
		
		row += Step;
	}

	// Ожидание завершения потоков
	for(auto& thread : threads)
	{
		thread.join();
	}

	return result;
}



6554ade636591801102861.png
  • Вопрос задан
  • 168 просмотров
Подписаться 1 Простой 2 комментария
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Скорее всего тут дело в кеше процессора. После первых запусков так получилось, что данные оказались в кеше.

Вообще, писать бенчмарки - очень сложно. Надо сначала прогонять тест несколько раз и отбрасывать результаты, а уже потом мерять. Надо быть очень внимательным, если вы запускакте разные тесты в одной программе подряд: результаты работы одного теста могут повлиять на остальные.

Ну и главное, выполнять такое короткое действие всего один раз - это вообще моветон. Надо выполнить его сотню тысяч раз и потом общее время делить на количество запусков. Иначе вы меряете случайный шум в основном. Может тут вам просто все время (не)везет и вот так третий тест оказывается быстрее остальных.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
ITK academy Нижний Новгород
от 80 000 до 120 000 ₽
ITK academy Краснодар
от 75 000 до 125 000 ₽