There are several reasons why the performance of current distributed and heterogeneous systems is often disappointing. For example, the characteristics of the application may be input sensitive and evolve during execution causing dramatic changes in memory reference patterns, resource requirements, or degree of concurrency between different phases of the computation. Or, the system may change dynamically with nodes failing or appearing, some network links severed and other links established with different latencies and bandwidths. Another important reason for poor performance is the fairly compartmentalized approach to optimization: applications, compilers, operating systems and hardware configurations are designed and optimized in isolation and without the knowledge of instance specific information and needs of a running application.