Search code examples
copenmp

Undefined behavior when exceeding a certain matrix length using C language and open MP


The C program reads a matrix and determines the average of a column and if that value has occurred in that column. It works with small matrices but it doesn't with medium and large Matrices. The results I get are random and changes from execution to another even if the input is the same. The sequential version works fine. Also is there an equivalent of the C++ collapse directive in C? I got no errors or warnings

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

// user call the application from the command line and 
// inputs the length of the square array and the name of the input file

int main(int argc, char **argv)
{
    int ii,i, sum = 0, newi = 0, k = 0;
    int n, I, J;
    int L;
    L = atoi(argv[1]);
    int size;
    size = L * L;
    newi = size;
    char *str = NULL;
    double *d = NULL;
    double **ptr;
    ptr = &(d);
    str = (char *)malloc(sizeof(char)*size);
    d = (double*)malloc(sizeof(double)*size);
    FILE *fp = argc > 1 ? fopen(argv[2], "r") : stdin;
    FILE *fptr = NULL;
    float local_sum, *avg;
    int matches2;
    if (!fp)
    {  //validate file open for reading 
        fprintf(stderr, "error: file open failed '%s'.\n", argv[2]);
        return 1;
    }

    for (i = 1;i < argc;i++)
    {
        while (fscanf(fp, "%s", str) != EOF)
        {
            sscanf(str, "%lf", &d[k]);//storing the values as double in a vector 
            k++;
        }
    }
    if (fp != stdin) fclose(fp);   // close file if not stdin 

    printf("number of elements in the file is %d\n", newi);
    printf("number of elements in  a row is %d\n", L);

    int r = L;
    float **arr = (float **)malloc(r * sizeof(float *));
    int w = 0;
    for (i = 0; i < r; i++)
        arr[i] = (float *)malloc(r * sizeof(float));

    avg = (float *)malloc(L * sizeof(float *));
    //#pragma omp parallel for // This didn't work 
    for (i = 0; i < L; i++)
    {
        int j = 0;
        //#pragma omp parallel for reduction (+:w) // This didn't work 
        for ( j = 0; j < L; j++)
        {
            arr[i][j] = d[w];
            //printf("  %lf  %d \n  \n ", arr[i][j],w);
            w += 1;
        }
    }
    // 1 ) finding the average of each column
    // 2 ) comparing the indivual values to the average
    // 3 ) writing the matching results
    // 1 ) finding the average of each column

    int j ;


    //#pragma omp parallel for 
    for (j = 0; j < L; j++)
    {
        local_sum = 0;
        #pragma omp parallel for shared (local_sum)
        for (i = 0; i < L; i++)
        {
            local_sum += arr[i][j];
            // no data dependency or a race condition
            //printf("local sum is %lf\n", local_sum);//delete
            //printf("Hello from thread %d of %d in local summation \n ", omp_get_thread_num(), omp_get_num_threads());
        }
        //control       printf("local sum is %lf\n", local_sum);//delete                                                
        avg[j] = local_sum / L;// every j is unique to the running threads and there's no race condition 
        // 2 )comparing the indivual values to the average
        int matches = 0;
        #pragma omp parallel for  shared(matches)
            for (i = 0; i < L; i++)
            {  
                if (arr[i][j] == avg[j])
                    matches++;
                    //printf("Hello from thread %d of %d in matches calculation now is %d \n ", omp_get_thread_num(), omp_get_num_threads(),matches);
                }
                //fclose(fp);

                //control       printf("matches are  %d\n", matches);

        // 3 )writing the results
            matches2 = matches;

        omp_set_dynamic(0);

        #pragma omp parallel firstprivate(matches2) num_threads(1)
        
        {
            if (matches2 >= 1)

            {

                printf("we have a match in column %d  the value matches the average of elements in the column.(%d time/s) \n", j, matches2);
                // creating the output file and opening it to Write without deleting previous results
                fptr = fopen("D:\\OutputfromFile.txt", "a");
                //fptr = fopen(*argv[3], "a"); This did not work ! 
                fprintf(fptr, "We have a match in column %d ", j);// writing results to the file
                fprintf(fptr, " , we matched  %d time/s\n", matches2);// writing results to the file
                //printf("Hello from thread %d of %d \n ", omp_get_thread_num(), omp_get_num_threads());
            }

            else
            {
                //if (j+1==L)continue;
                //control           printf("we have no matches ");
                // creating the output file and opening it to Write without deleting previous results
                fptr = fopen("D:\\OutputfromFile.txt", "a");
                fprintf(fptr, "We have no matches ");// writing results to the file 
                //fprintf(fptr, " , we matched  %d time/s\n", matches);// writing results to the file
                //break;
            }
        }
    }
    fclose(fptr);
}

