@@ -35,6 +35,8 @@ Analise o código `matmul_seq.cpp`:
3535#include < cstdlib>
3636#include < algorithm>
3737
38+
39+ #define TAM_MATRIZ 1000
3840/*
3941 ============================================================
4042 OBJETIVO
@@ -53,71 +55,107 @@ Analise o código `matmul_seq.cpp`:
5355
5456 ============================================================
5557*/
56- int main (int argc, char* argv[ ] ) {
57- const int N = 2000; // Tamanho da matriz
58- int B = 0; // Tamanho do bloco. Se for 0 → versão ingênua.
5958
60- // Lê o tamanho do bloco da linha de comando
61- // Exemplo: ./matmul_seq 200 → roda com blocos 200×200
62- if (argc > 1) {
63- // Atualiza o valor de B de acordo com o parâmetro de entrada
64- B = std::atoi(argv[1]);
65- }
59+ /* Definicoes para melhorar a legibilidade*/
60+
61+ using Matriz = std::vector<std::vector<double >>;
62+
63+ inline Matriz criaMatriz (int size, double value){
64+ return Matriz(size, std::vector<double >(size, value));
65+ }
66+
67+ /**
68+ * @brief Versão ingênua da multiplicação de matrizes.
69+ *
70+ * Implementa a multiplicação com três loops aninhados (i, j, k) sem uso de tiling.
71+ * O acesso às matrizes é feito de forma direta, sem otimizações de cache.
72+ * /
73+ inline void versaoIngenua(){
6674
6775 // Cria três matrizes NxN em memória, preenchidas com valores fixos
6876 // - A inicializada com 1.0
6977 // - Bmat inicializada com 2.0
7078 // - C inicializada com 0.0 (resultado)
71- std::vector<std::vector<double>> A(N, std::vector<double>(N, 1.0));
72- std::vector<std::vector<double>> Bmat(N, std::vector<double>(N, 2.0));
73- std::vector<std::vector<double>> C(N, std::vector<double>(N, 0.0));
7479
75- // Marca o início da medição de tempo
76- auto start = std::chrono::high_resolution_clock::now();
80+ Matriz A = criaMatriz(TAM_MATRIZ, 1.0);
81+ Matriz Bmat = criaMatriz(TAM_MATRIZ, 2.0);
82+ Matriz C = criaMatriz(TAM_MATRIZ, 0.0);
7783
78- if (B <= 0) {
79- // ========================================================
80- // VERSÃO INGENUA
81- // --------------------------------------------------------
82- // Três loops aninhados (i, j, k)
83- // Acesso às matrizes sem tiling
84- // ========================================================
85- for (int i = 0; i < N; i++) {
86- for (int j = 0; j < N; j++) {
87- for (int k = 0; k < N; k++) {
88- C[i][j] += A[i][k] * Bmat[k][j];
89- }
84+ for (int i = 0; i < TAM_MATRIZ; i++) {
85+ for (int j = 0; j < TAM_MATRIZ; j++) {
86+ for (int k = 0; k < TAM_MATRIZ; k++) {
87+ C[i][j] += A[i][k] * Bmat[k][j];
9088 }
9189 }
92- } else {
93- // ========================================================
94- // VERSÃO COM TILING
95- // ========================================================
96- for (int ii = 0; ii < N; ii += B) { // blocos de linhas
97- for (int jj = 0; jj < N; jj += B) { // blocos de colunas
98- for (int kk = 0; kk < N; kk += B) { // blocos intermediários
99- // Multiplicação de submatrizes B×B
100- // Ordem j -> i -> k
101- for (int j = jj; j < std::min(jj + B, N); j++) {
102- for (int i = ii; i < std::min(ii + B, N); i++) {
103- double sum = C[i][j];
104- for (int k = kk; k < std::min(kk + B, N); k++) {
105- sum += A[i][k] * Bmat[k][j];
106- }
107- C[i][j] = sum;
90+ }
91+ }
92+
93+ /**
94+ * @brief Multiplicação de matrizes utilizando a técnica de tiling (blocking).
95+ *
96+ * Realiza a multiplicação de matrizes dividindo as matrizes em blocos (tiles) de tamanho ` tamBloco ` .
97+ * Otimiza o uso da cache ao trabalhar com submatrizes menores que cabem na hierarquia de memória.
98+ *
99+ * @param tamBloco Tamanho do bloco (tile) usado para dividir as matrizes na multiplicação.
100+ * /
101+ inline void versaoTiling(int tamBloco){
102+
103+ // Cria três matrizes NxN em memória, preenchidas com valores fixos
104+ // - A inicializada com 1.0
105+ // - Bmat inicializada com 2.0
106+ // - C inicializada com 0.0 (resultado)
107+
108+ Matriz A = criaMatriz(TAM_MATRIZ, 1.0);
109+ Matriz Bmat = criaMatriz(TAM_MATRIZ, 2.0);
110+ Matriz C = criaMatriz(TAM_MATRIZ, 0.0);
111+
112+ for (int ii = 0; ii < TAM_MATRIZ; ii += tamBloco) { // blocos de linhas
113+ for (int jj = 0; jj < TAM_MATRIZ; jj += tamBloco) { // blocos de colunas
114+ for (int kk = 0; kk < TAM_MATRIZ; kk += tamBloco) {// blocos intermediários
115+ // Multiplicação de submatrizes tamBloco x tamBloco
116+ // Ordem j -> i -> k
117+ for (int j = jj; j < std::min(jj + tamBloco, TAM_MATRIZ); j++) {
118+ for (int i = ii; i < std::min(ii + tamBloco, TAM_MATRIZ); i++) {
119+ double sum = C[i][j];
120+ for (int k = kk; k < std::min(kk + tamBloco, TAM_MATRIZ); k++) {
121+ sum += A[i][k] * Bmat[k][j];
108122 }
123+ C[i][j] = sum;
109124 }
110125 }
111126 }
112127 }
113128 }
129+ }
130+
131+
132+
133+ int main(int argc, char* argv[ ] ) {
134+ int tamBloco = 0; // Tamanho do bloco. Se for 0 → versão ingênua.
135+
136+ // Lê o tamanho do bloco da linha de comando
137+ // Exemplo: ./matmul_seq 200 → roda com blocos 200×200
138+ if (argc > 1) {
139+ // Atualiza o valor de tamBloco de acordo com o parâmetro de entrada
140+ tamBloco = std::atoi(argv[1]);
141+ }
142+
143+ // Marca o início da medição de tempo
144+ auto start = std::chrono::high_resolution_clock::now();
145+
146+ if (tamBloco <= 0) {
147+ versaoIngenua();
148+ }
149+ else {
150+ versaoTiling(tamBloco);
151+ }
114152
115153 // Marca o fim da medição
116154 auto end = std::chrono::high_resolution_clock::now();
117155
118156 // Calcula e imprime o tempo total em milissegundos
119157 std::cout << "Execução ("
120- << (B <= 0 ? "ingênua" : "tiling B =" + std::to_string(B ))
158+ << (tamBloco <= 0 ? "ingênua" : "tiling tamBloco =" + std::to_string(tamBloco ))
121159 << "): "
122160 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
123161 << " ms" << std::endl;
0 commit comments