in reply to Re^4: Using $a and $b from XS
in thread Using $a and $b from XS
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^6: Using $a and $b from XS
by BrowserUk (Patriarch) on Feb 07, 2005 at 02:22 UTC | |
Maybe some time could be saved by looking up the symbols once and then filling in the aliases each time through the loop That could definitely be done. By looking them up once at the top of the main routine and then reverting to your original scheme of passing them into the comparator sub each time (almost as constants) in addition to values to set into them would work, but just pushing and popping them as constants each comparison is going to have a hit. So then you look at assigning the values into them inside the main routine, before passing them through. That's good, but it requires cut&paste reuse, complicates the calling of the comparator and makes the code messy. That could probably be alleviated by the use of a couple of macros to assign the values to the globals inline to the call to the comparator, but when I tried it, the compiler generated streams of errors. It necessitates calling macros within macros, including using some of those macros as lvalues of values returned by other macros. And worse, I don't really understand how some of those macros--which are themselves defined in terms of yet more macros--work! (Does anyone?) Therefore, I am not able to work out why what I was trying to do went bellyup. Normally, if I get "macro expansion" problems, I just ask the compiler to output the preprocessor output so I can see what the actual effect is, but just trying to track down which damn source file is being passed to the compiler is the first problem. Trying to call it with the appropriate environment (compiler flags--libraries etc) outside of the MakeMaker nest-of-vipers is impossible. So then I tried passing the /P flag via the Inline C options, which works, but as every source file includes every damn header in the whole crumbling edifice, it produces a file of 3/4 of a megabyte and ONE HUNDRED AND THIRTEEN THOUSAND NINE HUNDRED AND FOURTY EIGHT LINES! And what lines. Here is what your nice elegant topNbs() function looks like by the time the C compiler comes to convert it to machine code:
Now whilst the compiler may be able to make sense of it in that form, my eyes refuse to retain focus long enough to read from one end of a single line to the other. I did try to reformat that to my usual coding standard, but--even standalone, away from the other 114, 000 lines--it caused my usually reliable reformatting macros to segfault my editor! And do you see those oh so helpful line numbers embedded in compiler directives? Apart from the fact that they relate to intermediate files--some of which appear to get deleted--not the original source code--they are also, to the best of my ability to correlate them, WRONG! So how does anyone debug this stuff? Symbolic debuggers (do they help)? Embedded break points? Reverse binary osmosis? Pressing their ear to the cpu and listening to the frequency of the hum? I'm still hoping an expert will read this thread and give us some other ideas. Hmmm. Maybe... Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.
| [reply] [d/l] |
|
Re^6: Using $a and $b from XS
by BrowserUk (Patriarch) on Feb 07, 2005 at 11:38 UTC | |
Here is my final incarnation of the comparator caller "function" plus a version of topNbs() that uses it. By re-writing the PUSHMARK() macro, I managed to squeeze the calling of the via-$A$B comparator into another macro and avoid (the little) overhead that imposed. I've also done away with the separate SV** topN; and associated memory allocation and freeing by building the return list directly on the stack. If your going to adapt your topNheap(), note the order and positioning of the large group of XS macros--they are critical.
The upshot in my tests is that whilst using $a and $b is quicker than passing via the stack for small numbers of callbacks, as that number grows, the extra cost of lookup of globals (in the comparator sub itself) overtakes the saving of stacking the parameters in the C code. Once again, when you move above about 1% N of T, sort starts to win by not having to call the comparator at all. I'd be really interested to see what a real XS programmer would make of the above? Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.
| [reply] [d/l] [select] |
by tall_man (Parson) on Feb 07, 2005 at 20:44 UTC | |
I get a result like:
I'm also working out how to avoid the extra creation of zero-fill items. Ideally, I would replace them with the first n items of the input in reverse-sorted order. There are two reasons for this: 1) We cannot yet handle negative numbers. 2) We should be testing for the case that the input length is less than or equal to n, and in that case returning everything they gave us. Something like:
| [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Feb 08, 2005 at 01:52 UTC | |
If you reverse the order of $a and $b in the comparator, you'll see it works okay for the only case you have coded so far. To be honest, I haven't been trying to fix up the algorithms, that's your department :) I've been concentrating on how to make the callback from C to Perl. I'm also working out how to avoid the extra creation of zero-fill items. 1) We cannot yet handle negative numbers. 2) We should be testing for the case that the input length is less than or equal to n, and in that case returning everything they gave us. Something like: These becomes a non-issues once we fix the main problem--that of handling building the list when you don't know what the sort order will be. There is no useful value that we can use to initialise the list. Even undef is a legitimate value for the caller to pass us as a part of the list, and their comparator function can choose to order that in whatever way they see fit. Hence, the problem moves from how to initialise the list, to one of deciding when to add a new value to the list. We don't need to pre-initialise the list with a sorted list. We just build it as we go and the algorithm will take care of the sorting. Essentially, we just stick each new value on the end of the list until we reach the limit, and effectively ignore it's presence when doing the binary search. Once we find the legitimate position, the new, unsorted value we tacked on the end will get shifted off when we insert that same value into it's proper place. Harder to describe than code--though the ternary fudge on the initialisation of $right took me a while to see. It also means that we need to remember to remove the last value from the list before returning it. Here it is coded in Perl. I'm not ready to get back into Inline C again yet. Man, that makes you remember just why you like Perl so much :)
A similar mechanism should work for the heap sort version. Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.
| [reply] [d/l] |
by tall_man (Parson) on Feb 08, 2005 at 03:10 UTC | |
by BrowserUk (Patriarch) on Feb 08, 2005 at 04:16 UTC | |
|
Re^6: Using $a and $b from XS
by BrowserUk (Patriarch) on Feb 07, 2005 at 05:34 UTC | |
Gah! I guess I'm hooked :| Pushing things along a little further, I succeeded in coding a macro (that doesn't break), to take care of the assignments to $a & $b and then call the comparator, reducing some of the overhead in the process: Read more... (2 kB)
This appears to be reliable and gives it another step up over sort for smallish lists from biggish ones:
However, as soon as size of N approaches 10% of the main list, sort once again takes a lead:
And if the list gets really large and the N very small (which ought to favour the linear search + binary sort over full sort and slice), sort once again wins hands down. More interestingly, topNbs() (via @_) starts to show better again?
I think this is due to the allocation, initialisation of the SV* topN array, followed by the incremental extension of the perl stack through XPUSHs as we copy the topN array onto the stack. Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.
| [reply] [d/l] [select] |