Author Topic: atoms-family Bricscad (missed values)  (Read 3817 times)

0 Members and 1 Guest are viewing this topic.

Peter Guappa

  • Guest
atoms-family Bricscad (missed values)
« on: December 13, 2011, 01:49:31 PM »
To check my variabless, I sometimes use the' Missed Values' routine from thread: http://www.theswamp.org/index.php?topic=30256.msg358398#msg358398

It works great in Autocad, but when I use it in Bricscad it still returns ALL variables.

Anyone an idea why?

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #1 on: December 13, 2011, 03:39:32 PM »
It seems that BC handles the atom-family in a different manner. Every variable, whether declared as local or not, is added to the atom-family when the lisp file is loaded!

After only loading this file:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / A20111213-2131 B20111213-2131)
  2.   (foreach X20111213-2131 '(0 1 2 3)
  3.     (print X20111213-2131)
  4.   )
  5.   (setq A20111213-2131 1)
  6.   (setq B20111213-2131 "A")
  7.   (setq C20111213-2131 "xyz")
  8. )
  9.  

You get these results:
Code: [Select]
(CAR (MEMBER "A20111213-2131" (atoms-family 1))) => "A20111213-2131"
(CAR (MEMBER "B20111213-2131" (atoms-family 1))) => "B20111213-2131"
(CAR (MEMBER "C20111213-2131" (atoms-family 1))) => "C20111213-2131"
(CAR (MEMBER "X20111213-2131" (atoms-family 1))) => "X20111213-2131"

I have tried using (gc) multiple times but that doesn't solve this.

Strange...

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #2 on: December 14, 2011, 03:50:51 AM »
It's probably that BC's lisp interpreter doesn't handle variable localizations correctly. A bit of a bug if you ask me! It could cause huge problems in the long run.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #3 on: December 14, 2011, 05:01:51 AM »
@irneb:
Your assumption is of course incorrect: Bricscad's lisp engine is very good.

To continue with my previous post:
After loading the lisp file (again before running the function)
Code: [Select]
!A20111213-2131 => nil
!B20111213-2131 => nil
!C20111213-2131 => nil
!X20111213-2131 => nil

After running the function:
Code: [Select]
!A20111213-2131 => nil
!B20111213-2131 => nil
!C20111213-2131 => "xyz"
!X20111213-2131 => nil

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #4 on: December 14, 2011, 06:10:10 AM »
@irneb:
Your assumption is of course incorrect: Bricscad's lisp engine is very good.
Fine, I was simply commenting on the fact you actually mentioned that these symbols are still listed as in memory even after the defun completed and you forced garbage collection "multiple times". To me that sounds dangerous, even though it does seem to set each local var's value to nil.

As a test, what happens with a global (or external) variable's value if it's reused as local? Test code:
Code: [Select]
(foreach n '(1 2 3 4 5 6) (set (read (strcat "Test" (itoa n))) nil))
(gc)
(setq Test1 "Global value 1"
      Test2 "Global value 2"
      Test3 "Global value 3"
)

(defun ShowTestValues (/ atom-list Name Sym Val)
  (setq atom-list (atoms-family 1))
  (setq n 0)
  (princ "\n(Name Symbol Value)\n---------------------------------------------")
  (foreach n '(1 2 3 4 5 6)
    (princ "\n")
    (setq Name (strcat "TEST" (itoa n))
          Sym  (car (member Name atom-list))
          Val  (eval (read Name))
    )
    (prin1 (list Name Sym Val))
  )
  (princ "\n---------------------------------------------")
  (princ)
)

(defun RunTest1 (/ Test1 Test2 Test4 Test6)
  (princ "\n\nLocal in RunTest1 before setting variables.")
  (ShowTestValues)
  (foreach n '(1 2 3 4 5 6)
    (set (read (strcat "TEST" (itoa n))) (strcat "RunTest1 local value " (itoa n)))
  )
  (princ "\n\nLocal in RunTest1 after setting variables.")
  (ShowTestValues)
)

(defun RunTest2 (/ Test1 Test3 Test5 Test6)
  (princ "\n\nLocal in RunTest2 before setting variables.")
  (ShowTestValues)
  (foreach n '(1 2 3 4 5 6)
    (set (read (strcat "TEST" (itoa n))) (strcat "RunTest2 local value " (itoa n)))
  )
  (princ "\n\nLocal in RunTest2 after setting variables, but before calling RunTest1.")
  (ShowTestValues)
  (RunTest1)
  (princ "\n\nLocal in RunTest2 after calling RunTest1.")
  (ShowTestValues)
)

(princ "\n\nGlobal before calling defuns.")
(ShowTestValues)
(RunTest1)
(princ "\n\nGlobal after calling RunTest1.")
(ShowTestValues)
(RunTest2)
(princ "\n\nGlobal after calling RunTest2.")
(ShowTestValues)
Results when run in Vanilla 2012 on W7-64:
Code: [Select]
Global before calling defuns.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "Global value 2")
("TEST3" "TEST3" "Global value 3")
("TEST4" nil nil)
("TEST5" nil nil)
("TEST6" nil nil)
---------------------------------------------

