Recent Changes - Search:

edit SideBar

CodeGenerationAndMemoryLeaks

Information about how to track down memory leaks in the Ptolemy CG code generator.

Example

Generate code:

  $PTII/bin/ptcg  $PTII/ptolemy/cg/adapter/generic/program/procedural/c/mbed/adapters/ptolemy/vergil/actor/lib/demo/mbed/SimpleFSM.xml

Use valgrind to check for leaks:

bash-3.2$ valgrind --leak-check=full ~/cg/SimpleFSM
valgrind --leak-check=full ~/cg/SimpleFSM
==33900== Memcheck, a memory error detector
==33900== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==33900== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==33900== Command: /Users/cxh/cg/SimpleFSM
==33900==
1
0
1
1
0
...
==33900==
==33900== HEAP SUMMARY:
==33900== in use at exit: 40,321 bytes in 742 blocks
==33900== total heap usage: 3,525 allocs, 2,783 frees, 177,057 bytes allocated
==33900==
==33900== 528 bytes in 33 blocks are definitely lost in loss record 130 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x100001DBD: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:95)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)
==33900==
==33900== 528 bytes in 33 blocks are definitely lost in loss record 131 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x100001E10: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:104)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)
==33900==
==33900== 528 bytes in 33 blocks are definitely lost in loss record 132 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x100001E69: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:114)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)
==33900==
==33900== 1,600 bytes in 100 blocks are definitely lost in loss record 144 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x10000264F: SimpleFSM_Sequence3_fire (SimpleFSM_Sequence3.c:100)
==33900== by 0x100002AA5: AtomicActor_Iterate (_AtomicActor.c:53)
==33900== by 0x1000023B6: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:4)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)
==33900==
==33900== 1,600 bytes in 100 blocks are definitely lost in loss record 145 of 150
==33900== at 0x51B7: calloc (vg_replace_malloc.c:627)
==33900== by 0x100004CF2: FSMReceiver_Get (_FSMReceiver.c:57)
==33900== by 0x100005B69: IOPort_GetInside (_IOPort.c:269)
==33900== by 0x10000482C: FSMDirector_TransferOutputs1 (_FSMDirector.c:113)
==33900== by 0x100003F82: Director_TransferOutputs (_Director.c:259)
==33900== by 0x100001EB2: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:126)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900==
==33900== LEAK SUMMARY:
==33900== definitely lost: 4,784 bytes in 299 blocks
==33900== indirectly lost: 0 bytes in 0 blocks
==33900== possibly lost: 0 bytes in 0 blocks
==33900== still reachable: 10,274 bytes in 70 blocks
==33900== suppressed: 25,263 bytes in 373 blocks
==33900== Reachable blocks (those to which a pointer was found) are not shown.
==33900== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==33900==
==33900==
==33900== For counts of detected and suppressed errors, rerun with: -v
==33900== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 15 from 15)

First Leak

The first leak:

==33900== 528 bytes in 33 blocks are definitely lost in loss record 130 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x100001DBD: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:95)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)

