Newbie questions about Pliant

Newbie questions about Pliant

The argument that Pliant will be faster than C shows a
very poor understanding of the realities of performance
and optimization.
Message posted by maybe Darrell Johnson on 2001/03/12 01:07:33

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.

Message posted by hubert.tonneau on 2001/03/12 10:51:02

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 extra optimizing

Message posted by pom on 2001/03/12 14:04:26
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.

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 a priori.