Local in RunTest1 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" nil nil)
("TEST2" nil nil)
("TEST3" "TEST3" "Global value 3")
("TEST4" nil nil)
("TEST5" nil nil)
("TEST6" nil nil)
---------------------------------------------

Local in RunTest1 after setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest1 local value 1")
("TEST2" "TEST2" "RunTest1 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest1 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest1 local value 6")
---------------------------------------------

Global after calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "Global value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" nil nil)
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" nil nil)
---------------------------------------------

Local in RunTest2 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" nil nil)
("TEST2" "TEST2" "Global value 2")
("TEST3" nil nil)
("TEST4" nil nil)
("TEST5" nil nil)
("TEST6" nil nil)
---------------------------------------------

Local in RunTest2 after setting variables, but before calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest2 local value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest2 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest2 local value 5")
("TEST6" "TEST6" "RunTest2 local value 6")
---------------------------------------------

Local in RunTest1 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" nil nil)
("TEST2" nil nil)
("TEST3" "TEST3" "RunTest2 local value 3")
("TEST4" nil nil)
("TEST5" "TEST5" "RunTest2 local value 5")
("TEST6" nil nil)
---------------------------------------------

Local in RunTest1 after setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest1 local value 1")
("TEST2" "TEST2" "RunTest1 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest1 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest1 local value 6")
---------------------------------------------

Local in RunTest2 after calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest2 local value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest2 local value 6")
---------------------------------------------

Global after calling RunTest2.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" nil nil)
---------------------------------------------
Notice Test1 sticks to its Global value at the end since it's localized everywhere. And Test6 even disappears from the global attoms-family without GC, since it's localized as well. It's not only cleared to nil at the end of each defun, but also removed from RAM.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #5 on: December 14, 2011, 07:21:13 AM »
Results using Bricscad 12.1.8:
Code: [Select]
Global before calling defuns.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "Global value 2")
("TEST3" "TEST3" "Global value 3")
("TEST4" "TEST4" NIL)
("TEST5" "TEST5" NIL)
("TEST6" "TEST6" NIL)
---------------------------------------------

Local in RunTest1 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" NIL)
("TEST2" "TEST2" NIL)
("TEST3" "TEST3" "Global value 3")
("TEST4" "TEST4" NIL)
("TEST5" "TEST5" NIL)
("TEST6" "TEST6" NIL)
---------------------------------------------

Local in RunTest1 after setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest1 local value 1")
("TEST2" "TEST2" "RunTest1 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest1 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest1 local value 6")
---------------------------------------------

Global after calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "Global value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" NIL)
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" NIL)
---------------------------------------------

Local in RunTest2 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" NIL)
("TEST2" "TEST2" "Global value 2")
("TEST3" "TEST3" NIL)
("TEST4" "TEST4" NIL)
("TEST5" "TEST5" NIL)
("TEST6" "TEST6" NIL)
---------------------------------------------

Local in RunTest2 after setting variables, but before calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest2 local value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest2 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest2 local value 5")
("TEST6" "TEST6" "RunTest2 local value 6")
---------------------------------------------

Local in RunTest1 before setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" NIL)
("TEST2" "TEST2" NIL)
("TEST3" "TEST3" "RunTest2 local value 3")
("TEST4" "TEST4" NIL)
("TEST5" "TEST5" "RunTest2 local value 5")
("TEST6" "TEST6" NIL)
---------------------------------------------

Local in RunTest1 after setting variables.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest1 local value 1")
("TEST2" "TEST2" "RunTest1 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest1 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest1 local value 6")
---------------------------------------------

Local in RunTest2 after calling RunTest1.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "RunTest2 local value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" "RunTest2 local value 6")
---------------------------------------------

Global after calling RunTest2.
(Name Symbol Value)
---------------------------------------------
("TEST1" "TEST1" "Global value 1")
("TEST2" "TEST2" "RunTest2 local value 2")
("TEST3" "TEST3" "RunTest1 local value 3")
("TEST4" "TEST4" "RunTest2 local value 4")
("TEST5" "TEST5" "RunTest1 local value 5")
("TEST6" "TEST6" NIL)
---------------------------------------------

Apart from the atoms-family issue previously discussed, everything seems OK to me.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #6 on: December 14, 2011, 10:06:34 AM »
OK, so it seem the effect is the same. Doesn't seem to have an issue with localized variables.

It's just that BC doesn't clear the symbol name from the atoms-family. Strange! Does that list simply keep on growing throughout a session? Is there no way of removing all the nil symbols from such list?
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #7 on: December 15, 2011, 03:36:29 AM »
Does that list simply keep on growing throughout a session? Is there no way of removing all the nil symbols from such list?
I don't know the answer to both questions. If the atoms-family is just a list of strings I am not terribly worried about the size of the list.

