<div dir="ltr">On Thu, Oct 9, 2008 at 7:21 PM, Richard O'Keefe <span dir="ltr"><<a href="mailto:ok@cs.otago.ac.nz" target="_blank">ok@cs.otago.ac.nz</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<div><br>
On 9 Oct 2008, at 7:43 pm, Edwin Fine wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I'm assuming you are providing this code as an "executable requirements document." I was rather hoping that it could be implemented as a BIF.<br>
I'll have to study your code below so I can learn some "fast and fancy" Erlang!<br>
</blockquote>
<br></div>
Well, no.  I was providing the code as a first draft of what<br>
could be dropped into string.erl.  I see no reason why it should<br>
be a BIF, if by that you mean something implemented in C.</blockquote><div> </div><div>Yes, that is what I meant.<br> <br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<br>
If the performance of unjoining should be a bottleneck in some</blockquote><div><br>My background and experience has led me to believe that primitive operations, or functions that are likely to be heavily used, should be implemented in a low-level language like C, and not in the higher-level language. I consider string:split to be something that will be heavily used in text-processing applications (which will also become heavily used, I predict). Since string operations really need to be efficient, I wrongly assumed that the string operations were written in C and that the equivalent Erlang code would not be nearly as efficient.<br>
<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
program, after getting over my astonishment I would recommend<br>
unrolling.  For example,<div><br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
unjoin0([C|Cs]) -><br>
   [[C] | unjoin0(Cs)];<br>
unjoin0([]) -><br>
   [].<br>
</blockquote>
<br></div>
would become<br>
<br>
unjoin0([A,B,C,D|S]) -> [[A],[B],[C],[D] | unjoin0(S);<br>
unjoin0([A,B,C])     -> [[A],[B],[C]];<br>
unjoin0([A,B])       -> [[A],[B]];<br>
unjoin0([A])         -> [[A]];<br>
unjoin0([])          -> [].<br>
<br>
That plus HiPE can often do surprisingly well.</blockquote><div> </div><div>I'd rather ensure that the function is implemented efficiently to start off with, and not <i>require</i> HiPE to be used to get performance. One of these nights when I have some spare time, I am going to try your code out  (with and without HiPE) against a 'C'  or C++ version of split and join so that I can have some hard data to tell for sure one way or the other.<br>

<br>This is how I see it: even given the increasingly fast computer architectures of today, one should do one's best not to waste processor time when performance is desired. I have seen users of interpreted, byte-code interpreted, and threaded-interpreted languages implement  computationally expensive, heavily used functions in the language instead of in a low-level C library. In almost all cases where the code was not I/O bound, there was a significant penalty for writing such functions. Rewriting those functions in C/C++ often gave one or two orders of magnitude improvement. I know that the overall algorithm can make a huge difference, and that we should not waste our time with premature optimization, but at the same time we should not waste CPU time with belated pessimization. If we can predict based on experience that something (a) is likely to be heavily used and (b) will be more efficient in a lower-level language then we should implement it in said language. All the little inefficiencies can add up into a steaming great system-wide inefficiency. The death of a thousand cuts.<br>

<br>Now, that having been said, I have not devoted time (yet) to studying the relative efficiency of Erlang-implemented operations compared to C code. Obviously in a large-scale sense, Erlang is generally efficient enough given the uses to which it has been put. On the gripping hand, the uses to which Erlang has been put are going to push its envelope as it gains more traction. It's going to be used in many more Web-related applications, which means <i>inter alia</i> much more text processing involving fiddling around with strings (excuse the unintended pun). Fiddling with strings can and does kill systems that are not designed to do that.<br>
<br>Here's the old war story ploy.<br><br>I once ported a C++ application to an IBM mainframe - which had (gasp!) a C++ compiler - and saw the mainframe get absolutely *caned* by my laptop performance-wise in many cases. Investigation at that time revealed that although the mainframe wiped out my laptop in terms of I/O speed and bandwidth, my laptop just smoked the IBM when it came to what goes on in the Web: dynamic string processing and lots of memory allocations and deallocations. IBM, seeing the writing on the wall, modified its hardware architecture, IIRC by adding special string opcodes, and improved its runtime libraries, to support more efficient string-processing and better dynamic memory handling.<br>

<br>Now Erlang has been known to present challenges when it comes to string processing (and pattern matching and file I/O - see the WideFinder project) if the unwary don't take special steps like using binaries for efficiency, and keeping as much as possible in iolists instead of having everything flattened. We all know that Erlang was originally intended for soft real-time type applications. The way things go is that as a language proves its merits, and becomes more and more in demand because (in Erlang's case) it has a reputation for creating highly reliable and available systems, people will start pushing the envelope of its original design parameters. Reading the history of Awk is interesting in this regard; it was put to uses which the authors never dreamed of (like implementing a database - horror). Demands came in for more and better library functions. I predict the same will happen with Erlang, if it is not already happening.<br>
<br>It is well to say that one shouldn't use one single language to do everything (and I agree with that caution), but in my experience, software managers don't like having too many languages floating about because of the recruitment, maintenance and training burden. Many developers are not as gifted as the readers of this list and find it difficult to hop between different languages. This all creates a tendency to use the primary language for as many things as possible (the old hammer and nails analogy), even if it wasn't designed for that. It is therefore probably a good idea that we don't pessimize Erlang by writing fundamental code in Erlang that arguably should be implemented as 'C' BIFs. And I am sure there will be argument :)<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
But this is something to do AFTER measurement!<br>
</blockquote><div><br>Ideally, yes, and then again, maybe not, if we strongly suspect that it's going to bite us later NOT to do it now. Here's the problem: like I wrote earlier about the death of a thousand cuts, what if there isn't a few big bottlenecks? What if the system is slow simply because it is bloated from too many unnecessary opcodes being executed in a fairly distributed pattern?<br>
<br>Like John Haugeland (sp?) wrote earlier, sometimes 20+ years of programming experience gives one an intuitive idea regarding performance. Every little bit counts (excuse the pun). I am just generally saying that if one doesn't watch out, the system gradually bloats with new high-level code and then it's not so performant anymore.<br>

</div></div><br>Now I will duck into the flame-proof bomb shelter.<br></div>