Author Topic: MY-BASIC  (Read 109295 times)

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #135 on: January 26, 2016, 10:31:41 AM »
Here is the Script BASIC version for reference.

FYI: The Script BASIC version is doing 510 iterations compared to the MyBASIC version only doing 128. This was run on a fairly old laptop and nowhere close to the screaming machine you ran your test on. I gave it a try at 128 iterations and execution time only dropped by 2 10ths of a second.



Code: ScriptBasic
  1. ' ScriptBasic GFX - Mandelbrot
  2.  
  3. IMPORT gfx.inc
  4.  
  5. s = gfx::Window(640,480,"ScriptBasic GFX Mandelbrot")
  6. ts = gfx::Time()
  7. FOR y = 0 TO 479
  8.   FOR x = 0 TO 639
  9.     cx = (x - 320) / 120
  10.     cy = (y - 240) / 120
  11.     rit = gfx::Mandelbrot(cx, cy, 510)
  12.     gfx::PixelRGBA s, x, y, rit * 12, rit * 8, rit * 4, 255
  13.   NEXT
  14. NEXT
  15. te = gfx::Time()
  16. gfx::stringColor s, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0x000000ff
  17. gfx::Update
  18. WHILE gfx::KeyName(1) <> "+escape"
  19. WEND
  20. gfx::Close
  21.  
« Last Edit: January 26, 2016, 03:12:38 PM by John »

wangrenxin

  • Guest
Re: MY-BASIC
« Reply #136 on: January 26, 2016, 06:28:41 PM »
John, that sounds so attractive that I can't refuse to read the source code of SB.

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #137 on: January 26, 2016, 07:16:49 PM »
John, that sounds so attractive that I can't refuse to read the source code of SB.

It's a good read.  :)

Before you dig into the source, here is the same (128 iterations) but the Mandelbrot function is written in Script BASIC rather than C.

@Markus - You can drastically reduce the time if you don't update your canvas with each pixel. Just wait until the end and update it at one time, then grab your end time.



Code: ScriptBasic
  1. ' ScriptBasic GFX - Mandelbrot
  2.  
  3. IMPORT gfx.inc
  4.  
  5. FUNCTION Mandelbrot(cx, cy, iter)
  6.   LOCAL zx, zy, tp
  7.   zx = .0
  8.   zy = .0
  9.   tp = .0
  10.   WHILE zx * zx + zy * zy < 4 AND iter > 0
  11.     tp = zx * zx - zy * zy + cx
  12.     zy = 2 * zx * zy + cy
  13.     zx = tp
  14.     iter = iter - 1
  15.   WEND
  16.   Mandelbrot = iter
  17. END FUNCTION
  18.  
  19. s = gfx::Window(640,480,"Script BASIC SDL_gfx Mandelbrot")
  20. ts = gfx::Time()
  21. FOR y = 0 TO 479
  22.   FOR x = 0 TO 639
  23.     cx = (x - 320) / 120
  24.     cy = (y - 240) / 120
  25.     rit = Mandelbrot(cx, cy, 128)
  26.     gfx::PixelRGBA s, x, y, rit * 32, rit * 16, rit * 8, 255
  27.   NEXT
  28. NEXT
  29. te = gfx::Time()
  30. gfx::stringColor s, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0x000000ff
  31. gfx::Update
  32. WHILE gfx::KeyName(1) <> "+escape"
  33. WEND
  34. gfx::Close
  35.  
« Last Edit: January 26, 2016, 07:51:33 PM by John »

Offline Cybermonkey342

  • BASIC Developer
  • Posts: 34
Re: MY-BASIC
« Reply #138 on: January 28, 2016, 09:05:08 AM »
Hi Markus,

The mandelbrot sample code came along with AllegroBASIC takes ~63 seconds on my i7 PC. Then I modified the code by commenting all graphics related lines, it costs almost the same duration. After that I tried to port it to a MY-BASIC shell version without graphics as well, it takes only ~15 seconds. I guess you were not using the memory pool, I recommend you to add a pool to optimize the memory performance of small chucks, since a simple implementation can even improve it more than 4 times faster. You can search for _open_mem_pool, mb_set_memory_manager(_pop_mem, _push_mem), _close_mem_pool() in shell/main.c to find my implementation.

