The best code in the world is junk if it cannot keep up with outside events. The answer is appalling. Generally, we take a wild guess, write some code, and see how well it does. If it isn't fast enough, we'll change something and try again. There seems to be no other answer, since there's no way to tell how long a line of C takes to execute.
Some assemblers generate timing information in the listing file.
The number of T-states per instruction are listed, giving precise elapsed time data. Knowing the clock rate, wait states, and the like, it's a simple matter to convert T-states to time. It's silly to be forced to write code to, essentially, document the compiler's behavior. Of course, complex library routines may not have totally predictable responses. A trig function's response will vary greatly depending on the input argument.