Browse Source

Implement parallel openmp algorithm

master
Apostolos Fanakis 6 years ago
parent
commit
ef493d09a3
No known key found for this signature in database GPG Key ID: 56CE2DEDE9F1FB78
  1. 4
      openmp/Makefile
  2. 17
      openmp/coo_sparse_matrix.c
  3. 27
      openmp/coo_sparse_matrix.h
  4. BIN
      openmp/coo_sparse_matrix.o
  5. 17
      openmp/csr_sparse_matrix.c
  6. 27
      openmp/csr_sparse_matrix.h
  7. BIN
      openmp/csr_sparse_matrix.o
  8. 65
      openmp/openmp_gs_pagerank.c
  9. 170
      openmp/openmp_gs_pagerank_functions.c
  10. 18
      openmp/openmp_gs_pagerank_functions.h
  11. BIN
      openmp/pagerank.out
  12. 44
      openmp/serial_gs_pagerank.c
  13. BIN
      openmp/serial_gs_pagerank.o
  14. BIN
      openmp/serial_gs_pagerank_functions.o

4
openmp/Makefile

@ -7,8 +7,8 @@ CC = gcc -std=gnu99 -fopenmp
RM = rm -f RM = rm -f
CFLAGS_DEBUG=-O0 -ggdb3 -Wall -I. CFLAGS_DEBUG=-O0 -ggdb3 -Wall -I.
CFLAGS=-O3 -Wall -I. CFLAGS=-O3 -Wall -I.
OBJ=serial_gs_pagerank.o serial_gs_pagerank_functions.o coo_sparse_matrix.o csr_sparse_matrix.o OBJ=openmp_gs_pagerank.o openmp_gs_pagerank_functions.o coo_sparse_matrix.o csr_sparse_matrix.o
DEPS=serial_gs_pagerank_functions.h coo_sparse_matrix.h csr_sparse_matrix.h DEPS=openmp_gs_pagerank_functions.h coo_sparse_matrix.h csr_sparse_matrix.h
# ========================================== # ==========================================
# TARGETS # TARGETS

17
openmp/coo_sparse_matrix.c

