Author Topic: Tiny Benchmark Test  (Read 34843 times)

0 Members and 1 Guest are viewing this topic.

Aurel

  • Guest
Re: Tiny Benchmark Test
« Reply #105 on: May 20, 2014, 10:26:37 AM »
-the basic principles of working with the Windows device context

Mike...
I have found this functions from net and some parts from Dlib userFunctions
and they are combinations of both.
So... from that point,do you can tell me is my function ok now
after adding DeleteObject,because i think that now work fine?

Yes Mike you are right about arguments which are strings.
But i see one strange thing in all this inside(interpreteed) loops with string
arguments.
There is no big difference if i have some calculations or some other executions
inside this loop...it looks to me that speed(time) depend of number of iteration.
Again ...maybe i am completely wrong .

Ok about Ed toy2 i will open new topic in interpreters..

Mike Lobanovsky

  • Guest
Re: Tiny Benchmark Test
« Reply #106 on: May 20, 2014, 11:28:12 AM »
So... from that point,do you can tell me is my function ok now after adding DeleteObject,because i think that now work fine?
Yes Aurel, if you are talking about the entire set of drawing functions in ruben2 after you added my corrections, then I can say that they are OK and they do not cause GDI leaks in this particular program.

In order to revise any other 3rd-party functions before you add them to ruben2, or create your own ones, just memorise a few simple rules of handling Windows device contexts and GDI objects:

1. Release the device contexts that you Get in your code when you are done working with them.

2. Delete the device contexts that you have Create'd when they are no longer needed.

3. Always store the GDI objects that are already present in your device contexts which you have Get'ed (gotten) or Create'd, whenever you use SelectObject() to add a new GDI object to a device context. The device contexts are never empty; even newly created DC's already have their default font, pen, brush, and 1x1 px BMP pre-selected into them.

4. Always restore the old GDI objects before you try to delete the new ones with a call to DeleteObject(). GDI objects including BMP's cannot be deleted if they are still selected into a DC.

5. Some drawing functions, e.g. FillRect(), don't need the respective GDI object (in this case, a brush) to be selected into the device context. Such a GDI object can and should be deleted directly with a call to DeleteObject() when it is no longer needed.

6. When deleting a device context, first re-select all the old GDI objects that you have changed with your calls to SelectObject() and only then delete the DC proper. There's no sense in trying to re-select anything into a DC that's already been deleted.

Simple, eh? :)

Quote
There is no big difference if i have some calculations or some other executions
inside this loop...it looks to me that speed(time) depend of number of iteration.
Again ...maybe i am completely wrong .
You simply can't see the real speed with which your integer tokens can run in a Select Case- or in a jump table-based loop as long as everything else works 100 times slower with string arguments. You have to change the entire concept of ruben3 to some decent 3rd-party prototype, perhaps, this toy2 proggy.

Quote
Ok about Ed toy2 i will open new topic in interpreters..
Yes, please do.

Charles Pegge

  • Guest
Re: Tiny Benchmark Test
« Reply #107 on: May 20, 2014, 11:12:21 PM »

Mike,

I picked up a few issues with the GC. Nothing major. Local string arrays were getting logged into the global GC list, instead of the local one.

And it will no longer be possible to call a function without assigning the result to a variable. (except for integer returns)

This is your test code, slightly modified. - Its a good test for string memory leakage.


Code: [Select]
$Filename "t.exe"
 Include "$/inc/RTL32.inc"
 Include "$/inc/console.inc"
#Lookahead

'String s = Space(2500)
 String s = String(2500,"A")
 

sys i
printl "Press key to begin" : waitkey
While i<1000
   s=Replace s, "A", "A"
   i++
   printl i
Wend
printl "Press key to end" : waitkey

Function Replace(String t, w, r) As String
   '
   Sys a, b, lw, lr, ls
   string s = t
   '
   ls = len(s)
   lw = Len(w)
   lr = Len(r)
   a = 1
   ' 
   Do
      if a>Len s then Exit Do
      a = InStr(a, s, w)
      If a = 0 Then Exit Do
      s = Left(s, a - 1) + r + Mid(s, a + lw)
      a += lr
   End Do
   Return s
End Function

http://www.oxygenbasic.org/o2zips/Oxygen.zip

Mike Lobanovsky

  • Guest
Re: Tiny Benchmark Test
« Reply #108 on: May 21, 2014, 03:18:41 AM »
Hi Charles,

Yes, your "Must assign to a variable" feature is cool! :D Works OK for both internal and external functions.

But garbage collection doesn't work for strings created in external modules. For example,

$Filename "test.exe"
Include "RTL32.inc"
#Lookahead

Declare Function Spaces Lib "test.dll" Alias "Spaces" (ByVal nBytes As Long) As String

String s

While 1
   s = Spaces(2500)
WEnd


would crash immediately with Spaces() implemented in an external test.dll module like this:

char* __stdcall __declspec(dllexport) Spaces(const int nBytes)
{
    char* s = (char*)malloc(nBytes+1);
    memset(s,0x20,nBytes);
    s[nBytes]=0;
    return s;
}


having exhausted the entire 2GB of XP process heap in a fraction of a second.

Do you think it might be reasonable to make the garbage collector guard against such weird cases as well?


.

Charles Pegge

  • Guest
Re: Tiny Benchmark Test
« Reply #109 on: May 21, 2014, 04:10:48 AM »
Hi Mike,

Yes, Oxygen assumes that returned char* (as from GetCommandLine)  are constants. It has no way of knowing how they were created, and therefore, if they are not constants, they must be handed back to the host system for recycling.

In your example, Oxygen first frees any content of s then copies from the returned char pointer, into s. The final content of s will be released by the GC. (at the end of eternity :) )

I think most libraries deliver their creations as handles, which are explicitly freed when finished with.

There is a more subtle problem to chew on:

Uninitialised member strings, must be logged to the correct garbage collection list. Since all Oxygen arrays and structures are lazy, if they are passed byref, the function must log any new strings to the global GC list by default. It cannot use its local GC list, or the string member would evaporate when the function terminates.

Mike Lobanovsky

  • Guest
Re: Tiny Benchmark Test
« Reply #110 on: May 21, 2014, 07:01:30 AM »
Thanks Charles,

Yes, I know my example was totally weird because nobody in his right senses would create a DLL like that. I did it simply to illustrate the idea and hear out your reasons why the GC shouldn't react to cases like that. :)