Most existing dynamic voltage scaling (DVS) schemes for multiple tasks assume an energy cost function (energy consumption versus execution time) that is independent of the task characteristics. In practice the actual energy cost functions vary significantly from task to task. Different tasks running on the same hardware platform can exhibit different memory and peripheral access patterns, cache miss rates, etc. These effects results in a distinct energy cost function for each task.We present a new formulation and solution to the problem of minimizing the total (dynamic and static) system energy while executing a set of tasks under DVS. First, we demonstrate and quantify the dependence of the energy cost function on task characteristics by direct measurements on a real hardware platform (the TI OMAP processor) using real application programs. Next, we present simple analytical solutions to the problem of determining energy-optimal voltage scale factors for each task, while allowing each task to be preempted and to have its own energy cost function. Based on these solutions, we present simple and efficient algorithms for implementing DVS with multiple tasks. We consider two cases: (1) all tasks have a single deadline, and (2) each task has its own deadline. Experiments on a real hardware platform using real applications demonstrate a 10% additional saving in total system energy compared to previous leakage-aware DVS schemes.