MY-BASIC shell version without graphics:
Code: [Select]
miter=128
zm=120
time1=ticks()
for y=0 to 479
  for x=0 to 639
    zx=0
    zy=0
    cx= (x-320)/zm
    cy= (y-240)/zm
    i = miter
  while (zx*zx+zy*zy <4) and (i >0)
    tmp = zx * zx - zy * zy + cx
    zy = 2 * zx * zy + cy
    zx = tmp
    i=i-1
  wend
  next
next
time2=ticks()
time=(time2-time1)/1000
print time, " seconds.";
input
Yes, I don't use a memory pool, this looked too complicated for a C beignner ... maybe I can use your implementation of shell/main.c?

Okay, I tried your implementation, but can't compile it whether with TCC nor with GCC:
Quote
tcc: error: undefined symbol 'MB_SIZEOF_LST'
tcc: error: undefined symbol 'MB_SIZEOF_DCT'
« Last Edit: January 28, 2016, 10:05:22 AM by Cybermonkey342 »

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #139 on: January 28, 2016, 12:17:38 PM »
Quote
Yes, I don't use a memory pool, this looked too complicated for a C beignner ...

I have to agree, memory management and garbage collection shouldn't be part the MyBASIC API and handled transparently.

wangrenxin

  • Guest
Re: MY-BASIC
« Reply #140 on: January 28, 2016, 11:21:24 PM »
@Markus, I simplified it by modifying the constant part:

Code: C
  1.  
  2. /*
  3. ** {========================================================
  4. ** Memory manipulation
  5. */
  6.  
  7. static const size_t _SIZEOF_4BYTES = 4;
  8. static const size_t _SIZEOF_8BYTES = 8;
  9. static const size_t _SIZEOF_32BYTES = 32;
  10. static const size_t _SIZEOF_64BYTES = 64;
  11. static const size_t _SIZEOF_128BYTES = 128;
  12. static const size_t _SIZEOF_256BYTES = 256;
  13. static const size_t _SIZEOF_512BYTES = 512;
  14.  
  15. typedef unsigned _pool_chunk_size_t;
  16.  
  17. typedef union _pool_tag_t {
  18.         _pool_chunk_size_t size;
  19.         void* ptr;
  20. } _pool_tag_t;
  21.  
  22. typedef struct _pool_t {
  23.         size_t size;
  24.         char* stack;
  25. } _pool_t;
  26.  
  27. static int pool_count = 0;
  28.  
  29. static _pool_t* pool = 0;
  30.  
  31. static long alloc_count = 0;
  32. static long alloc_bytes = 0;
  33. static long in_pool_count = 0;
  34. static long in_pool_bytes = 0;
  35.  
  36. static long _POOL_THRESHOLD_COUNT = 0;
  37. static long _POOL_THRESHOLD_BYTES = 1024 * 1024 * 32;
  38.  
  39. #define _POOL_NODE_ALLOC(size) (((char*)malloc(sizeof(_pool_tag_t) + size)) + sizeof(_pool_tag_t))
  40. #define _POOL_NODE_PTR(s) (s - sizeof(_pool_tag_t))
  41. #define _POOL_NODE_NEXT(s) (*((void**)(s - sizeof(_pool_tag_t))))
  42. #define _POOL_NODE_SIZE(s) (*((_pool_chunk_size_t*)(s - sizeof(_pool_tag_t))))
  43. #define _POOL_NODE_FREE(s) do { free(_POOL_NODE_PTR(s)); } while(0)
  44.  
  45. static int _cmp_size_t(const void* l, const void* r) {
  46.         size_t* pl = (size_t*)l;
  47.         size_t* pr = (size_t*)r;
  48.  
  49.         if(*pl > *pr) return 1;
  50.         else if(*pl < *pr) return -1;
  51.         else return 0;
  52. }
  53.  
  54. static void _tidy_mem_pool(bool_t force) {
  55.         int i = 0;
  56.         char* s = 0;
  57.  
  58.         if(!force) {
  59.                 if(_POOL_THRESHOLD_COUNT > 0 && in_pool_count < _POOL_THRESHOLD_COUNT)
  60.                         return;
  61.  
  62.                 if(_POOL_THRESHOLD_BYTES > 0 && in_pool_bytes < _POOL_THRESHOLD_BYTES)
  63.                         return;
  64.         }
  65.  
  66.         if(!pool_count)
  67.                 return;
  68.  
  69.         for(i = 0; i < pool_count; i++) {
  70.                 while((s = pool[i].stack)) {
  71.                         pool[i].stack = (char*)_POOL_NODE_NEXT(s);
  72.                         _POOL_NODE_FREE(s);
  73.                 }
  74.         }
  75.  
  76.         in_pool_count = 0;
  77.         in_pool_bytes = 0;
  78. }
  79.  
  80. static void _open_mem_pool(void) {
  81. #define N 7
  82.         size_t szs[N];
  83.         size_t lst[N];
  84.         int i = 0;
  85.         int j = 0;
  86.         size_t s = 0;
  87.  
  88.         pool_count = 0;
  89.  
  90.         szs[i++] = _SIZEOF_4BYTES;
  91.         szs[i++] = _SIZEOF_8BYTES;
  92.         szs[i++] = _SIZEOF_32BYTES;
  93.         szs[i++] = _SIZEOF_64BYTES;
  94.         szs[i++] = _SIZEOF_128BYTES;
  95.         szs[i++] = _SIZEOF_256BYTES;
  96.         szs[i++] = _SIZEOF_512BYTES;
  97.  
  98.         mb_assert(i == N);
  99.  
  100.         memset(lst, 0, sizeof(lst));
  101.  
  102.         /* Find all unduplicated sizes */
  103.         for(i = 0; i < N; i++) {
  104.                 s = szs[i];
  105.                 for(j = 0; j < N; j++) {
  106.                         if(!lst[j]) {
  107.                                 lst[j] = s;
  108.                                 pool_count++;
  109.  
  110.                                 break;
  111.                         } else if(lst[j] == s) {
  112.                                 break;
  113.                         }
  114.                 }
  115.         }
  116.         qsort(lst, pool_count, sizeof(lst[0]), _cmp_size_t);
  117.  
  118.         pool = (_pool_t*)malloc(sizeof(_pool_t) * pool_count);
  119.         for(i = 0; i < pool_count; i++) {
  120.                 pool[i].size = lst[i];
  121.                 pool[i].stack = 0;
  122.         }
  123. #undef N
  124. }
  125.  
  126. static void _close_mem_pool(void) {
  127.         int i = 0;
  128.         char* s = 0;
  129.  
  130.         if(!pool_count)
  131.                 return;
  132.  
  133.         for(i = 0; i < pool_count; i++) {
  134.                 while((s = pool[i].stack)) {
  135.                         pool[i].stack = (char*)_POOL_NODE_NEXT(s);
  136.                         _POOL_NODE_FREE(s);
  137.                 }
  138.         }
  139.  
  140.         free((void*)pool);
  141.         pool = 0;
  142.         pool_count = 0;
  143. }
  144.  
  145. static char* _pop_mem(unsigned s) {
  146.         int i = 0;
  147.         _pool_t* pl = 0;
  148.         char* result = 0;
  149.  
  150.         ++alloc_count;
  151.         alloc_bytes += s;
  152.  
  153.         if(pool_count) {
  154.                 for(i = 0; i < pool_count; i++) {
  155.                         pl = &pool[i];
  156.                         if(s <= pl->size) {
  157.                                 if(pl->stack) {
  158.                                         in_pool_count--;
  159.                                         in_pool_bytes -= (long)(_pool_chunk_size_t)s;
  160.  
  161.                                         /* Pop from stack */
  162.                                         result = pl->stack;
  163.                                         pl->stack = (char*)_POOL_NODE_NEXT(result);
  164.                                         _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  165.  
  166.                                         return result;
  167.                                 } else {
  168.                                         /* Create a new node */
  169.                                         result = _POOL_NODE_ALLOC(pl->size);
  170.                                         if((intptr_t)result == sizeof(_pool_tag_t)) {
  171.                                                 result = 0;
  172.                                         } else {
  173.                                                 _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  174.                                         }
  175.  
  176.                                         return result;
  177.                                 }
  178.                         }
  179.                 }
  180.         }
  181.  
  182.         /* Allocate directly */
  183.         result = _POOL_NODE_ALLOC(s);
  184.         if((intptr_t)result == sizeof(_pool_tag_t)) {
  185.                 result = 0;
  186.         } else {
  187.                 _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  188.         }
  189.  
  190.         return result;
  191. }
  192.  
  193. static void _push_mem(char* p) {
  194.         int i = 0;
  195.         _pool_t* pl = 0;
  196.  
  197.         if(--alloc_count < 0) {
  198.                 mb_assert(0 && "Multiple free.");
  199.         }
  200.         alloc_bytes -= _POOL_NODE_SIZE(p);
  201.  
  202.         if(pool_count) {
  203.                 for(i = 0; i < pool_count; i++) {
  204.                         pl = &pool[i];
  205.                         if(_POOL_NODE_SIZE(p) <= pl->size) {
  206.                                 in_pool_count++;
  207.                                 in_pool_bytes += _POOL_NODE_SIZE(p);
  208.  
  209.                                 /* Push to stack */
  210.                                 _POOL_NODE_NEXT(p) = pl->stack;
  211.                                 pl->stack = p;
  212.  
  213.                                 _tidy_mem_pool(false);
  214.  
  215.                                 return;
  216.                         }
  217.                 }
  218.         }
  219.  
  220.         /* Free directly */
  221.         _POOL_NODE_FREE(p);
  222. }
  223.  
  224. /* ========================================================} */
  225.  
  226.  