The offending line in SimpleFSM_ModalModel_FSMTransitionCode.c:95 is marked below

        /* 2. Nonpreemptive Transition */
        /* Generate Transition Code. -adapter- */
        /* ptolemy/cg/adapter/generic/program/procedural/adapters/ptolemy/domains/modal/kernel/FSMActor.java */

        SimpleFSM_ModalModel___transitionFlag = 1;
        switch (SimpleFSM_ModalModel__Controller__currentState)
            {
            case SimpleFSM_ModalModel__Controller_state:

                {
--->                (*(toDisplay->sendLocalInside))((struct IOPort*) toDisplay, 0, Boolean_new2(true));
                    SimpleFSM_ModalModel__Controller__currentState = SimpleFSM_ModalModel__Controller_state2;

                }

                break;

Since Booleans can have only two values, then we could have just two structs, one for true, the other for false.

I hacked ptolemy/cg/kernel/generic/program/procedural/c/type/Boolean.c as below

/*** Boolean_new() ***/
// Boolean Tokens can only be true or false and              
// are immutable, so we have just two Booleans            
Token* Boolean_False;
Token* Boolean_True;
// make a new integer token from the given value.                                                                                                                            
Token* Boolean_new(boolean b) {
#define TWO_BOOLEANS
#ifdef TWO_BOOLEANS
    if (b) {
        if (Boolean_True == NULL) {
            Boolean_True = malloc(sizeof(Token));
            Boolean_True->type = TYPE_Boolean;
            Boolean_True->payload.Boolean = b;
        }
        return Boolean_True;
    } else {
        if (Boolean_False == NULL) {
            Boolean_False = malloc(sizeof(Token));
            Boolean_False->type = TYPE_Boolean;
            Boolean_False->payload.Boolean = b;
        }
        return Boolean_False;
    }
#else
    // This code mallocs a token each time  
    // it is called.                                  
    Token* result = malloc(sizeof(Token));
    result->type = TYPE_Boolean;
    result->payload.Boolean = b;
    return result;
#endif
}
/**/

However, when I run, I get warnings and not the same output as before:

./SimpleFSM
commons/_CompositeActor.c:116: CompositeActorFire():(1) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(2) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(3) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(4) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(5) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(6) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(7) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(8) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(9) director did not transfer inputs?.
commons/_CompositeActor.c:116: CompositeActorFire():(10) director did not transfer inputs?.
1
0
All Done

I checked in ptolemy/cg/kernel/generic/program/procedural/c/type/Boolean.c,

Action item. Update and then edit ptolemy/cg/kernel/generic/program/procedural/c/type/Boolean.c and uncomment

//#define TWO_BOOLEANS

Then track down the above messages and why only two outputs are generated

It seems like perhaps tokens are not being treated as immutable after all?

and then track down

Second from last leak

==33900== 1,600 bytes in 100 blocks are definitely lost in loss record 144 of 150
==33900== at 0x47E1: malloc (vg_replace_malloc.c:300)
==33900== by 0x100007A8C: Boolean_new (_ptTypes.c:118)
==33900== by 0x10000264F: SimpleFSM_Sequence3_fire (SimpleFSM_Sequence3.c:100)
==33900== by 0x100002AA5: AtomicActor_Iterate (_AtomicActor.c:53)
==33900== by 0x1000023B6: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:4)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x100001744: iterate (SimpleFSM_Main.c:47)
==33900== by 0x10000163F: main (SimpleFSM_Main.c:26)

The model runs for 100 iterations, so we are leaking in each iteration.

Line 100 of SimpleFSM_Sequence3.c is marked below

void SimpleFSM_Sequence3_fire(struct AtomicActor* actor) {
    if (SimpleFSM_Sequence3__currentIndex < 2) {
----->   (*(output->send))((struct IOPort*) output, 0, Boolean_new(/*CGH77*//*CGH77*/BooleanArray_get(SimpleFSM_Sequence3_values_ ,SimpleFSM_Sequence3__currentIndex)));
        SimpleFSM_Sequence3__outputProduced = true;
    };
    if (SimpleFSM_Sequence3__outputProduced) {
        SimpleFSM_Sequence3__outputProduced = false;
        SimpleFSM_Sequence3__currentIndex += 1;
        if (SimpleFSM_Sequence3__currentIndex >= 2) {
            if (true) {
                // Code for the case where repeat is true                                            
                SimpleFSM_Sequence3__currentIndex = 0;
            } else {
                // Code for the case where repeat is false                                    
                //To prevent overflow...  
                SimpleFSM_Sequence3__currentIndex = 2;
            }
        }
    }
}

Here, it looks like we are creating new tokens each time we the Sequence3 actor fires.

