The truth about most programs where high performance is important is that 99% of the running time is spent in under 1% of the code.
It doesn't matter how much you improve the majority of the code; even if you optimize it away to zero run time, you would only get a 1% performance improvement.
The "Even Faster Than C" page explains that "yes, on small programs it's impossible to be faster than C, but on large ones, Pliant wins"; which is pure nonsense, because the performance-relevant code is almost always small. It's the old "our compiler is smarter than your programmers" argument that has proven false time and time again. There is no substitute for hand optimization.
Another bad argument is "you cannot help the C compiler to compile a pattern efficiently without touching the source code", which is blatantly false. There is an art to finding the optimal compiler flags.
To top it off, there is the fact that Pliant is a JIT compiled language. That means that it is doubly disadvantaged in that it must start up slower, and the optimization routines must be severely limited because it is not acceptable to spend hours (or even minutes!) figuring out the best code to generate. Any optimization strategy which can be applied to a JIT can be applied to a static compiler, with better results.
Be realistic. Talk about trade-offs, don't make silly claims about how your magic JIT can do a better job in 100 milliseconds than a high-quality optimizing static compiler can do in 20 minutes.
It's the old "our compiler is smarter than your programmers" argument
that has proven false time and time again.
There is no substitute for hand optimization.
You're right, but you are also pointing only half of the truth.
If you have a clever programmer, that knows the details about the field
he is programming for, and has time, he will for sure get better restults
that any automaton. In this area, Pliant is just as good as C, because it
can be as low level as C, so give you perfect control on any instruction
of your program.
Now, the other side to wonder is why Fortran still remains most of the
time faster in floatting computations than C. The explaination is that
the source code convensions make the optimizer live easier.
This is very important: if you spend much time on designing high quality
libraries, then you need to specify how high level the functions on that
libraries should be so that the optimizer will have maximum flexibility
to apply optimizing rules. C is always low level, and you have no way to
make it higher level in some areas, so you have no way to provide advanced
libraries for it. On the other hand, functionnal languages tend to be
high level in all areas, and even in execution model, so carry an extra
cost compared to Pliant because you need high level source code to get
best automatic optimizations, but no more.
The same apply for graphic libraries: the higher level they are, the
better they live over time since the graphic cards hardware is doing more
and more of the job (see discutions about why X11 is slow, which end to
because it is too low level and does not provide primitives for anti
aliased fonts and so on). Now, if you also have a compiler you can teach
to make basic rewrittings at compile time, according to the current driver
specifications, rather than sort the all thing at run time, then you can
get an extra bonus.
Another bad argument is "you cannot help the C compiler to compile a pattern
efficiently without touching the source code", which is blatantly false.
There is an art to finding the optimal compiler flags.
Yes, but you are again facing only half of the problem. Another important
thing with C is that a function prototype does not carry all informations
required to best optimize. So, if you are compiling your application as
a single self contained shot with all function beeing declared as static,
a clever C compiler could do quite well, but any large application will have
several parts compiled one after the other (thanks to the uggly make file
notion), and even worse, the C low level library is external to the
application, so some important optimizing informations are missing.
In Pliant, some informations about each function are deduced from the
prototype, but extra ones are computed at code generation time, and these
will not be lost, and it's a key issue for properly optimizing.
Now, what my probably sadely expressed sentence ment is that on large
applications, you often have to change the interface to some part, and
provide backward compatibility for the rest of the code for quite a time,
or forever. Then once again, if you can tell basic rewritting rules to
the compiler, then you can drastically reduce the cost of carrying the past.
don't make silly claims about how your magic JIT can do a better job
in 100 milliseconds than a high-quality optimizing static compiler
can do in 20 minutes.
First of all, Pliant has a precompiling notion: the PDEE which contains all
the low level routines of Pliant is generally precompiled. So, Pliant
code generator could spend a long time optimizing it.
Now, in any application, you can get some part or all part of it precompiled
(I do for my graphic applications in order to get the low level graphic
functions compiled using GCC, which is slow), so your argument about a JIT
compiler to not be abble to run any time consuming advanced optimization
algorithm does not apply to Pliant.
Now, I'll take as an example a true situation I met: a few years ago, I
wrote a full PostScript rip from scratch, including all the low level
drawing routines. Now, for the low level drawing primitives, some are
applyed to all pixels of a large image, so often, you have a small routine
with a lot of parameters beeing constant among all millions of calls within
the same image, and you don't know these constants at 'compile time', but
only at run time when you get the instruction to apply this or that filter
to a given image: in such a case, it can be a significant win to call the
compiler back to generate a fully optimized code, according to the constants.
The same may apply to many areas where you are looping in a tiny function,
which is basically what you asserted at the very beginning of you comment.
Lastly, I have not mentionned the profiling issue, but it might be the right
time to: In Pliant, since you carry a real execution environment in the
compiler, then you can make statistics (profiling) automatically in many
cases, whereas in C, you have to do everything by hand.
So my end conclusion is that if you spend time running the profiler and
optimizing by hand the significant pieces, then you get the best from a
C compiler, at high programming time cost, and if the profiling does not
reveal that the initial design was wrong (you have to change the interface
on the all code). With Pliant, you can do it as well, but can also get more
help from the compiler because it is more flexible since it has room for
introducing per field or per application extra optimizing rules, some of
them beeing the result of automatic statistics.
I can say it another way: C++ is a super set of C. Pliant is also a super
set of C.
The key difference is that with Pliant:
you get rid of the stupid copy on return C++ notion
you get room to feed extra optimizing rules to the compiler when you
introduce high level notions
you can tel the compiler how to make trivial rewrittings when you
are carrying the past
you have a true execution environment at compile time so you can evaluate
complex constants or make statistics
you can call the compiler back at execution time, for extra flexibility or
|The truth about most programs where high performance is important is that 99% of the running time is spent in under 1% of the
This fails to be true in two fundamental categories: librairies and scientific
programming. In those fields, up to 3/4th of the time is spent to perform
tests which could be made at compile-time or to compute values which are
of no interest, because of the difficulty to handle all the special uses
of an algorithm, which leads to a worst case-driven implementation.
performance-relevant code is almost always small.
This is true for "obvious" functions. It fails to be true in (at least) two cases:
Complex applications, where the performance-relevant code is theoreticaly small,
but the computer time is in higher ratio lost in glue code;
- Scientific applications where every line of a 1000 lines program are
almost identically time-consumming.
There is an art to finding the optimal compiler flags
There are hundred of things you cannot tell the compiler. When you face some
NP or exponential-time problem, any compile time is epsilon in regard to
run-time, and any optimization which actually appears has "abstract" probability
around 0. Moreover, each time you optimize a way, you loose in another one,
and there are not always an absolute good choice!
Any optimization strategy which can be applied to a JIT can be applied to a static
compiler, with better results.
There is an expressiveness problem here: if you have to rewrite Pliant to
be able to explain the optimizations you need, where is the gain ?
It seems you still claim that any feasible optimization is naturally
decidable at compile-time, whatever are the datas. This is far to be true.
There is a big proportion of real problems, where the data you handle are
far from being random, even if you can't make any assuption on their specificity