Self-optimizing MPI Applications: A Simulation-Based Approach