# | User | Message | Date |
84 | Maxim | yeah amd with the faster fuunction calling in R3 liquid should get an immediate boost in speed... it does A LOT of tiny function calls to manage the graph as if they where first level types with accessors instead of using a controler which loops over the graphs and limits flexibility. | 31-Oct-09 3:24 |
83 | BrianH | The plus side is that what you would just do, before you try to optimize, tends to be faster in R3 than it is in R2. | 31-Oct-09 3:04 |
82 | BrianH | Code converted from R2 to R3 tends to need reoptimizing - the balance of what is native vs what is mezz has changed, usually for the better. All of the loop functions are native now, for instance. Also, some natives have been converted to actions, and vice versa. | 31-Oct-09 3:01 |
81 | Maxim | with the tests I did, I think I can probably optimise liquid by at least 20% just by changing the loops and changing none of the algorithms or features. I am about to create a second reference liquid node type. which will be completely compatible from the outside, but with less features inside. I expect to DOUBLE its processing capacity. | 31-Oct-09 2:51 |
80 | Maxim | you learn a lot by doing it. | 31-Oct-09 2:48 |
79 | BrianH | With the typos fixed I hope :) | 31-Oct-09 2:48 |
78 | Maxim | I intend to devote a whole site to these tests eventually. with a very extensive and comprehensive set of test functions and statistics. | 31-Oct-09 2:48 |
77 | Maxim | better described than I would put it, but those where my assumptions... I will include this info in my next revision of the document. | 31-Oct-09 2:47 |
76 | BrianH | For instance, 1000 > i would be faster than i < 1000 because ops redirect to actions, and actions dispatch based on the type of their first argument. If the first argument is a literal value, the action of that type can be called directly. If it is a referenced value, it woulkd have to be dereferenced first, which is apparently slower. As for PICK being faster than NOT TAIL?, that is one native compared to two, with interpreter overhead between the two. Low-level natives like PICK, NOT and TAIL? don't do much in comparison with the interpreter overhead. Large numbers of small operations tend to be slower than small numbers of large operations, if the amount of work done is comparable. This is why structure manipulation is faster in REBOL than simple math. | 31-Oct-09 2:46 |
75 | Maxim | for my 3D engine, this base line test was neccessary. I need to squeze every hz out of rebol... its nice to see how some exit conditions are 10-15% faster in some equivalebt tests... who would have tought that 'PICK was faster than NOT TAIL ? :-/ | 31-Oct-09 2:40 |
74 | BrianH | Thanks for the info, Maxim. We can do a little deduction from that data to guess how REBOL is implemented. The scientific method :) | 31-Oct-09 2:37 |
73 | Maxim | updated document. | 30-Oct-09 17:37 |
72 | Maxim | but I did miscalculate the remove-each MB/second create/scan/erase cycle... its not 100MB... its 10MB. | 30-Oct-09 17:35 |
71 | Maxim | as indicated in the document introductions... the repeat test is: loop ops [repeat i 1000 []] so with 100000 ops taking near 2 seconds. we end up with: 100,000 * 1000 / 2 = (50 million loops / second) | 30-Oct-09 17:26 |
70 | sqlab | M: looks more like 50 thousands than 50 millions for repeat. So take care of your powers of 10 | 30-Oct-09 17:22 |
69 | Maxim | in any case I want to build a single script which does all the tests, statistics, and eventually graphics and html pages of all results in one (VERY) long process. so I can better control how the tests are done and prevent automated test creation as I am doing now. | 30-Oct-09 16:58 |
68 | Maxim | not sure I'm making sense... in how I explain it. | 30-Oct-09 16:57 |
67 | Maxim | I reduce a block which is the test... and since foreach copy/deep, and there is NO word ever refering to the content of the refered block, I think the contents of the blocks prevent the blocks and the data they contain from being collected... the block contains words which are not GC counted as zero reference, so nothing gets de-allocated... that's just my guess. | 30-Oct-09 16:56 |
66 | Steeve | yep, but your tests seem not having such cases | 30-Oct-09 16:53 |
65 | Maxim | I think R2 GC can't determine co-dependent unused references... in some situations.
ex:
blk: reduce [ a: context [b: none] b: context [c: a] a/b: b ]
blk: none in this case both a and b point to each other, and clearing blk doesn't tell a or b that they aren't used anymore... that is my guess. | 30-Oct-09 16:53 |
64 | Steeve | and if you activate recycle/on, does that make any difference ? | 30-Oct-09 16:51 |
63 | Steeve | R3 is better with that | 30-Oct-09 16:49 |
62 | Steeve | yes, i noticed that too, it's a probem with R2 | 30-Oct-09 16:49 |
61 | Maxim | >> stats
== 541502965
>> recycle
>> stats
== 272784493 but that's just for about 10 % of the tests... the more tests I do the more ram stays "stuck" somewhere inside the interpreter. | 30-Oct-09 16:48 |
60 | Steeve | what do you mean ?, it does it here: >> recycle s: stats loop 1000000 [foreach a [1 2 3][a: a]] print stats - s recycle print stats - s 1569504 ;memory allocated by the loop -320 ; after the recycle | 30-Oct-09 16:46 |
59 | Maxim | I tried manually recycling... but it didn't do anything. | 30-Oct-09 16:39 |
58 | Maxim | this will also have to be investigated further (the leak) | 30-Oct-09 16:38 |
57 | Maxim | I did note, that there is a HUGE memory leak which occured probably in the actual benchmark procedure itself. although I keep no reference to any of the data or transient test blocks and funcs, they are kept somewhere, and my rebol.exe process keeps growing and growing.... I caught it at 500MB !! but it didn't do any difference in actual speeds... after a few tests.... cause i was a bit scared. | 30-Oct-09 16:38 |
56 | Maxim | as noted in the document test notes: I specifically didn't do any GC control, cause I wanted, at this point, to see how the loops react under normal rebol execution. the GC normally is pretty aggressive and when you look at the tests, most loops roll for several hundred thousands times, so the GC will have kicked-in... if it can. | 30-Oct-09 16:35 |
55 | Maxim | thanks steeve, I'm accumulating all comments First revision of the benchmarks will include: -RAM stats -empty vs filled-up loops. many words and a single func with the same content called from the loop -GC de-activated tests + recycle time stats | 30-Oct-09 16:33 |
54 | Steeve | but perhaps i'm wrong, you take it in account | 30-Oct-09 16:32 |
53 | Steeve | Your bench doesn''t take in account the time taken by the GC to recycle the memory. Some functions polluate the memory some other not. You should add the time needed to recycle after each test. | 30-Oct-09 16:31 |
52 | Steeve | A thing should be noted.
repeat and foreach do a bind/copy of the evaluated block.
Even if they are the fastest loops, they should be not used too intensivly because they will polluate the memory.
It's particularly sensitive for graphics applications or services that linger in memory. So, that's why I advise to use only LOOP, WHILE and UNTIL for intensive repeated loopings, if you don't want to blow up the memory used by your app. | 30-Oct-09 16:25 |
51 | Maxim | would *like* | 30-Oct-09 16:23 |
50 | Maxim | I would a few peer reviews so I can continue to evolve this document in order to make it as precise/usefull for everyone. | 30-Oct-09 16:22 |
49 | Maxim | See who is the overall winner in this REBOL iterator slug fest analysis!!!
over 8 hours of practically non-stop cpu cycling over a wide variety of exit conditions, datasets and ALL iterators in rebol 2
(loop, repeat, for, forever, foreach, remove-each, forskip, forall, while, until ) 20 kb of data, statistics, comments and test details. INVALUABLE data for people wanting to optimize their REBOL code. http://www.pointillistic.com/open-REBOL/moa/scream/rebol-iterator-comparison.txt | 30-Oct-09 15:51 |
48 | Maxim | will be nice to do the same exercise on R3 | 30-Oct-09 14:38 |
47 | Maxim | profiling almost done... my machine has been looping series and indexes non-stop for about 8 hours now :-) be ready for the most in-depth analysis on loops ever done for R2 ;-) | 30-Oct-09 14:38 |
46 | Maxim | (i: i + 1) > 1000 same speed as i: i + 1 i > 1000 | 30-Oct-09 11:18 |
45 | Maxim | and its not because of the paren... I checked that.... | 30-Oct-09 11:17 |
44 | Maxim | 1000 < i: i + 1 is 10% faster than (i: i + 1) > 1000 | 30-Oct-09 11:16 |
43 | Maxim | but I'm discovering a lot of discrepancies in things like string vs block speed of certain loops...
and a lot of other neat things like: pick series 1 is 15% faster than not tail? series | 30-Oct-09 11:15 |
42 | Maxim | the comment above about remove-each is false... it was a coding error. | 30-Oct-09 11:11 |
41 | Geomol | Yeah, there's often a huge difference between a mezzanine function and a native. In R2, FOR is mezz, REPEAT is native. | 30-Oct-09 11:09 |
40 | Maxim | did you know that FOR is 60x ... let me write that out ... SIXTY TIMES slower than REPEAT !!! | 30-Oct-09 5:18 |
39 | Maxim | wow I'm already at 7kb of output text with notes and proper header ... I haven't done half the tests yet! | 30-Oct-09 5:17 |
38 | Maxim | (probably exponentially faster as the series grows) | 30-Oct-09 1:29 |
37 | Maxim | and remove-each is 90 times faster if it always return true rather than false ! | 30-Oct-09 1:29 |
36 | Maxim | the main one being that foreach is actually the fastest series iterator! | 30-Oct-09 1:22 |
35 | Maxim | I'm doing an in-depth analysis of various looping funcs... and discovering some VERY unexpected results amongst the various tests... will report in a while when I'm done with the various loop use cases. | 30-Oct-09 1:20 |
34 | Maxim | steeve, replied in (new) !SCARE group | 29-Oct-09 7:32 |
33 | Steeve | maximum-of uses the func GREATER? in R3 To me it make sense, because in Rebol, blocks are really great ! :-) | 29-Oct-09 7:30 |
32 | Sunanda | If you are trying to find the largest in a series of not-strictly comparable items, then be aware that R2 behaves differently to R3: b: reduce [1 none 12-jan-2005 unset 'a copy []] last sort b ;; r2 and r3 agree maximum-of b ;; r3 has a headache == [[]] | 29-Oct-09 7:13 |
31 | Steeve | Do you use the skew command in draw ? or are you calculating the coordinates of your 3D objects for each layer. (I think SKEW allow to simulate isometric rendering in AGG, but it's just an assumption, i never tried it) | 29-Oct-09 7:10 |
30 | Maxim | *3D* | 29-Oct-09 7:07 |
29 | Maxim | I'm working on isometric rendering of 3 polygonal gfx in AGG, so profiling is currently quite high on my list :-) | 29-Oct-09 7:06 |
28 | Maxim | but I guess I could try using paths as the function argument... that actually might work too. | 29-Oct-09 7:05 |
27 | Maxim | so I can test functions with any number of args, as long as I don't use refinements, I'm ok. | 29-Oct-09 7:04 |
26 | Steeve | ok | 29-Oct-09 7:04 |
25 | Maxim | but no, the way profile handles its second argument (here reduce [a]) is that it uses the second argumet AS the argument spec for the function... loop i compose/only [ (:func) (args)] so in the end, the test becomes: loop i [maximum-of a] | 29-Oct-09 7:03 |
24 | Maxim | hehe | 29-Oct-09 7:00 |
23 | Steeve | tired ? | 29-Oct-09 6:57 |
22 | Steeve | actually, you are not sorting or traversing a long serie.
>>reduce [a]
== [[1 1 1 2 2 2 ...]] your serie contains only one value. i suggest to do a COPY A instead | 29-Oct-09 6:56 |
21 | Maxim | btw 'PROFILE is a handy function I built which accepts ANY function with ANY args and repeats the test until it takes longer than one second, you can adjust its loop scaling by varying amplitude and magnitude of loops at each iteration. 'REPORT-TEST simply dumps human-readable and easy to compare stats of calls to profile (which returns a block of info on the test). | 29-Oct-09 6:55 |
20 | Maxim | here is a sreen dump of iteration vs maximum-of native use.... goes to show the speed difference in binary vs interpreted!! >> a: [1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 6 6 6 6 6 7 7 7 7 7 8 8 8 8 8 9 9 9 9 9 10 10 10 110 110] report-test profile :maximum-of reduce [a] ---------------- performed: 10000000 ops within 0:00:09.781 seconds. speed: 1022390.34863511 ops a second speed: 34079.678287837 ops a frame ---------------- >> report-test profile :get-largest reduce [a] ---------------- performed: 10000 ops within 0:00:01.86 seconds. speed: 5376.34408602151 ops a second speed: 179.21146953405 ops a frame ---------------- we are talking 190 TIMES faster here | 29-Oct-09 6:52 |
19 | Steeve | Moreover, maximum-of and minimum-of are probably the only ones functions faster with R2 than R3. In R3, they have been turned back into mezzanines (never understood why) | 29-Oct-09 6:51 |
18 | Steeve | Ah, you're requesting that the math operators apply on blocks of scalar (vectors). Old request. Never done in R2 and not yet in R3 | 29-Oct-09 6:47 |
17 | Maxim | is there an equivalent for sum? | 29-Oct-09 6:44 |
16 | Steeve | dunno ;-) | 29-Oct-09 6:43 |
15 | Maxim | thx. | 29-Oct-09 6:43 |
14 | Maxim | darn ... how could I have missed that func for years! | 29-Oct-09 6:43 |
13 | Steeve | For R2 ? Abracadabra !!!! >> maximum-of | 29-Oct-09 6:38 |
12 | Maxim | any one know of a faster method than sorting a block to get the largest value inside of it? in my tests... this: forall blk [ val: max val first blk] is ~ five times SLOWER than this: last sort blk | 29-Oct-09 4:49 |
11 | Maxim | neat :-) | 20-Sep-09 8:53 |
10 | Gabriele | my framework for tests and benchmarks will be released... eventually :) | 20-Sep-09 8:50 |
9 | Steeve | Gabriele, could be useful to build a GUI like yours to standardize our benchmarks. | 19-Sep-09 8:44 |
8 | Gabriele | http://motoko.rebol.it/to-pair.png | 19-Sep-09 8:23 |
7 | BrianH | AS-PAIR and TO-PAIR are mezzanine. Carl has mentioned wanting to make AS-PAIR native - sounds like a good candidate. | 17-Sep-09 18:51 |
6 | Maxim | probably should add Rebol version and platform in any further profiling compilations... to make them even more usefull as a reference. | 17-Sep-09 8:30 |
5 | Maxim | integer to pair convertion speed tests: >> s: now/precise loop 1000000 [to-pair 2] print difference now/precise s 0:00:00.547 >> s: now/precise loop 1000000 [1x1 * 2] print difference now/precise s 0:00:00.219 >> s: now/precise loop 1000000 [to pair! 2] print difference now/precise s 0:00:00.328 >> s: now/precise loop 1000000 [as-pair 2 2] print difference now/precise s 0:00:00.937 | 17-Sep-09 8:28 |
4 | Maxim | I created this group, cause ever so often these experiments come around and we loose them... this should become a quick repository of tests & disussion for profiling discoveries we do. any test should provide the full test command-line code, so its easier for other to copy-paste & compare without having to re-type. ever so often, a compilation should be done, highlighted in a different color for easy referral... | 17-Sep-09 8:25 |
3 | Sunanda | And as-pair [2 2] is significantly slower than either. Nice tuning experiment! There will be other surprises too, I'm sure. | 17-Sep-09 8:21 |
2 | Geomol | And this comes in between: to pair! 2 | 17-Sep-09 8:19 |
1 | Maxim | interesting for those who didn't know, same result, but 2.5 times faster : >> s: now/precise loop 1000000 [to-pair 2] print difference now/precise s 0:00:00.547 >> s: now/precise loop 1000000 [1x1 * 2] print difference now/precise s 0:00:00.219 | 17-Sep-09 8:11 |