Pypy CFFI内存管理问题

时间:2019-02-08 19:43:45

标签: c pypy multiprocess cffi

T试图通过添加一些c函数来加快我的Pypy代码的速度。问题是,内存使用率一直在增加!我看到了一些有关该主题的文章,并尝试进行简单的测试来说明这一点。在下面的测试中,我可以根据这篇文章(Python CFFI memory management issues)释放内存,但是我的代码像这样崩溃:free():下一个大小无效(正常)。看来我释放了内存...

有人可以帮助我解决我的问题吗?

import gc
from cffi import FFI
from time import sleep
import execnet
ffibuilder = FFI()


Create_TypeStructure = """
typedef struct _STRUCT1
    {
        int Data1;
        int Data2;
        int Data3;
        double Data4;
        double Data5;
        double Data6;
        double Data7;
        double Data8;

    }STRUCT1, *PSTRUCT1;
"""

Create_DataStructure = """
PSTRUCT1 CreateDataStructure()
 {
     PSTRUCT1 pStruct1 = ( PSTRUCT1 ) malloc( sizeof( STRUCT1 )*6000 );
     SetDummyValues(&pStruct1);
     if(pStruct1 != NULL) printf("SECOND TEST: ptr is not null/n");
     else printf("SECOND TEST: ptr is null/n");
     return pStruct1;
 }
"""

Set_DummyValues = """
void SetDummyValues( PSTRUCT1 ptr )
    {
        ptr = NULL;
    }
"""

Free_DataStructure = """
 void FreeDataStructure(PSTRUCT1 ptr) 
    {
        free(ptr);
    }  
"""


Some_Function = """
PSTRUCT1 SomeCFunction(STRUCT1 *p) 
    {

        int tmp=-1;
        int numline = 5999;

        while (tmp < numline) 
        {
        tmp++ ;
        {
            p[tmp].Data1 = 1000000;
            p[tmp].Data2 = 1000000;
            p[tmp].Data3 = 1000000;
            p[tmp].Data4 = 2125585.265;
            p[tmp].Data5 = 2125585.265;
            p[tmp].Data6 = 2125585.265;
            p[tmp].Data7 = 2125585.265;
            p[tmp].Data8 = 2125585.265;
        }

        }

        return p;
    }


"""

ffibuilder.cdef(Create_TypeStructure) #declare strucutres
ffibuilder.cdef('PSTRUCT1 CreateDataStructure();') #declare function 
ffibuilder.cdef('void FreeDataStructure(PSTRUCT1 ptr);') #declare function
ffibuilder.cdef('PSTRUCT1 SomeCFunction(PSTRUCT1 ptr);') #declare function
ffibuilder.cdef('void SetDummyValues(PSTRUCT1 pStruct1);') #declare function

ffibuilder.set_source("c", Create_TypeStructure + Set_DummyValues + Create_DataStructure + Free_DataStructure + Some_Function )
ffibuilder.compile(verbose=True)
from c import ffi, lib


def worker_process(channel):
    # Import modules
    import gc
    from time import sleep
    import execnet
    from c import ffi, lib
    # task processor, sits on each CPU
    channel.send("ready")

    for x in channel:
        if x is None:  # we can shutdown
                break
        data_list = {}
        for i in range(15000):  
            # Create a pointer to the data structure and tell the garbage collector how to destroy it
            gc_c_pDataStructure = ffi.gc( lib.CreateDataStructure(), lib.FreeDataStructure )
            lib.SomeCFunction( gc_c_pDataStructure )  # Populate the data structure
            data_list[i]= gc_c_pDataStructure # Store some data 
            #lib.FreeDataStructure(data_list[i])

        for i in range(15000):
            lib.FreeDataStructure(data_list[i])

        #sleep(15)
        channel.send("Ok!")


numberOfTasks = 500 # simulations to launch
workerCount = 1 # CPUs
group = execnet.Group()
for i in range(workerCount):  # CPUs
    group.makegateway()



# execute taskprocessor everywhere
mch = group.remote_exec(worker_process)

# get a queue that gives us results
q = mch.make_receive_queue(endmarker="Stop")


tasks = range(numberOfTasks)  # a list of tasks, here just integers


terminated = 0