@ -15,9 +15,8 @@ void allocMemoryForCoo(CooSparseMatrix *sparseMatrix, int numberOfElements) {
} }
void addElement(CooSparseMatrix *sparseMatrix, double value, int row, int column) { void addElement(CooSparseMatrix *sparseMatrix, double value, int row, int column) {
// Checks if there is enough space allocated
if (sparseMatrix->numberOfNonZeroElements == sparseMatrix->size) { if (sparseMatrix->numberOfNonZeroElements == sparseMatrix->size) {
printf("%d == %d |||| %d, %d\n", sparseMatrix->numberOfNonZeroElements,
sparseMatrix->size, row, column);
printf("Number of non zero elements exceeded size of matrix!\n"); printf("Number of non zero elements exceeded size of matrix!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -29,6 +28,7 @@ void addElement(CooSparseMatrix *sparseMatrix, double value, int row, int column
newElement->rowIndex = row; newElement->rowIndex = row;
newElement->columnIndex = column; newElement->columnIndex = column;
// Adds the new element to the first empty (NULL) address of the matrix
sparseMatrix->elements[sparseMatrix->numberOfNonZeroElements] = newElement; sparseMatrix->elements[sparseMatrix->numberOfNonZeroElements] = newElement;
sparseMatrix->numberOfNonZeroElements = sparseMatrix->numberOfNonZeroElements + 1; sparseMatrix->numberOfNonZeroElements = sparseMatrix->numberOfNonZeroElements + 1;
} }
@ -42,14 +42,19 @@ void transposeSparseMatrix(CooSparseMatrix *sparseMatrix) {
} }
} }
/*
* This function is a port of the one found here:
* https://github.com/scipy/scipy/blob/3b36a57/scipy/sparse/sparsetools/coo.h#L34
*/
void transformToCSR(CooSparseMatrix initialSparseMatrix, void transformToCSR(CooSparseMatrix initialSparseMatrix,
CsrSparseMatrix *transformedSparseMatrix) { CsrSparseMatrix *transformedSparseMatrix) {
// Taken from here: https://github.com/scipy/scipy/blob/3b36a57/scipy/sparse/sparsetools/coo.h#L34 // Checks if the sizes of the two matrices fit
if (initialSparseMatrix.numberOfNonZeroElements > transformedSparseMatrix->size) { if (initialSparseMatrix.numberOfNonZeroElements > transformedSparseMatrix->numberOfElements) {
printf("Transformed CSR matrix does not have enough space!\n"); printf("Transformed CSR matrix does not have enough space!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Calculates the elements per row
for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){ for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){
int rowIndex = initialSparseMatrix.elements[i]->rowIndex; int rowIndex = initialSparseMatrix.elements[i]->rowIndex;
transformedSparseMatrix->rowCumulativeIndexes[rowIndex] = transformedSparseMatrix->rowCumulativeIndexes[rowIndex] =
@ -63,6 +68,7 @@ void transformToCSR(CooSparseMatrix initialSparseMatrix,
sum += temp; sum += temp;
} }
// Copies the values and columns of the elements
for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){ for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){
int row = initialSparseMatrix.elements[i]->rowIndex; int row = initialSparseMatrix.elements[i]->rowIndex;
int destinationIndex = transformedSparseMatrix->rowCumulativeIndexes[row]; int destinationIndex = transformedSparseMatrix->rowCumulativeIndexes[row];
@ -73,13 +79,12 @@ void transformToCSR(CooSparseMatrix initialSparseMatrix,
transformedSparseMatrix->rowCumulativeIndexes[row]++; transformedSparseMatrix->rowCumulativeIndexes[row]++;
} }
// Fixes the cumulative sum
for (int i=0, last=0; i<=transformedSparseMatrix->size; i++){ for (int i=0, last=0; i<=transformedSparseMatrix->size; i++){
int temp = transformedSparseMatrix->rowCumulativeIndexes[i]; int temp = transformedSparseMatrix->rowCumulativeIndexes[i];
transformedSparseMatrix->rowCumulativeIndexes[i] = last; transformedSparseMatrix->rowCumulativeIndexes[i] = last;
last = temp; last = temp;
} }
transformedSparseMatrix->numberOfNonZeroElements = initialSparseMatrix.numberOfNonZeroElements;
} }
void cooSparseMatrixVectorMultiplication(CooSparseMatrix sparseMatrix, void cooSparseMatrixVectorMultiplication(CooSparseMatrix sparseMatrix,

27
openmp/coo_sparse_matrix.h

@ -1,6 +1,8 @@
#ifndef COO_SPARSE_MATRIX_H /* Include guard */ #ifndef COO_SPARSE_MATRIX_H /* Include guard */
#define COO_SPARSE_MATRIX_H #define COO_SPARSE_MATRIX_H
/* ===== INCLUDES ===== */
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -8,26 +10,51 @@
#include "csr_sparse_matrix.h" #include "csr_sparse_matrix.h"
/* ===== STRUCTURES ===== */
// One element of the coordinate formated sparse matrix.
typedef struct cooSparseMatrixElement { typedef struct cooSparseMatrixElement {
double value; double value;
int rowIndex, columnIndex; int rowIndex, columnIndex;
} CooSparseMatrixElement; } CooSparseMatrixElement;
// A sparse matrix in COOrdinate format (aka triplet format).
typedef struct cooSparseMatrix { typedef struct cooSparseMatrix {
int size, numberOfNonZeroElements; int size, numberOfNonZeroElements;
CooSparseMatrixElement **elements; CooSparseMatrixElement **elements;
} CooSparseMatrix; } CooSparseMatrix;
/* ===== FUNCTION DEFINITIONS ===== */
// initCooSparseMatrix creates and initializes the members of a CooSparseMatrix
// structure instance.
CooSparseMatrix initCooSparseMatrix(); CooSparseMatrix initCooSparseMatrix();
//allocMemoryForCoo allocates memory for the elements of the matrix.
void allocMemoryForCoo(CooSparseMatrix *sparseMatrix, int numberOfElements); void allocMemoryForCoo(CooSparseMatrix *sparseMatrix, int numberOfElements);
// addElement adds an element representing the triplet passed in the arguments
// to the first empty address of the space allocated for the elements.
void addElement(CooSparseMatrix *sparseMatrix, double value, int row, void addElement(CooSparseMatrix *sparseMatrix, double value, int row,
int column); int column);
// transposeSparseMatrix transposes the matrix.
void transposeSparseMatrix(CooSparseMatrix *sparseMatrix); void transposeSparseMatrix(CooSparseMatrix *sparseMatrix);
// transformToCSR transforms the sparse matrix representation format from COO
// to CSR.
void transformToCSR(CooSparseMatrix initialSparseMatrix, void transformToCSR(CooSparseMatrix initialSparseMatrix,
CsrSparseMatrix *transformedSparseMatrix); CsrSparseMatrix *transformedSparseMatrix);
// cooSparseMatrixVectorMultiplication calculates the product of a
// CooSparseMatrix and a vector.
void cooSparseMatrixVectorMultiplication(CooSparseMatrix sparseMatrix, void cooSparseMatrixVectorMultiplication(CooSparseMatrix sparseMatrix,
double *vector, double **product, int vectorSize); double *vector, double **product, int vectorSize);
// destroyCooSparseMatrix frees all space used by the CooSparseMatrix.
void destroyCooSparseMatrix(CooSparseMatrix *sparseMatrix); void destroyCooSparseMatrix(CooSparseMatrix *sparseMatrix);
// printCooSparseMatrix prints the values of a CooSparseMatrix.
void printCooSparseMatrix(CooSparseMatrix sparseMatrix); void printCooSparseMatrix(CooSparseMatrix sparseMatrix);
#endif // COO_SPARSE_MATRIX_H #endif // COO_SPARSE_MATRIX_H

BIN
openmp/coo_sparse_matrix.o

Binary file not shown.

17
openmp/csr_sparse_matrix.c

@ -3,7 +3,7 @@
CsrSparseMatrix initCsrSparseMatrix() { CsrSparseMatrix initCsrSparseMatrix() {
CsrSparseMatrix sparseMatrix; CsrSparseMatrix sparseMatrix;
sparseMatrix.size = 0; sparseMatrix.size = 0;
sparseMatrix.numberOfNonZeroElements = 0; sparseMatrix.numberOfElements = 0;
sparseMatrix.values = NULL; sparseMatrix.values = NULL;
sparseMatrix.columnIndexes = NULL; sparseMatrix.columnIndexes = NULL;
@ -11,21 +11,23 @@ CsrSparseMatrix initCsrSparseMatrix() {
return sparseMatrix; return sparseMatrix;
} }
void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int numberOfElements) { void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int size, int numberOfElements) {
sparseMatrix->values = (double *) malloc(numberOfElements * sizeof(double)); sparseMatrix->values = (double *) malloc(numberOfElements * sizeof(double));
sparseMatrix->columnIndexes = (int *) malloc( sparseMatrix->columnIndexes = (int *) malloc(
numberOfElements * sizeof(int)); numberOfElements * sizeof(int));
sparseMatrix->rowCumulativeIndexes = (int *) malloc( sparseMatrix->rowCumulativeIndexes = (int *) malloc(
(numberOfElements + 1) * sizeof(int)); (size + 1) * sizeof(int));
for (int i=0; i<numberOfElements+1; ++i) { for (int i=0; i<size+1; ++i) {
sparseMatrix->rowCumulativeIndexes[i] = 0; sparseMatrix->rowCumulativeIndexes[i] = 0;
} }
sparseMatrix->size = numberOfElements;
sparseMatrix->size = size;
sparseMatrix->numberOfElements = numberOfElements;
} }
// Row indexes start from 0!
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row) { void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row) {
// Gets start and end indexes of the row's elements
int startIndex = sparseMatrix->rowCumulativeIndexes[row], int startIndex = sparseMatrix->rowCumulativeIndexes[row],
endIndex = sparseMatrix->rowCumulativeIndexes[row+1]; endIndex = sparseMatrix->rowCumulativeIndexes[row+1];
for (int i=startIndex; i<endIndex; ++i) { for (int i=startIndex; i<endIndex; ++i) {
@ -34,9 +36,8 @@ void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row) {
} }
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column) { void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column) {
for (int i=0; i<sparseMatrix->numberOfNonZeroElements; ++i){ for (int i=0; i<sparseMatrix->numberOfElements; ++i){
if(sparseMatrix->columnIndexes[i] == column){ if(sparseMatrix->columnIndexes[i] == column){
// Zeros out this element
sparseMatrix->values[i] = 0; sparseMatrix->values[i] = 0;
} }
} }

27
openmp/csr_sparse_matrix.h

@ -1,24 +1,47 @@
#ifndef CSR_SPARSE_MATRIX_H /* Include guard */ #ifndef CSR_SPARSE_MATRIX_H /* Include guard */
#define CSR_SPARSE_MATRIX_H #define CSR_SPARSE_MATRIX_H
/* ===== INCLUDES ===== */
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
/* ===== STRUCTURES ===== */
// A sparse matrix in compressed SparseRow format.
typedef struct csrSparseMatrix { typedef struct csrSparseMatrix {
int size, numberOfNonZeroElements; int size, numberOfElements;
int *rowCumulativeIndexes, *columnIndexes; int *rowCumulativeIndexes, *columnIndexes;
double *values; double *values;
} CsrSparseMatrix; } CsrSparseMatrix;
/* ===== FUNCTION DEFINITIONS ===== */
// initCsrSparseMatrix creates and initializes the members of a CsrSparseMatrix
// structure instance.
CsrSparseMatrix initCsrSparseMatrix(); CsrSparseMatrix initCsrSparseMatrix();
void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int numberOfElements);
// allocMemoryForCsr allocates memory for the elements of the matrix.
void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int size, int numberOfElements);
// zeroOutRow assigns a zero value to all the elements of a row in the matrix.
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row); void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row);
// zeroOutColumn assigns a zero value to all the elements of a column in the
// matrix.
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column); void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column);
// csrSparseMatrixVectorMultiplication calculates the product of a
// CsrSparseMatrix and a vector.
void csrSparseMatrixVectorMultiplication(CsrSparseMatrix sparseMatrix, void csrSparseMatrixVectorMultiplication(CsrSparseMatrix sparseMatrix,
double *vector, double **product, int vectorSize); double *vector, double **product, int vectorSize);
// destroyCsrSparseMatrix frees all space used by the CsrSparseMatrix.
void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix); void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix);
// printCsrSparseMatrix prints the values of a CsrSparseMatrix.
void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix); void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix);
#endif // CSR_SPARSE_MATRIX_H #endif // CSR_SPARSE_MATRIX_H