@John, But contexts are totally different from different users with C/C++, thus there's no one-fits-all memory pool solution, that's why C/C++ libs often accept customized memory allocator.
« Last Edit: January 28, 2016, 11:40:32 PM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #141 on: January 28, 2016, 11:45:22 PM »
Wang,

The forum has syntax highlighting for most of the popular languages. Just use a [code=c] for syntax highlighting. (see change to your above example)

wangrenxin

  • Guest
Re: MY-BASIC
« Reply #142 on: January 29, 2016, 04:12:17 AM »
The forum has syntax highlighting for most of the popular languages. Just use a [code=c] for syntax highlighting. (see change to your above example)

Wow, that is prettier and easier to read.

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #143 on: January 29, 2016, 08:55:08 PM »
Can MyBASIC be embedded in itself?

Here is an example of Script BASIC being embedded in itself.
Here is the same but multi-threaded.

wangrenxin

  • Guest
Re: MY-BASIC
« Reply #144 on: January 30, 2016, 01:42:35 AM »
Looks interesting. I shall give MB the ability to load and run nested MB code when I made a decision to introduce COROUTINE to MB.

Offline Cybermonkey342

  • BASIC Developer
  • Posts: 34
Re: MY-BASIC
« Reply #145 on: February 05, 2016, 01:57:10 PM »
@Markus, I simplified it by modifying the constant part:

Code: C
  1.  
  2. /*
  3. ** {========================================================
  4. ** Memory manipulation
  5. */
  6.  
  7. static const size_t _SIZEOF_4BYTES = 4;
  8. static const size_t _SIZEOF_8BYTES = 8;
  9. static const size_t _SIZEOF_32BYTES = 32;
  10. static const size_t _SIZEOF_64BYTES = 64;
  11. static const size_t _SIZEOF_128BYTES = 128;
  12. static const size_t _SIZEOF_256BYTES = 256;
  13. static const size_t _SIZEOF_512BYTES = 512;
  14.  
  15. typedef unsigned _pool_chunk_size_t;
  16.  
  17. typedef union _pool_tag_t {
  18.         _pool_chunk_size_t size;
  19.         void* ptr;
  20. } _pool_tag_t;
  21.  
  22. typedef struct _pool_t {
  23.         size_t size;
  24.         char* stack;
  25. } _pool_t;
  26.  
  27. static int pool_count = 0;
  28.  
  29. static _pool_t* pool = 0;
  30.  
  31. static long alloc_count = 0;
  32. static long alloc_bytes = 0;
  33. static long in_pool_count = 0;
  34. static long in_pool_bytes = 0;
  35.  
  36. static long _POOL_THRESHOLD_COUNT = 0;
  37. static long _POOL_THRESHOLD_BYTES = 1024 * 1024 * 32;
  38.  
  39. #define _POOL_NODE_ALLOC(size) (((char*)malloc(sizeof(_pool_tag_t) + size)) + sizeof(_pool_tag_t))
  40. #define _POOL_NODE_PTR(s) (s - sizeof(_pool_tag_t))
  41. #define _POOL_NODE_NEXT(s) (*((void**)(s - sizeof(_pool_tag_t))))
  42. #define _POOL_NODE_SIZE(s) (*((_pool_chunk_size_t*)(s - sizeof(_pool_tag_t))))
  43. #define _POOL_NODE_FREE(s) do { free(_POOL_NODE_PTR(s)); } while(0)
  44.  
  45. static int _cmp_size_t(const void* l, const void* r) {
  46.         size_t* pl = (size_t*)l;
  47.         size_t* pr = (size_t*)r;
  48.  
  49.         if(*pl > *pr) return 1;
  50.         else if(*pl < *pr) return -1;
  51.         else return 0;
  52. }
  53.  
  54. static void _tidy_mem_pool(bool_t force) {
  55.         int i = 0;
  56.         char* s = 0;
  57.  
  58.         if(!force) {
  59.                 if(_POOL_THRESHOLD_COUNT > 0 && in_pool_count < _POOL_THRESHOLD_COUNT)
  60.                         return;
  61.  
  62.                 if(_POOL_THRESHOLD_BYTES > 0 && in_pool_bytes < _POOL_THRESHOLD_BYTES)
  63.                         return;
  64.         }
  65.  
  66.         if(!pool_count)
  67.                 return;
  68.  
  69.         for(i = 0; i < pool_count; i++) {
  70.                 while((s = pool[i].stack)) {
  71.                         pool[i].stack = (char*)_POOL_NODE_NEXT(s);
  72.                         _POOL_NODE_FREE(s);
  73.                 }
  74.         }
  75.  
  76.         in_pool_count = 0;
  77.         in_pool_bytes = 0;
  78. }
  79.  
  80. static void _open_mem_pool(void) {
  81. #define N 7
  82.         size_t szs[N];
  83.         size_t lst[N];
  84.         int i = 0;
  85.         int j = 0;
  86.         size_t s = 0;
  87.  
  88.         pool_count = 0;
  89.  
  90.         szs[i++] = _SIZEOF_4BYTES;
  91.         szs[i++] = _SIZEOF_8BYTES;
  92.         szs[i++] = _SIZEOF_32BYTES;
  93.         szs[i++] = _SIZEOF_64BYTES;
  94.         szs[i++] = _SIZEOF_128BYTES;
  95.         szs[i++] = _SIZEOF_256BYTES;
  96.         szs[i++] = _SIZEOF_512BYTES;
  97.  
  98.         mb_assert(i == N);
  99.  
  100.         memset(lst, 0, sizeof(lst));
  101.  
  102.         /* Find all unduplicated sizes */
  103.         for(i = 0; i < N; i++) {
  104.                 s = szs[i];
  105.                 for(j = 0; j < N; j++) {
  106.                         if(!lst[j]) {
  107.                                 lst[j] = s;
  108.                                 pool_count++;
  109.  
  110.                                 break;
  111.                         } else if(lst[j] == s) {
  112.                                 break;
  113.                         }
  114.                 }
  115.         }
  116.         qsort(lst, pool_count, sizeof(lst[0]), _cmp_size_t);
  117.  
  118.         pool = (_pool_t*)malloc(sizeof(_pool_t) * pool_count);
  119.         for(i = 0; i < pool_count; i++) {
  120.                 pool[i].size = lst[i];
  121.                 pool[i].stack = 0;
  122.         }
  123. #undef N
  124. }
  125.  
  126. static void _close_mem_pool(void) {
  127.         int i = 0;
  128.         char* s = 0;
  129.  
  130.         if(!pool_count)
  131.                 return;
  132.  
  133.         for(i = 0; i < pool_count; i++) {
  134.                 while((s = pool[i].stack)) {
  135.                         pool[i].stack = (char*)_POOL_NODE_NEXT(s);
  136.                         _POOL_NODE_FREE(s);
  137.                 }
  138.         }
  139.  
  140.         free((void*)pool);
  141.         pool = 0;
  142.         pool_count = 0;
  143. }
  144.  
  145. static char* _pop_mem(unsigned s) {
  146.         int i = 0;
  147.         _pool_t* pl = 0;
  148.         char* result = 0;
  149.  
  150.         ++alloc_count;
  151.         alloc_bytes += s;
  152.  
  153.         if(pool_count) {
  154.                 for(i = 0; i < pool_count; i++) {
  155.                         pl = &pool[i];
  156.                         if(s <= pl->size) {
  157.                                 if(pl->stack) {
  158.                                         in_pool_count--;
  159.                                         in_pool_bytes -= (long)(_pool_chunk_size_t)s;
  160.  
  161.                                         /* Pop from stack */
  162.                                         result = pl->stack;
  163.                                         pl->stack = (char*)_POOL_NODE_NEXT(result);
  164.                                         _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  165.  
  166.                                         return result;
  167.                                 } else {
  168.                                         /* Create a new node */
  169.                                         result = _POOL_NODE_ALLOC(pl->size);
  170.                                         if((intptr_t)result == sizeof(_pool_tag_t)) {
  171.                                                 result = 0;
  172.                                         } else {
  173.                                                 _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  174.                                         }
  175.  
  176.                                         return result;
  177.                                 }
  178.                         }
  179.                 }
  180.         }
  181.  
  182.         /* Allocate directly */
  183.         result = _POOL_NODE_ALLOC(s);
  184.         if((intptr_t)result == sizeof(_pool_tag_t)) {
  185.                 result = 0;
  186.         } else {
  187.                 _POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
  188.         }
  189.  
  190.         return result;
  191. }
  192.  
  193. static void _push_mem(char* p) {
  194.         int i = 0;
  195.         _pool_t* pl = 0;
  196.  
  197.         if(--alloc_count < 0) {
  198.                 mb_assert(0 && "Multiple free.");
  199.         }
  200.         alloc_bytes -= _POOL_NODE_SIZE(p);
  201.  
  202.         if(pool_count) {
  203.                 for(i = 0; i < pool_count; i++) {
  204.                         pl = &pool[i];
  205.                         if(_POOL_NODE_SIZE(p) <= pl->size) {
  206.                                 in_pool_count++;
  207.                                 in_pool_bytes += _POOL_NODE_SIZE(p);
  208.  
  209.                                 /* Push to stack */
  210.                                 _POOL_NODE_NEXT(p) = pl->stack;
  211.                                 pl->stack = p;
  212.  
  213.                                 _tidy_mem_pool(false);
  214.  
  215.                                 return;
  216.                         }
  217.                 }
  218.         }
  219.  
  220.         /* Free directly */
  221.         _POOL_NODE_FREE(p);
  222. }
  223.  
  224. /* ========================================================} */
  225.  
  226.  