Note:
Code: [Select]
(type atoms-family) => SUBR (not: LIST)If I look at the atoms-family after adding a few atoms, I find that they seem to be inserted at random. So my guess is that the return value from (atoms-family) is a list representation of something different.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #8 on: December 15, 2011, 04:04:25 AM »
If I look at the atoms-family after adding a few atoms, I find that they seem to be inserted at random. So my guess is that the return value from (atoms-family) is a list representation of something different.
Yes in nearly every single Lisp interpreter a list of symbols is kept in ram. This is to help with the garbage collection. Basically as soon as a symbol is created, it's added to that list which then associates a pointer to the value's position in ram. Then the garbage collection happens periodically (simplest method would be to run through the list testing each symbol to see if it's still defined and used, if not free the ram associated and remove from list). If it never gets removed from that list then you literally have a memory leak, i.e. some of the ram never gets freed even though it's no longer used.

It's one of the bugs FireFox (and other Mozilla programs) has been battling with for years. The longer you keep it running the more ram it uses. I.e. you need to close the program down to free the ram - not ideal in the least.

If it's simply that the list doesn't clear the name of the symbol, then it's not too bad. Though still using a slight bit of unecessary ram to store the symbol name. Though it does make later garbage collections less efficient than they may have been, since they go through already cleared symbol checks again and again. No biggie, since GB only happens during idle cycles - but you can see possible slow downs if you forge a GB.

If the list is still referring to the pointer and the value stored in RAM is simply set to nil, then you have a much bigger issue - and your memory leak could become disastrous.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #9 on: December 15, 2011, 04:20:29 AM »
Just to clarify (since my previous explanation is rather simplistic): The "list" of symbol names is not a list directly exposed inside the interpreter. It's part of the interpreter's internal program. The atoms-family function is simply exposing the names from that list. The list contains much more than just the names, it also contains type definitions and pointers to the RAM.

The way localized variables are handled in AutoLisp is each item in the atoms list has a structure known as a stack instead of simply space for a pointer. A stack basically means a list which can only be added to (called push) / removed from (called pop) at it's head. Whenever a defun declares a locak variable, the atoms list is checked if such already exists. If not it just creates a new one, if it already exists then a new ram position pointer is pushed onto that symbol's stack. When the defun which created the local var completes that symbol's stack gets inspected, the RAM pointed to by the pointer freed, and the pointer poped from the stack. If sych stack then becomes empty the symbol item is removed from the atoms list.

My "worry" with BC is seeing as it never removes the symbol name from the atoms list, all I can say for sure is the value returned when inspecting such variable is nil. That doesn't mean the RAM is cleared at all, since the value nil could still be saved somewhere in RAM. Or perhaps nil is defined as a null pointer, in which case it might not be as bad. The point is I don't know, and the list not being cleared makes me very itchy to say the least.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #10 on: December 15, 2011, 07:12:51 AM »
Irneb, thank you for that explanation. The point you are making is an important one. I will file a SR (support request) with Bricscad. Maybe they are willing to shed some light on this.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8855
  • AKA Daniel
Re: atoms-family Bricscad (missed values)
« Reply #11 on: December 15, 2011, 09:44:55 AM »
I'm pretty sure that the lisp engine doesn't leak out pointers.   :police:
It's probably using some sort of memory pool that gets collected when there is a bit of pressure built up. Its probably pretty advanced stuff  :wink: 

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #12 on: December 23, 2011, 06:36:58 AM »
To recap:

The problem with the (atoms-family) function in Bricscad has been fixed.

Quote from: SR response by Bricscad's Torsten Moses
... but for sure, that (problem) never triggered any memory consumption problem.
...
Basically, Lisp engine uses a reserved memory area of ~ 128 MB (see (mem) function) - that area is split into Page + Heap area ... but both sections can dynamically grow + shrink. This reserved area is not available for any other code running in Bricscad - so it is like a "static section".

Theoretically, if a Lisp program needs more than 128 MB code + data, it could run out of memory, but it never happened, even with largest applications.

But if so, there is a LispEx.cfg file installed which allows to manually setup the max-memory-limit.

Besides these few details, Lisp engine's memory handling is quite complex, but also extremely fast (because of that reserved area) ... also the GarbageCollection is very advanced and very fast - compared to ACad AutoLISP :-)

Note: The fix is not included in the latest Bricscad version (V12.1.10).
« Last Edit: December 23, 2011, 07:04:09 AM by roy_043 »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: atoms-family Bricscad (missed values)
« Reply #13 on: January 17, 2012, 03:27:09 AM »
The (atoms-family) fix is included in BC V12.1.12.
The BC results for the test in irneb's post #4 now match those listed in that post.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: atoms-family Bricscad (missed values)
« Reply #14 on: January 17, 2012, 06:16:28 AM »
Well, I'll be d@*** ... if Adesk got such a support ticket, you'd be lucky to still be alive if they ever "fixed" it!  :lmao: It seems BricSys actually listens to their clients!
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.