BIN
openmp/csr_sparse_matrix.o

Binary file not shown.

65
openmp/openmp_gs_pagerank.c

@ -0,0 +1,65 @@
#include <sys/time.h>
#include "openmp_gs_pagerank_functions.h"
struct timeval startwtime, endwtime;
int main(int argc, char **argv) {
CsrSparseMatrix transitionMatrix = initCsrSparseMatrix();
double *pagerankVector;
bool convergenceStatus;
Parameters parameters;
int maxIterationsForConvergence = 0;
parseArguments(argc, argv, &parameters);
initialize(&transitionMatrix, &pagerankVector, &parameters);
// Saves information about the dataset to the output file
{
FILE *outputFile;
outputFile = fopen(parameters.outputFilename, "w");
if (outputFile == NULL) {
printf("Error while opening the output file.\n");
exit(EXIT_FAILURE);
}
fprintf(outputFile, "Pagerank will run for the dataset %s\n"\
"Dataset contains %d pages with %d outlinks.\n",
parameters.graphFilename, parameters.numberOfPages, transitionMatrix.size);
fclose(outputFile);
}
// Starts wall-clock timer
gettimeofday (&startwtime, NULL);
int* iterations = (int *)malloc(parameters.numberOfPages*sizeof(int));
// Calculates pagerank
iterations = pagerank(&transitionMatrix, &pagerankVector,
&convergenceStatus, parameters, &maxIterationsForConvergence);
// Stops wall-clock timer
gettimeofday (&endwtime, NULL);
double seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
printf("%s wall clock time = %f\n","Pagerank (Gauss-Seidel method), serial implementation",
seq_time);
printf(ANSI_COLOR_YELLOW "\n----- RESULTS -----\n" ANSI_COLOR_RESET);
if (convergenceStatus) {
printf(ANSI_COLOR_GREEN "Pagerank converged after %d iterations!\n" \
ANSI_COLOR_RESET, maxIterationsForConvergence);
} else {
printf(ANSI_COLOR_RED "Pagerank did not converge after max number of" \
" iterations (%d) was reached!\n" ANSI_COLOR_RESET, maxIterationsForConvergence);
}
// Saves results to the output file
savePagerankToFile(parameters.outputFilename, iterations, pagerankVector,
parameters.numberOfPages, maxIterationsForConvergence);
free(pagerankVector);
destroyCsrSparseMatrix(&transitionMatrix);
}