@John, But contexts are totally different from different users with C/C++, thus there's no one-fits-all memory pool solution, that's why C/C++ libs often accept customized memory allocator.

Thanks, I tried that. Using the mempool, calculating the mandelbrot needs about 96 seconds. Without the mempool it needs about 110 seconds if AllegroBASIC was compiled with TCC. Using GCC it needs without mempool about 96 seconds and with mempool about 94 seconds. Not the wide difference as expected ...

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #146 on: February 05, 2016, 02:39:40 PM »
Are those numbers based on showing each pixel as it's calculated?


Here is the above 10 second example but updating the canvas with each pixel. Can you post your numbers not updating the canvas until the end?

I think this good example of what I have been saying all along about interpreters. (Script BASIC specifically) I can go from 214 seconds to 1 second with a couple line changes. That should be the true goal of any real BASIC.



Code: ScriptBasic
  1. ' ScriptBasic GFX - Mandelbrot
  2.  
  3. IMPORT gfx.inc
  4.  
  5. FUNCTION Mandelbrot(cx, cy, iter)
  6.   LOCAL zx, zy, tp
  7.   zx = .0
  8.   zy = .0
  9.   tp = .0
  10.   WHILE zx * zx + zy * zy < 4 AND iter > 0
  11.     tp = zx * zx - zy * zy + cx
  12.     zy = 2 * zx * zy + cy
  13.     zx = tp
  14.     iter = iter - 1
  15.   WEND
  16.   Mandelbrot = iter
  17. END FUNCTION
  18.  
  19. s = gfx::Window(640,480,"Script BASIC SDL_gfx Mandelbrot")
  20. ts = gfx::Time()
  21. FOR y = 0 TO 479
  22.   FOR x = 0 TO 639
  23.     cx = (x - 320) / 120
  24.     cy = (y - 240) / 120
  25.     rit = Mandelbrot(cx, cy, 128)
  26.     gfx::PixelRGBA s, x, y, rit * 32, rit * 16, rit * 8, 255
  27.     gfx::Update
  28.   NEXT
  29. NEXT
  30. te = gfx::Time()
  31. gfx::stringColor s, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0x000000ff
  32. gfx::Update
  33. WHILE gfx::KeyName(1) <> "+escape"
  34. WEND
  35. gfx::Close
  36.  