while 1:
    channel, item = q.get()
    if item == "Stop":
        terminated += 1
        print "Terminated task on channel %s" % channel.gateway.id
    if terminated == len(mch):
        print "Got all results, Finish!"
        break
        continue
    if item != "ready":
        print "%s: Terminated: %s" % (channel.gateway.id, item)
    if not tasks:
        print "No tasks remain, sending termination request to all"
        mch.send_each(None)
        tasks = -1
    if tasks and tasks != -1:
        task = tasks.pop()
        channel.send(task)
        print "Sent task %r to channel %s" % (task, channel.gateway.id)

group.terminate()

1 个答案:

答案 0 :(得分:0)

我的解决方案:强制Pypy垃圾收集器工作并删除手动释放。同样也不需要将指针设置为NULL。

import gc
from cffi import FFI
from time import sleep
import execnet
ffibuilder = FFI()
import __pypy__


Create_TypeStructure = """
typedef struct _STRUCT1
    {
        int Data1;
        int Data2;
        int Data3;
        double Data4;
        double Data5;
        double Data6;
        double Data7;
        double Data8;

    }STRUCT1, *PSTRUCT1;
"""

Create_DataStructure = """
PSTRUCT1 CreateDataStructure()
 {
     PSTRUCT1 pStruct1 = ( PSTRUCT1 ) malloc( sizeof( STRUCT1 )*6000 );
     return pStruct1;
 }
"""


Free_DataStructure = """
 void FreeDataStructure(PSTRUCT1 ptr) 
    {
        free(ptr);
    }  
"""


Some_Function = """
PSTRUCT1 SomeCFunction(STRUCT1 *p) 
    {

        int tmp=-1;
        int numline = 5999;

        while (tmp < numline) 
        {
        tmp++ ;
        {
            p[tmp].Data1 = 1000000;
            p[tmp].Data2 = 1000000;
            p[tmp].Data3 = 1000000;
            p[tmp].Data4 = 2125585.265;
            p[tmp].Data5 = 2125585.265;
            p[tmp].Data6 = 2125585.265;
            p[tmp].Data7 = 2125585.265;
            p[tmp].Data8 = 2125585.265;
        }

        }

        return p;
    }


"""

ffibuilder.cdef(Create_TypeStructure) #declare strucutres
ffibuilder.cdef('PSTRUCT1 CreateDataStructure();') #declare function 
ffibuilder.cdef('void FreeDataStructure(PSTRUCT1 ptr);') #declare function
ffibuilder.cdef('PSTRUCT1 SomeCFunction(PSTRUCT1 ptr);') #declare function

ffibuilder.set_source("c", Create_TypeStructure + Create_DataStructure + Free_DataStructure + Some_Function )
ffibuilder.compile(verbose=True)
from c import ffi, lib


def worker_process(channel):
    # Import modules
    import gc
    from time import sleep
    import execnet
    from c import ffi, lib
    import __pypy__
    # task processor, sits on each CPU
    channel.send("ready")

    for x in channel:
        if x is None:  # we can shutdown
                break
        data_list = {}
        for i in range(5000):  
            # Create a pointer to the data structure and tell the garbage collector how to destroy it
            gc_c_pDataStructure = ffi.gc( lib.CreateDataStructure(), lib.FreeDataStructure )
            __pypy__.add_memory_pressure(6000)
            lib.SomeCFunction( gc_c_pDataStructure )  # Populate the data structure
            data_list[i]= gc_c_pDataStructure # Store some data 
            #lib.FreeDataStructure(data_list[i])

        #for i in range(5000):
            #lib.FreeDataStructure(data_list[i])

        #sleep(15)
        channel.send("Ok!")


numberOfTasks = 500 # simulations to launch
workerCount = 3 # CPUs
group = execnet.Group()
for i in range(workerCount):  # CPUs
    group.makegateway()



# execute taskprocessor everywhere
mch = group.remote_exec(worker_process)

# get a queue that gives us results
q = mch.make_receive_queue(endmarker="Stop")


tasks = range(numberOfTasks)  # a list of tasks, here just integers


terminated = 0

while 1:
    channel, item = q.get()
    if item == "Stop":
        terminated += 1
        print "Terminated task on channel %s" % channel.gateway.id
        if terminated == len(mch):
            print "Got all results, Finish!"
            break
        continue
    if item != "ready":
        print "%s: Terminated: %s" % (channel.gateway.id, item)
    if not tasks:
        print "No tasks remain, sending termination request to all"
        mch.send_each(None)
        tasks = -1
    if tasks and tasks != -1:
        task = tasks.pop()
        channel.send(task)
        print "Sent task %r to channel %s" % (task, channel.gateway.id)

group.terminate()