170
openmp/serial_gs_pagerank_functions.c → openmp/openmp_gs_pagerank_functions.c

@ -1,12 +1,13 @@
/* ===== INCLUDES ===== */ /* ===== INCLUDES ===== */
#include "serial_gs_pagerank_functions.h" #include "openmp_gs_pagerank_functions.h"
#include <omp.h>
/* ===== CONSTANTS ===== */ /* ===== CONSTANTS ===== */
const char *ARGUMENT_CONVERGENCE_TOLERANCE = "-c"; const char *ARGUMENT_CONVERGENCE_TOLERANCE = "-c";
const char *ARGUMENT_MAX_ITERATIONS = "-m"; const char *ARGUMENT_MAX_ITERATIONS = "-m";
const char *ARGUMENT_DAMPING_FACTOR = "-a"; const char *ARGUMENT_DAMPING_FACTOR = "-a";
const char *ARGUMENT_THREADS_NUMBER = "-t";
const char *ARGUMENT_VERBAL_OUTPUT = "-v"; const char *ARGUMENT_VERBAL_OUTPUT = "-v";
const char *ARGUMENT_OUTPUT_HISTORY = "-h"; const char *ARGUMENT_OUTPUT_HISTORY = "-h";
const char *ARGUMENT_OUTPUT_FILENAME = "-o"; const char *ARGUMENT_OUTPUT_FILENAME = "-o";
@ -15,26 +16,31 @@ const int NUMERICAL_BASE = 10;
char *DEFAULT_OUTPUT_FILENAME = "pagerank_output"; char *DEFAULT_OUTPUT_FILENAME = "pagerank_output";
const int FILE_READ_BUFFER_SIZE = 4096; const int FILE_READ_BUFFER_SIZE = 4096;
const int CONVERGENCE_CHECK_ITERATION_PERIOD = 3; const int CONVERGENCE_CHECK_ITERATION_PERIOD = 2;
const int SPARSITY_INCREASE_ITERATION_PERIOD = 3; const int SPARSITY_INCREASE_ITERATION_PERIOD = 10;
/* ===== GLOBAL VARIABLES ====== */
int numberOfThreads;
/* ===== FUNCTIONS ===== */ /* ===== FUNCTIONS ===== */
int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector, int* pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
bool *convergenceStatus, Parameters parameters) { bool *convergenceStatus, Parameters parameters, int* maxIterationsForConvergence) {
// Variables declaration // Variables declaration
int iterations = 0, numberOfPages = parameters.numberOfPages; int numberOfPages = parameters.numberOfPages;
int *iterations;
double delta, *pagerankDifference, *previousPagerankVector, double delta, *pagerankDifference, *previousPagerankVector,
*convergedPagerankVector, *linksFromConvergedPagesPagerankVector; *convergedPagerankVector, *linksFromConvergedPagesPagerankVector;
CsrSparseMatrix originalTransitionMatrix = initCsrSparseMatrix();
CooSparseMatrix linksFromConvergedPages = initCooSparseMatrix(); CooSparseMatrix linksFromConvergedPages = initCooSparseMatrix();
bool *convergenceMatrix; bool *convergenceMatrix;
int P = omp_get_max_threads();
omp_set_num_threads(P);
// Space allocation // Space allocation
{ {
size_t sizeofDouble = sizeof(double); size_t sizeofDouble = sizeof(double);
// iterations until each page converged
iterations = (int *) malloc(numberOfPages * sizeof(int));
// pagerankDifference used to calculate delta // pagerankDifference used to calculate delta
pagerankDifference = (double *) malloc(numberOfPages * sizeofDouble); pagerankDifference = (double *) malloc(numberOfPages * sizeofDouble);
// previousPagerankVector holds last iteration's pagerank vector // previousPagerankVector holds last iteration's pagerank vector
@ -50,12 +56,22 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
*convergenceStatus = false; *convergenceStatus = false;
// Initialization // Initialization
allocMemoryForCoo(&linksFromConvergedPages, transitionMatrix->numberOfNonZeroElements); // originalTransitionMatrix used to run pagerank in phases
#pragma omp parallel for num_threads(P) allocMemoryForCsr(&originalTransitionMatrix, transitionMatrix->size, transitionMatrix->numberOfElements);
memcpy(originalTransitionMatrix.rowCumulativeIndexes, transitionMatrix->rowCumulativeIndexes,
(transitionMatrix->size+1) * sizeof(int));
memcpy(originalTransitionMatrix.columnIndexes, transitionMatrix->columnIndexes,
transitionMatrix->numberOfElements * sizeof(int));
memcpy(originalTransitionMatrix.values, transitionMatrix->values,
transitionMatrix->numberOfElements * sizeof(double));
allocMemoryForCoo(&linksFromConvergedPages, transitionMatrix->numberOfElements);
#pragma omp parallel for num_threads(numberOfThreads)
for (int i=0; i<numberOfPages; ++i) { for (int i=0; i<numberOfPages; ++i) {
convergedPagerankVector[i] = 0; convergedPagerankVector[i] = 0;
convergenceMatrix[i] = false; convergenceMatrix[i] = false;
linksFromConvergedPagesPagerankVector[i] = 0; linksFromConvergedPagesPagerankVector[i] = 0;
iterations[i] = 0;
} }
} }
@ -75,14 +91,14 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
if (parameters.history) { if (parameters.history) {
// Outputs pagerank vector to file // Outputs pagerank vector to file
savePagerankToFile(parameters.outputFilename, iterations != 0, savePagerankToFile(parameters.outputFilename, NULL, *pagerankVector,
*pagerankVector, numberOfPages, parameters.realIterations); numberOfPages, *maxIterationsForConvergence);
} }
// Periodically checks for convergence // Periodically checks for convergence
if (!(iterations % CONVERGENCE_CHECK_ITERATION_PERIOD)) { if (!((*maxIterationsForConvergence) % CONVERGENCE_CHECK_ITERATION_PERIOD)) {
// Builds pagerank vectors difference // Builds pagerank vectors difference
#pragma omp parallel for num_threads(P) #pragma omp parallel for num_threads(numberOfThreads)
for (int i=0; i<numberOfPages; ++i) { for (int i=0; i<numberOfPages; ++i) {
pagerankDifference[i] = (*pagerankVector)[i] - previousPagerankVector[i]; pagerankDifference[i] = (*pagerankVector)[i] - previousPagerankVector[i];
} }
@ -95,11 +111,13 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
} }
} }
++(*maxIterationsForConvergence);
// Periodically increases sparsity // Periodically increases sparsity
if (iterations && !(iterations % SPARSITY_INCREASE_ITERATION_PERIOD)) { if ((*maxIterationsForConvergence) && !(*maxIterationsForConvergence % SPARSITY_INCREASE_ITERATION_PERIOD)) {
bool *newlyConvergedPages = (bool *) malloc(numberOfPages * sizeof(bool)); bool *newlyConvergedPages = (bool *) malloc(numberOfPages * sizeof(bool));
// Checks each individual page for convergence // Checks each individual page for convergence
#pragma omp parallel for num_threads(P) #pragma omp parallel for num_threads(numberOfThreads)
for (int i=0; i<numberOfPages; ++i) { for (int i=0; i<numberOfPages; ++i) {
double difference = fabs((*pagerankVector)[i] - double difference = fabs((*pagerankVector)[i] -
previousPagerankVector[i]) / fabs(previousPagerankVector[i]); previousPagerankVector[i]) / fabs(previousPagerankVector[i]);
@ -110,9 +128,11 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
newlyConvergedPages[i] = true; newlyConvergedPages[i] = true;
convergenceMatrix[i] = true; convergenceMatrix[i] = true;
convergedPagerankVector[i] = (*pagerankVector)[i]; convergedPagerankVector[i] = (*pagerankVector)[i];
iterations[i] = *maxIterationsForConvergence;
} }
} }
#pragma omp parallel for num_threads(P)
#pragma omp parallel for num_threads(numberOfThreads)
for (int i=0; i<numberOfPages; ++i) { for (int i=0; i<numberOfPages; ++i) {
// Filters newly converged pages // Filters newly converged pages
if (newlyConvergedPages[i] == true) { if (newlyConvergedPages[i] == true) {
@ -132,10 +152,10 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
} }
} }
// Increases sparsity of the transition matrix by // Increases sparsity of the transition matrix by zeroing
// deleting elements that correspond to converged pages // out elements that correspond to converged pages
zeroOutRow(transitionMatrix, i); zeroOutRow(transitionMatrix, i);
zeroOutColumn(transitionMatrix, i); //zeroOutColumn(transitionMatrix, i);
// Builds the new linksFromConvergedPagesPagerankVector // Builds the new linksFromConvergedPagesPagerankVector
cooSparseMatrixVectorMultiplication(linksFromConvergedPages, cooSparseMatrixVectorMultiplication(linksFromConvergedPages,
@ -146,21 +166,29 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
free(newlyConvergedPages); free(newlyConvergedPages);
} }
++iterations; // Prunes the transition matrix every 8 iterations
if (*maxIterationsForConvergence != 0 && (*maxIterationsForConvergence%8 == 0)) {
memcpy(transitionMatrix->values, originalTransitionMatrix.values,
transitionMatrix->numberOfElements * sizeof(double));
#pragma omp parallel for num_threads(numberOfThreads)
for (int i=0; i<numberOfPages; ++i) {
convergedPagerankVector[i] = 0;
convergenceMatrix[i] = false;
linksFromConvergedPagesPagerankVector[i] = 0;
}
linksFromConvergedPages.numberOfNonZeroElements = 0;
}
// Outputs information about this iteration // Outputs information about this iteration
if (iterations%2) { if (parameters.verbose){
printf(ANSI_COLOR_BLUE "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, iterations, delta); if ((*maxIterationsForConvergence)%2) {
printf(ANSI_COLOR_BLUE "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, *maxIterationsForConvergence, delta);
} else { } else {
printf(ANSI_COLOR_CYAN "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, iterations, delta); printf(ANSI_COLOR_CYAN "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, *maxIterationsForConvergence, delta);
} }
} while (!*convergenceStatus && (parameters.maxIterations == 0 ||
iterations < parameters.maxIterations));
parameters.realIterations = iterations;
if (!parameters.history) {
// Outputs last pagerank vector to file
savePagerankToFile(parameters.outputFilename, false, *pagerankVector,
numberOfPages, parameters.realIterations);
} }
} while (!*convergenceStatus && (parameters.maxIterations == 0 ||
*maxIterationsForConvergence < parameters.maxIterations));
// Frees memory // Frees memory
free(pagerankDifference); free(pagerankDifference);
@ -181,6 +209,9 @@ int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
void initialize(CsrSparseMatrix *transitionMatrix, void initialize(CsrSparseMatrix *transitionMatrix,
double **pagerankVector, Parameters *parameters) { double **pagerankVector, Parameters *parameters) {
// Sets the number of threads to be used
omp_set_num_threads(numberOfThreads);
// Reads web graph from file // Reads web graph from file
if ((*parameters).verbose) { if ((*parameters).verbose) {
printf(ANSI_COLOR_YELLOW "----- Reading graph from file -----\n" ANSI_COLOR_RESET); printf(ANSI_COLOR_YELLOW "----- Reading graph from file -----\n" ANSI_COLOR_RESET);
@ -190,7 +221,8 @@ void initialize(CsrSparseMatrix *transitionMatrix,
// Outputs the algorithm parameters to the console // Outputs the algorithm parameters to the console
if ((*parameters).verbose) { if ((*parameters).verbose) {
printf(ANSI_COLOR_YELLOW "\n----- Running with parameters -----\n" ANSI_COLOR_RESET\ printf(ANSI_COLOR_YELLOW "\n----- Running with parameters -----\n" ANSI_COLOR_RESET\
"Number of pages: %d", (*parameters).numberOfPages); "Number of pages: %d"\
"\nNumber of threads: %d", (*parameters).numberOfPages, numberOfThreads);
if (!(*parameters).maxIterations) { if (!(*parameters).maxIterations) {
printf("\nMaximum number of iterations: inf"); printf("\nMaximum number of iterations: inf");
} else { } else {
@ -201,7 +233,7 @@ void initialize(CsrSparseMatrix *transitionMatrix,
"\nGraph filename: %s\n", (*parameters).convergenceCriterion, "\nGraph filename: %s\n", (*parameters).convergenceCriterion,
(*parameters).dampingFactor, (*parameters).graphFilename); (*parameters).dampingFactor, (*parameters).graphFilename);
} }
(*parameters).realIterations = 0;
// Allocates memory for the pagerank vector // Allocates memory for the pagerank vector
(*pagerankVector) = (double *) malloc((*parameters).numberOfPages * sizeof(double)); (*pagerankVector) = (double *) malloc((*parameters).numberOfPages * sizeof(double));
double webUniformProbability = 1. / (*parameters).numberOfPages; double webUniformProbability = 1. / (*parameters).numberOfPages;
@ -221,24 +253,22 @@ void calculateNextPagerank(CsrSparseMatrix *transitionMatrix,
double *linksFromConvergedPagesPagerankVector, double *linksFromConvergedPagesPagerankVector,
double *convergedPagerankVector, int vectorSize, double dampingFactor) { double *convergedPagerankVector, int vectorSize, double dampingFactor) {
// Calculates the web uniform probability once. // Calculates the web uniform probability once.
double webUniformProbability = 1. / vectorSize; double webUniformProbability = 1. / vectorSize;
csrSparseMatrixVectorMultiplication(*transitionMatrix, previousPagerankVector, csrSparseMatrixVectorMultiplication(*transitionMatrix, previousPagerankVector,
pagerankVector, vectorSize); pagerankVector, vectorSize);
#pragma omp parallel for
#pragma omp parallel for num_threads(4)
for (int i=0; i<vectorSize; ++i) { for (int i=0; i<vectorSize; ++i) {
(*pagerankVector)[i] = dampingFactor * (*pagerankVector)[i]; (*pagerankVector)[i] = dampingFactor * (*pagerankVector)[i];
} }
double normDifference = vectorNorm(previousPagerankVector, vectorSize) - double normDifference = vectorNorm(previousPagerankVector, vectorSize) -
vectorNorm(*pagerankVector, vectorSize); vectorNorm(*pagerankVector, vectorSize);
#pragma omp parallel for
for (int i=0; i<vectorSize; ++i) { for (int i=0; i<vectorSize; ++i) {
//(*pagerankVector)[i] += normDifference * webUniformProbability + (*pagerankVector)[i] += normDifference * webUniformProbability +
//linksFromConvergedPagesPagerankVector[i] + convergedPagerankVector[i]; linksFromConvergedPagesPagerankVector[i] + convergedPagerankVector[i];
(*pagerankVector)[i] += 0.5*normDifference* webUniformProbability +linksFromConvergedPagesPagerankVector[i] + convergedPagerankVector[i];
} }
} }
@ -261,13 +291,15 @@ double vectorNorm(double *vector, int vectorSize) {
* parseArguments parses the command line arguments given by the user. * parseArguments parses the command line arguments given by the user.
*/ */
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) { void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) {
if (argumentCount < 2 || argumentCount > 10) { if (argumentCount < 2 || argumentCount > 16) {
validUsage(argumentVector[0]); validUsage(argumentVector[0]);
} }
numberOfThreads = omp_get_max_threads();
(*parameters).numberOfPages = 0; (*parameters).numberOfPages = 0;
(*parameters).maxIterations = 0; (*parameters).maxIterations = 0;
(*parameters).convergenceCriterion = 1; (*parameters).convergenceCriterion = 0.001;
(*parameters).dampingFactor = 0.85; (*parameters).dampingFactor = 0.85;
(*parameters).verbose = false; (*parameters).verbose = false;
(*parameters).history = false; (*parameters).history = false;
@ -304,6 +336,15 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
(*parameters).dampingFactor = alphaInput; (*parameters).dampingFactor = alphaInput;
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_THREADS_NUMBER)) {
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
size_t threadsInput = strtol(argumentVector[argumentIndex], &endPointer, NUMERICAL_BASE);
if (threadsInput == 0 && endPointer) {
printf("Invalid iterations argument\n");
exit(EXIT_FAILURE);
}
numberOfThreads = threadsInput;
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_VERBAL_OUTPUT)) { } else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_VERBAL_OUTPUT)) {
(*parameters).verbose = true; (*parameters).verbose = true;
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_HISTORY)) { } else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_HISTORY)) {
@ -423,33 +464,27 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
// Calculates the outdegree of each page and assigns the uniform probability // Calculates the outdegree of each page and assigns the uniform probability
// of transition to the elements of the corresponding row // of transition to the elements of the corresponding row
int* pageOutdegree = malloc((*parameters).numberOfPages*sizeof(int)); int* pageOutdegree = malloc((*parameters).numberOfPages*sizeof(int));
for (int i=0; i<(*parameters).numberOfPages; ++i){ for (int i=0; i<(*parameters).numberOfPages; ++i){
pageOutdegree[i] = 0; pageOutdegree[i] = 0;
} }
for (int i=0; i<numberOfEdges; ++i) { for (int i=0; i<numberOfEdges; ++i) {
int currentRow = tempMatrix.elements[i]->rowIndex; int currentRow = tempMatrix.elements[i]->rowIndex;
if (currentRow == tempMatrix.elements[i]->rowIndex) {
++pageOutdegree[currentRow]; ++pageOutdegree[currentRow];
} }
}
for (int i=0; i<tempMatrix.size; ++i) { for (int i=0; i<tempMatrix.size; ++i) {
tempMatrix.elements[i]->value = 1./pageOutdegree[tempMatrix.elements[i]->rowIndex]; tempMatrix.elements[i]->value = 1./pageOutdegree[tempMatrix.elements[i]->rowIndex];
} }
free(pageOutdegree);
// Transposes the temporary transition matrix (P^T). // Transposes the temporary transition matrix (P^T).
transposeSparseMatrix(&tempMatrix); transposeSparseMatrix(&tempMatrix);
allocMemoryForCsr(transitionMatrix, numberOfEdges);
allocMemoryForCsr(transitionMatrix, (*parameters).numberOfPages, numberOfEdges);
// Transforms the temporary COO matrix to the desired CSR format // Transforms the temporary COO matrix to the desired CSR format
transformToCSR(tempMatrix, transitionMatrix); transformToCSR(tempMatrix, transitionMatrix);
//printCsrSparseMatrix(*transitionMatrix);
destroyCooSparseMatrix(&tempMatrix); destroyCooSparseMatrix(&tempMatrix);
fclose(graphFile); fclose(graphFile);
@ -486,27 +521,34 @@ int checkIncrement(int previousIndex, int maxIndex, char *programName) {
return ++previousIndex; return ++previousIndex;
} }
void savePagerankToFile(char *filename, bool append, double *pagerankVector, void savePagerankToFile(char *filename, int *iterationsUntilConvergence,
int vectorSize, int realIterations) { double *pagerankVector, int vectorSize, int iteration) {
FILE *outputFile; FILE *outputFile;
if (append) {
outputFile = fopen(filename, "a"); outputFile = fopen(filename, "a");
} else {
outputFile = fopen(filename, "w");
}
if (outputFile == NULL) { if (outputFile == NULL) {
printf("Error while opening the output file.\n"); printf("Error while opening the output file.\n");
return; return;
} }
//Save numberofPages and convergence time
fprintf(outputFile, "\n----- Iteration %d -----\n", iteration);
// Saves the pagerank vector
double sum = 0;
for (int i=0; i<vectorSize; ++i) {
sum += pagerankVector[i];
}
if (iterationsUntilConvergence == NULL){
for (int i=0; i<vectorSize; ++i) { for (int i=0; i<vectorSize; ++i) {
fprintf(outputFile, "%f ", pagerankVector[i]); fprintf(outputFile, "%d = %.10g\n", i, pagerankVector[i]/sum);
} }
fprintf(outputFile, "\n"); } else {
//fprintf(outputFile, "%d\t", vectorSize); for (int i=0; i<vectorSize; ++i) {
//fprintf(outputFile, "%d\t", realIterations); fprintf(outputFile, "%d\t%d\t%.10g\n", i, iterationsUntilConvergence[i],
pagerankVector[i]/sum);
}
}
fclose(outputFile); fclose(outputFile);
} }