« Last Edit: February 05, 2016, 07:21:18 PM by John »

Offline Cybermonkey342

  • BASIC Developer
  • Posts: 34
Re: MY-BASIC
« Reply #147 on: February 06, 2016, 01:01:04 AM »
Yep, drawing each pixel ... The funny thing is, with RETROBASIC which uses SDL2 the reuslt is way faster. Only about 60 seconds compared to the 95 seconds with Allegro4.
If I don't draw each pixel it needs with AllegroBASIC and TCC 100 seconds, so it even takes longer than drawing every pixel!

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #148 on: February 06, 2016, 01:05:12 AM »
I'm using SDL 1.2 64 bit with my examples.

That sounds way too strange to even know where to start to unravel that.

If I remove my SDL graphics code, it still runs about the same if I waited until the end to update the canvas. (10 seconds)
« Last Edit: February 06, 2016, 01:32:18 AM by John »

Offline John

  • Forum Support / SB Dev
  • Posts: 3570
    • ScriptBasic Open Source Project
Re: MY-BASIC
« Reply #149 on: February 06, 2016, 09:33:09 PM »
I think I found a happy middle of the road with this Mandelbrot benchmark. Doing the update of canvas when a line is completed is visually pleasing and relatively fast.



Code: ScriptBasic
  1. ' ScriptBasic GFX - Mandelbrot
  2.  
  3. IMPORT gfx.inc
  4.  
  5. FUNCTION Mandelbrot(cx, cy, iter)
  6.   LOCAL zx, zy, tp
  7.   zx = .0
  8.   zy = .0
  9.   tp = .0
  10.   WHILE zx * zx + zy * zy < 4 AND iter > 0
  11.     tp = zx * zx - zy * zy + cx
  12.     zy = 2 * zx * zy + cy
  13.     zx = tp
  14.     iter = iter - 1
  15.   WEND
  16.   Mandelbrot = iter
  17. END FUNCTION
  18.  
  19. s = gfx::Window(640,480,"Script BASIC SDL_gfx Mandelbrot")
  20. ts = gfx::Time()
  21. FOR y = 0 TO 479
  22.   FOR x = 0 TO 639
  23.     cx = (x - 320) / 120
  24.     cy = (y - 240) / 120
  25.     rit = Mandelbrot(cx, cy, 128)
  26.     gfx::PixelRGBA s, x, y, rit * 32, rit * 16, rit * 8, 255
  27.   NEXT
  28.   gfx::Update
  29. NEXT
  30. te = gfx::Time()
  31. gfx::stringColor s, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0x000000ff
  32. gfx::Update
  33. WHILE gfx::KeyName(1) <> "+escape"
  34. WEND
  35. gfx::Close
  36.  

Here is the same by the line method but using the C Mandelbrot iterator.



Code: ScriptBasic
  1. ' ScriptBasic GFX - Mandelbrot
  2.  
  3. IMPORT gfx.inc
  4.  
  5. s = gfx::Window(640,480,"Script BASIC SDL_gfx Mandelbrot")
  6. ts = gfx::Time()
  7. FOR y = 0 TO 479
  8.   FOR x = 0 TO 639
  9.     cx = (x - 320) / 120
  10.     cy = (y - 240) / 120
  11.     rit = gfx::Mandelbrot(cx, cy, 128)
  12.     gfx::PixelRGBA s, x, y, rit * 32, rit * 16, rit * 8, 255
  13.   NEXT
  14.   gfx::Update
  15. NEXT
  16. te = gfx::Time()
  17. gfx::stringColor s, 20, 15, "Time: " & FORMAT("%.4f",(te-ts)/1000) & " Seconds." & CHR(0), 0x000000ff
  18. gfx::Update
  19. WHILE gfx::KeyName(1) <> "+escape"
  20. WEND
  21. gfx::Close
  22.  
« Last Edit: February 06, 2016, 09:59:05 PM by John »