darkautism / lfqueue

Minimize lock-free queue ever!
Do What The F*ck You Want To Public License
131 stars 27 forks source link

Memory Leak while using valgrind #4

Closed Taymindis closed 6 years ago

Taymindis commented 6 years ago

==14613== Memcheck, a memory error detector ==14613== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==14613== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==14613== Command: ./a.out ==14613== Using 16 threads. Total time = 90.838795 seconds ==14613== ==14613== HEAP SUMMARY: ==14613== in use at exit: 64,000,000 bytes in 16,000,000 blocks ==14613== total heap usage: 32,000,020 allocs, 16,000,020 frees, 576,010,048 bytes allocated ==14613== ==14613== 12 bytes in 3 blocks are possibly lost in loss record 1 of 2 ==14613== at 0x4C29C23: malloc (vg_replace_malloc.c:299) ==14613== by 0x40091F: worker (in /home/booking/cground/lfqueue/a.out) ==14613== by 0x4E3DDD4: start_thread (in /usr/lib64/libpthread-2.17.so) ==14613== by 0x5150B3C: clone (in /usr/lib64/libc-2.17.so) ==14613== ==14613== 63,999,988 bytes in 15,999,997 blocks are definitely lost in loss record 2 of 2 ==14613== at 0x4C29C23: malloc (vg_replace_malloc.c:299) ==14613== by 0x40091F: worker (in /home/booking/cground/lfqueue/a.out) ==14613== by 0x4E3DDD4: start_thread (in /usr/lib64/libpthread-2.17.so) ==14613== by 0x5150B3C: clone (in /usr/lib64/libc-2.17.so) ==14613== ==14613== LEAK SUMMARY: ==14613== definitely lost: 63,999,988 bytes in 15,999,997 blocks ==14613== indirectly lost: 0 bytes in 0 blocks ==14613== possibly lost: 12 bytes in 3 blocks ==14613== still reachable: 0 bytes in 0 blocks ==14613== suppressed: 0 bytes in 0 blocks ==14613== ==14613== For counts of detected and suppressed errors, rerun with: -v ==14613== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Test program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
#include <sys/time.h>
#include "lfq.h"

struct lfq_ctx ctx;
struct timeval  tv1, tv2;
// lfstack_t results;

void *worker(void *);
void *worker(void *arg)
{
    long long i = 0;
    int *int_data;
    while (i < 1000000) {
        int_data = (int*) malloc(sizeof(int));
        assert(int_data != NULL);
        *int_data = i++;

        /*Enqueue*/
        while (lfq_enqueue(&ctx, int_data) != 0);

        /*Dequeue*/
        while ( (int_data = lfq_dequeue(&ctx)) != 0);

        // printf("%d\n", *int_data);
        free(int_data);

    }

    return NULL;
}

int main(void)
{   
    int nthreads = sysconf(_SC_NPROCESSORS_ONLN); // Linux
    int i;

    lfq_init(&ctx, nthreads);

    /* Spawn threads. */
    pthread_t threads[nthreads];
    printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s");
    gettimeofday(&tv1, NULL);
    for (i = 0; i < nthreads; i++)
        pthread_create(threads + i, NULL, worker, NULL);

    for (i = 0; i < nthreads; i++)
        pthread_join(threads[i], NULL);
     gettimeofday(&tv2, NULL);
    printf ("Total time = %f seconds\n",
         (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
         (double) (tv2.tv_sec - tv1.tv_sec));

    lfq_clean(&ctx);
    return 0;
}
darkautism commented 6 years ago

Hi Taymindis,

Thanks your report. I add memory barrier in this code can prevent this bug.

This memory barrier must in outside lfq_dequeue. I trying to add memory barrier into lfq_dequeue will no helpful.

I'll add a macro in header file make it easy to use.

Edit

 /*Dequeue*/
//while ( (int_data = lfq_dequeue(&ctx)) != 0);
do {
    int_data = lfq_dequeue(&ctx);
    __sync_synchronize();
} while(int_data == 0);

Test program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
#include <sys/time.h>
#include "lfq.h"

struct lfq_ctx ctx;
struct timeval  tv1, tv2;
// lfstack_t results;

void *worker(void *);
void *worker(void *arg)
{
    long long i = 0;
    int *int_data;
    while (i < 1000000) {
        int_data = (int*) malloc(sizeof(int));
        assert(int_data != NULL);
        *int_data = i++;

        /*Enqueue*/
        while (lfq_enqueue(&ctx, int_data) != 0);

        /*Dequeue*/
        //while ( (int_data = lfq_dequeue(&ctx)) != 0);
        do {
        int_data = lfq_dequeue(&ctx);
        __sync_synchronize();
        } while(int_data == 0);

        // printf("%d\n", *int_data);
        free(int_data);

    }

    return NULL;
}

int main(void)
{   
    int nthreads = sysconf(_SC_NPROCESSORS_ONLN); // Linux
    int i;

    lfq_init(&ctx, nthreads);

    /* Spawn threads. */
    pthread_t threads[nthreads];
    printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s");
    gettimeofday(&tv1, NULL);
    for (i = 0; i < nthreads; i++)
        pthread_create(threads + i, NULL, worker, NULL);

    for (i = 0; i < nthreads; i++)
        pthread_join(threads[i], NULL);
     gettimeofday(&tv2, NULL);
    printf ("Total time = %f seconds\n",
         (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
         (double) (tv2.tv_sec - tv1.tv_sec));

    lfq_clean(&ctx);
    return 0;
}