18
openmp/serial_gs_pagerank_functions.h → openmp/openmp_gs_pagerank_functions.h

@ -1,5 +1,5 @@
#ifndef SERIAL_GS_PAGERANK_FUNCTIONS_H /* Include guard */ #ifndef OPENMP_GS_PAGERANK_FUNCTIONS_H /* Include guard */
#define SERIAL_GS_PAGERANK_FUNCTIONS_H #define OPENMP_GS_PAGERANK_FUNCTIONS_H
/* ===== INCLUDES ===== */ /* ===== INCLUDES ===== */
@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <omp.h>
#include "coo_sparse_matrix.h" #include "coo_sparse_matrix.h"
@ -27,6 +28,7 @@
extern const char *ARGUMENT_CONVERGENCE_TOLERANCE; extern const char *ARGUMENT_CONVERGENCE_TOLERANCE;
extern const char *ARGUMENT_MAX_ITERATIONS; extern const char *ARGUMENT_MAX_ITERATIONS;
extern const char *ARGUMENT_DAMPING_FACTOR; extern const char *ARGUMENT_DAMPING_FACTOR;
extern const char *ARGUMENT_THREADS_NUMBER;
extern const char *ARGUMENT_VERBAL_OUTPUT; extern const char *ARGUMENT_VERBAL_OUTPUT;
extern const char *ARGUMENT_OUTPUT_HISTORY; extern const char *ARGUMENT_OUTPUT_HISTORY;
extern const char *ARGUMENT_OUTPUT_FILENAME; extern const char *ARGUMENT_OUTPUT_FILENAME;
@ -41,7 +43,7 @@ extern const int FILE_READ_BUFFER_SIZE;
// A data structure to conveniently hold the algorithm's parameters. // A data structure to conveniently hold the algorithm's parameters.
typedef struct parameters { typedef struct parameters {
int numberOfPages, maxIterations, realIterations; int numberOfPages, maxIterations;
double convergenceCriterion, dampingFactor; double convergenceCriterion, dampingFactor;
bool verbose, history; bool verbose, history;
char *outputFilename, *graphFilename; char *outputFilename, *graphFilename;
@ -71,8 +73,8 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
// Function savePagerankToFile appends or overwrites the pagerank vector // Function savePagerankToFile appends or overwrites the pagerank vector
// "pagerankVector" to the file with the filename supplied in the arguments. // "pagerankVector" to the file with the filename supplied in the arguments.
void savePagerankToFile(char *filename, bool append, double *pagerankVector, void savePagerankToFile(char *filename, int *iterationsUntilConvergence,
int vectorSize, int realIterations); double *pagerankVector, int vectorSize, int iteration);
// Function initialize allocates memory for the pagerank vector, reads the // Function initialize allocates memory for the pagerank vector, reads the
// dataset from the file and creates the transition probability distribution // dataset from the file and creates the transition probability distribution
@ -92,7 +94,7 @@ void calculateNextPagerank(CsrSparseMatrix *transitionMatrix,
// Function pagerank iteratively calculates the pagerank of each page until // Function pagerank iteratively calculates the pagerank of each page until
// either the convergence criterion is met or the maximum number of iterations // either the convergence criterion is met or the maximum number of iterations
// is reached. // is reached.
int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector, int* pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector,
bool *convergenceStatus, Parameters parameters); bool *convergenceStatus, Parameters parameters, int* maxIterationsForConvergence);
#endif // SERIAL_GS_PAGERANK_FUNCTIONS_H #endif // OPENMP_GS_PAGERANK_FUNCTIONS_H

BIN
openmp/pagerank.out

Binary file not shown.

44
openmp/serial_gs_pagerank.c

@ -1,44 +0,0 @@
#include <sys/time.h>
#include <omp.h>
#include "serial_gs_pagerank_functions.h"
//#include "coo_sparse_matrix.h"
struct timeval startwtime, endwtime;
double seq_time;
int main(int argc, char **argv) {
CsrSparseMatrix transitionMatrix = initCsrSparseMatrix();
double *pagerankVector;
bool convergenceStatus;
Parameters parameters;
omp_set_dynamic(0);
parseArguments(argc, argv, &parameters);
initialize(&transitionMatrix, &pagerankVector, &parameters);
// Starts wall-clock timer
gettimeofday (&startwtime, NULL);
int iterations = pagerank(&transitionMatrix, &pagerankVector,
&convergenceStatus, parameters);
if (parameters.verbose) {
printf(ANSI_COLOR_YELLOW "\n----- RESULTS -----\n" ANSI_COLOR_RESET);
if (convergenceStatus) {
printf(ANSI_COLOR_GREEN "Pagerank converged after %d iterations!\n" \
ANSI_COLOR_RESET, iterations);
} else {
printf(ANSI_COLOR_RED "Pagerank did not converge after max number of" \
" iterations (%d) was reached!\n" ANSI_COLOR_RESET, iterations);
}
}
// Stops wall-clock timer
gettimeofday (&endwtime, NULL);
double seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
printf("%s wall clock time = %f\n","Pagerank (Gauss-Seidel method), serial implementation",
seq_time);
free(pagerankVector);
destroyCsrSparseMatrix(&transitionMatrix);
}

BIN
openmp/serial_gs_pagerank.o

Binary file not shown.

BIN
openmp/serial_gs_pagerank_functions.o

Binary file not shown.
Loading…
Cancel
Save