Program Execution Explorer lab Solution

Useful pointers

Background
The name of this assignment comes from the idea that a debugger like GDB is better thought of as a way of exploring program execution histories than merely as a debugger.

Although the GNU Emacs text editor is not intended for high performance numeric computation, its scripting language Elisp is reasonably widely used and Elisp applications needs adequate (if not stellar) performance for numeric applications. One such application, GNU Calc, is a desk calculator that does a lot of arithmetic internally. Your goal is to see how much overhead is imposed by Emacs when doing standard arithmetic operations, in particular multiplication with two integer arguments, and to think about how to reduce the arithmetic overhead.

Keep a log
Keep a log in the file pexexlab.txt of what you do in the lab so that you can reproduce the results later. This should not merely be a transcript of what you typed: it should be more like a lab notebook, in which you briefly note down what you did and what happened. It should record not just what worked, but also what didn't work.

Gather instruction traces
You can multiply two numbers with Emacs from the shell by running a command like this:

emacs -batch -eval '(print (* 37 -26))'
Gather a trace for the key part of the above test case. This trace should include every instruction in the Ftimes function, which is the C implementation of the Elisp * function. It should also include every instruction in every function that Ftimes calls, either directly or indirectly.

For the purpose of this assignment, a trace is an ASCII text file. Each line corresponds to a single machine instruction executed in turn during the trace. Lines use the following format:

0x8120921<arith_driver+1data.c:2577 push %edi M[0xffffc9c4]=0x084073c2 esp=0xffffc9c4
Columns should be separated by single tab characters. The first column gives the machine address of the instruction, both in hexadecimal and (in angle brackets) as an offset from the current function); this address is followed by the basename of the source file and line number that is most responsible for the instruction; the example source line is the { at the start of the arith_driver procedure, since the instruction is part of that function's prolog. The second column gives the machine instruction in the same format used by GDB's x/i command, using a space to separate the instruction from operands. The third column gives the effect of the instruction on memory and general-purpose registers, again using hexadecimal values. The example above stores 0x084073c2 into the memory word at address 0xffffc9c4; the leading 0 in "084073c2" reminds the reader that it's a 32-bit operation. The example also sets the esp register to 0xffffc9c4. List memory modifications in increasing address order, and register modifications in alphabetical order. Traces need not record modifications to status registers such as eflags.

To gather information for your first trace (which you should put into the file trace1.tr), use the executable ~eggert/bin32/bin/emacs-24.5 on the SEASnet GNU/Linux servers. The corresponding source code can be found in ~eggert/src/emacs-24.5/ (particularly its src subdirctory), and the executable was compiled for the x86. The above example trace line corresponds to line 2577 of ~eggert/src/emacs-24.5/src/data.c.

Gather a second trace trace2.tr for the same test case from the executable ~eggert/bin64/bin/emacs-24.5 on the same platform. It is generated from the same source code, and was compiled for the x86-64.

Gather a third trace trace3.tr from a test case that prints (* most-positive-fixnum most-positive-fixnum) instead. Use the x86 Emacs for this test case; on this platform, most-positive-fixnum is 536870911.

Examine integer overflow handling
Compile the following function:

#include <limits.h
int big = INT_MAX;
int
testovf (void)
{
return big + 1 < big;
}

for the x86 in three ways: (1) with -O2, (2) with -O2 -ftrapv, (3) with -O2 -fwrapv. Compare the resulting assembly-language files, and describe and justify the differences that you see. Put your description into a plain ASCII text file testovf.txt.

A few more questions
Answer the following questions, in a plain text file answers.txt:

Explain why the instructions in the third trace did not produce the correct mathematical result. Which instructions caused the problem, exactly?
If you just count instructions, which trace is the most efficient and why?
Similarly, which is the least efficient and why?
Where did the number 536870911 come from? Explain in terms of the Emacs source code.
The two Emacs executables were compiled with GCC's -O2 option. Suppose they had also been compiled with -ftrapv. Explain any problems the traces would run into, or if there would not be a problem explain why not.
Similarly, discuss whether and how -fwrapv would have caused problems.
Suppose we assume -fwrapv is used. Suggest changes to how Emacs does integer multiplication that should help improve its performance. Focus on just the integer multiplication; don't alter the machinery Emacs uses to decide which flavor of multiplication to do.
How significant are the efficiency differences discussed above, in the context of Emacs execution?
Submit
Submit a compressed tarball pexex.tgz containing the files mentioned above, namely pexexlab.txt, trace1.tr, trace2.tr, trace3.tr, testovf.txt, and answers.txt.
Powered by