Solution

  • The code now works fine

    1. I moved the writing to the file outside the parallel region.
    2. made the outermost loop parallel instead of the nested ones.
    3. made sure to remove any dependencies ( I could think of )and initialize variables inside the parallel loop.
    4. handled the file opening process and potential failure properly
    5. if I missed something please let me know.
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <omp.h>
    
    int main(int argc, char **argv)
    {
        int ii, i, sum = 0, newi = 0, k = 0;
        int n, I, J;
        int L;
        L = atoi(argv[1]);
        int size;
        size = L * L;
        newi = size;
        char *str = NULL;
        double  *d = NULL;
        double  **ptr;
        ptr = &(d);
        str = (char *)malloc(sizeof(char)*size);
        if (str == NULL) printf(" str memory allocation failed ");
        d = (double *)malloc(sizeof(double)*size);
        if (d == NULL) printf("  double  memory allocation failed ");
        FILE *fp = argc > 1 ? fopen(argv[2], "r") : stdin;
        FILE *fptr = NULL;
        double   local_sum, *avg;
        int matches2;
        int *filearraymatches, *filearraytimes;
        filearraymatches = (int  *)malloc(L * sizeof(int  *));
        filearraytimes = (int  *)malloc(L * sizeof(int  *));
    
        if (!fp)
        {  //validate file open for reading 
            fprintf(stderr, "error: file open failed '%s'.\n", argv[2]);
            return 1;
        }
    
    
    
        for (i = 1;i < argc;i++)
        {
            while (fscanf(fp, "%s", str) != EOF)
            {
                //printf("%s\n", str);//just checking 
                sscanf(str, "%lf", &d[k]);//storing the values as  double  in a vector 
                k++;
            }
    
    
        }
    
    
        if (fp != stdin) fclose(fp);   // close file if not stdin 
    
        printf("number of elements in the file is %d\n", newi);
        printf("number of elements in  a row is %d\n", L);
    
        int r = L;
        double  **arr = (double  **)malloc(r * sizeof(double  *));
        int w = 0;
        for (i = 0; i < r; i++)
        arr[i] = (double  *)malloc(r * sizeof(double));
        avg = (double*)calloc(L, sizeof(double));
    
    
    #pragma omp parallel for default(none)//there is no race condition the variables are all independent 
        for (i = 0; i < L; i++)
        {
            int j = 0;
            
            for (j = 0; j < L; j++)
            {
                arr[i][j] = d[i*L+j];
                w += 1;
                
            }
            
        }
    
        // 1 ) finding the average of each column
        // 2 ) comparing the individual values to the average
        // 3 ) writing the matching results
    
    // 1 ) finding the average of each column
        int j;
        int matches = 0;
    #pragma omp parallel for private(local_sum) private(matches)  private(i) default(none) 
    
        for (j = 0; j < L; j++)
        {
            matches = 0;
            local_sum = 0;
    
            for (i = 0; i < L; i++)
            {
                local_sum += arr[i][j];
                // no data dependency or a race condition
                //printf("local sum is %lf\n", local_sum);//delete
                //printf("Hello from thread %d of %d in local summation \n ", omp_get_thread_num(), omp_get_num_threads());
    
            }   
                                                
            avg[j] = local_sum /(double) L;// every j is unique to the running threads and there's no race condition 
            //printf("local average is %lf\n", avg[j]);//correct calculation 
    
    
    // 2 )comparing the individual values to the average
            for (i = 0; i < L; i++)
            {
                if (arr[i][j] == avg[j]) 
                { matches++; 
                //printf("Hello from thread %d of %d in matches calculation now is %d \n ", omp_get_thread_num(), omp_get_num_threads(), matches);
                //printf("matches are %d \n", matches);
                }
                //else printf("matches are %d \n  the element is %lf while the average is :%lf", matches, arr[i][j], avg[j]);
        
                    ;//printf("Hello from thread %d of %d in matches we don't have a match  matches:  %d \n ", omp_get_thread_num(), omp_get_num_threads(), matches);
                //printf("avg[%d]= %lf \n", i, avg[i]);
                //printf("arr[i][j] =  %lf , average is %lf \n", arr[i][j], avg[j]);
                    
                //printf("\n***********************matches are  %d\n", matches);
                
            }
    // 3 )writing the results
            if (matches >0)
            {
                filearraymatches[j] = j;
                filearraytimes[j] = matches;
                //printf("we have a match in column %d  the value matches the average of elements in the column.(%d time/s the average in the column is %lf ) \n", j, matches, avg[j]);
    
            }
            else
            {
                filearraymatches[j] = 0;
                filearraytimes[j] = 0;
            }
    
        }
    
        char *path = argv[3];// Output file is a parameter
        // Writing results to the file 
        //fptr = fopen(path, "W");//assertion error
        fptr = fopen(path, "w");
        if (fptr == NULL)
        {
            perror(path);
            printf("   fileerror  ");
            exit(EXIT_FAILURE);
        }
           
        for (int i = 0;i < L;i++)
        {
                if (filearraytimes[i] != 0)
                {
                    fprintf(fptr, "We have a match in column %d ", i);// writing results to the file
                    fprintf(fptr, " , we matched  %d time/s\n", filearraytimes[i]);// writing results to the file
                }
                else fprintf(fptr, " We have no matches in this column %d \n",i);// writing results to the file 
        }
            fclose(fptr);
    }