These techniques measure execution times of individual routines, or the latency of a single interrupt. With only two channels and no memory, the scope doesn't identify the time spent in individual lines of C within a routine. Once again, add code to drive a bit high only during the code fragment's execution. Look at one address bit at a time, making a paper record of when addresses change relative to the routine's start pulse. Given a short subroutine, it's not too hard to make a map of its execution.
Logic analyzers are almost as useful for performance measurements.
Connect the analyzer to the system's address bus and command it to acquire one sample every 100 microseconds. 1000 acquisitions after starting, the logic analyzer's internal memory will contain a sort of statistical profile of where the code runs. It might miss very short routines, but it will give you a high level picture very quickly. Crank up the acquisition rate for finer details. If the analyzer can store 1000 cycles, then with a 10 microsecond rate you'll get a pretty good profile over 10 milliseconds of execution.