To get rid of this leak:

  1. Edit cg/commons/_ptTypes.c and create a Boolean_new2() function that does not allocate new tokens.
    Token* Boolean_new(boolean b) {
        // This code mallocs a token each time                                                                                                                                  
        // it is called.                                                                                                                                                        
        Token* result = malloc(sizeof(Token));
        result->type = TYPE_Boolean;
        result->payload.Boolean = b;
        return result;
    }
    // Boolean Tokens can only be true or false and                                                                                                                              
    // are immutable, so we have just two Booleans                                                                                                                              
    Token* Boolean_False;
    Token* Boolean_True;
    // make a new integer token from the given value.                                                                                                                            
    Token* Boolean_new2(boolean b) {
    #define TWO_BOOLEANS
    #ifdef TWO_BOOLEANS
  2. Update cg/commons/_ptTypes.h to declare Boolean_new2()
    Token* Boolean_new(boolean b);
    Token* Boolean_new2(boolean b);
    Token* Double_new(double d);
  3. Update cg/_SimpleFSM/SimpleFSM_Sequence3.c so that we call Boolean_new2():
    void SimpleFSM_Sequence3_fire(struct AtomicActor* actor) {
        if (SimpleFSM_Sequence3__currentIndex < 2) {
            (*(output->send))((struct IOPort*) output, 0, Boolean_new2(/*CGH77*//*CGH77*/BooleanArray_get(SimpleFSM_Sequence3_values_ ,SimpleFSM_Sequence3__currentIndex)));
            SimpleFSM_Sequence3__outputProduced = true;
        };
  4. Recompile and run
  5. That memory leak goes away.

This points to fixing the problem with commons/_CompositeActor.c:116: CompositeActorFire():(1) director did not transfer inputs?. above and having Boolean_new just return one of two predefined tokens and not instantiating a token each time.

This is a workaround, but could get things going.

Leak at the bottom

This leak:

==33900== 1,600 bytes in 100 blocks are definitely lost in loss record 145 of 150
==33900== at 0x51B7: calloc (vg_replace_malloc.c:627)
==33900== by 0x100004CF2: FSMReceiver_Get (_FSMReceiver.c:57)
==33900== by 0x100005B69: IOPort_GetInside (_IOPort.c:269)
==33900== by 0x10000482C: FSMDirector_TransferOutputs1 (_FSMDirector.c:113)
==33900== by 0x100003F82: Director_TransferOutputs (_Director.c:259)
==33900== by 0x100001EB2: SimpleFSM_ModalModel_makeTransitions (SimpleFSM_ModalModel_FSMTransitionCode.c:126)
==33900== by 0x100004407: FSMDirector_Fire (_FSMDirector.c:36)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)
==33900== by 0x1000030A5: CompositeActor_Iterate (_CompositeActor.c:144)
==33900== by 0x1000023CC: SimpleFSM_Schedule_iterate (SimpleFSM_SDFSchedule.c:5)
==33900== by 0x100008CB2: SDFDirector_Fire (_SDFDirector.c:70)
==33900== by 0x100002FE4: CompositeActor_Fire (_CompositeActor.c:131)

The model runs for 100 iterations, so we are leaking in each iteration.

Line 57 of cg/commons/_FSMReceiver.c is marked below:

Token* FSMReceiver_Get(struct FSMReceiver* r) {
    if (r->_token->type == -1) {
        fprintf(stderr, "No Token in the FSM Receiver : FSMReceiver_Get (_FSMReceiver.c)\n");
        exit(-1);
    }

    // FIXME: A memory leak.  
--> Token* retour = calloc(1, sizeof(Token));
    retour->type = r->_token->type;
    retour->payload = r->_token->payload;

    r->_token->type = -1;
    return retour;
}

What is happening here is that we are constantly creating tokens and they are never being deleted.

Probably the correct thing to do is reference counting.

This gets tricky, because it is hard to know when to delete something, but a rough algorithm would be to add a referenceCount field to Token and then when adding a Token to a pbl object, increase the referenceCount.

When pbl object is deleted, decrement the referenceCount of all contained Tokens and then, if the reference count of a Token is 0, call free on the token.

Another idea is to use the Boehm GC (http://www.hboehm.info/gc/), but I think that is too large.

Edit - History - Print - Recent Changes - Search
Page last modified on April 03, 2015, at 02:48 AM