Assignment 1: High Performance Matrix Multiplication on a CPU

Due: Friday, October 9th, 2015 at 8pm


Changelog

Date Description
25-Sep-15 Original posting
7-Oct-15 Added comment about specifying custom optimizations


Your assignment is to optimize matrix multiplication to run on a single core of Bang. Your starting point is a an implementation that performs one level of cache blocking, along with a test harness for evaluating performance. This implementation will behavior poorly, and you will be able to make it go significantly faster. We have also provided a variant that invokes a heavily optimized matrix multiply routine, provided by the ATLAS library. This reference variant will enable you to assess performance goals. ATLAS will outperform most "home made" implementations. See the references at the end to learn more about useful optimizations.

The assignment includes a 2-3 page report, which is important part of the assignment. The requirements for your report are described later in this document.

Part 1. Getting Started with GitLab

All assignments will be turned in using UCSD's GitLab. The turnin procedure is described below in the section "Turning in your assignment". In this section, we'll go over how to set up your repository.

You must follow these steps to get the starter code and to get set up to do assignment 1.

Refer to the link below for instructions on how to obtain the starter code to get started on your assignment

A1 Git Instructions

Try to make your code go as fast as you can. In the spirit of friendly competition, post your performance results to the A1 Piazza Folder. We will post a summary of the class' results on-line.

Your grade will based on 4 factors: performance attained by your implementation; correctness, well-displayed results and comments and explanation and insight into how you realized your reported performance. In determining your grade for the assignment, explanations and insight will be emphasized somewhat more heavily than performance itself, unless there was little improvement in performance over the provided naive code.

Part 2. The Assignment Checklist

  1. Add a second level of cache blocking. Modify the code in the file dgemm-blocked.c that implements the blocked algorithm. This is Algorithm 3 described in the Demmel on-line reader. This module must implement the routine square_dgemm using the same signature as in the provided code, but with two levels of blocking. Note that, as discussed in class, a second level of cache blocking won't improve performance much, but is a requisite step to further optimization that will improve performance significantly.

  2. Perform other optimizations to increase performance. Be sure to get the innermost loops to vectorize. As a minimum, you will need to use SSE intrinsics combined with register blocking. Consult the tips below for how to improve performance. Your performance goal is between 4 and 5 Gigaflops/second averaged over the complete set of inputs specified in the provided driver program dgemm-blocked. While it is possible to reach nearly theoretical performance for certain inputs (ATLAS can realize 8 GFlops, where the peak for Bang's processors is 9.32 GFlops), performance will vary over the full range of inputs.

  3. Verify correctness. The provided code will test for correctness in the test harness, benchmark.c. Do not modify any code in this file, as we'll be substituting an unmodified copy when grading your assignments.

  4. Conduct a performance study. Measure the GigaFLOP rate of your code for a few dozen values of N ranging from N=256 to 769. Do this for your improved implementation only; there is little point in performing such a careful study on a slow implementation! The code stores a list of values of n in a static array, and the longest list, currently uncommented provides a complete study. In your early testing use one of the shorter lists to save time. Also report results with the provided naïve code, using 6 different values of N spaced throughout the range you used to test the naïve implementation.

    Specific report requirements. Your report must present certain measurements, but feel free to add others if they illuminate your understanding of high performance matrix multiplication on Kepler. Plot the speedup of your optimized algorithm against the provided naïve code for the values you selected to evaluate the naïve code.

  5. Report and comment on your results. The assignment includes a report, which will present and discuss your experimental results as well as your optimizations. The general requirements for your report are described in §6.2 below:
    Required files in the submission.

  6. Requirements.

Part 3. The Provided Starter Code

We've provided you with starter code that implements the naive ijk algorithm and a single level blocked implementation that uses cache more efficiently. In addition, we've provided an implementation that uses an optimized version of the BLAS (provided by the ATLAS library, which is installed on Bang) to enable you to assess performance of your 2-level blocked implementation. This code has been installed in the UCSD GitLab repository:

 https://git.ucsd.edu/cse260-fa15/pa1-provided 

To build your code, use the provided Makefile, which sets up the appropriate flags for the compiler via an included "arch" file located in in $(PUB)/Arch Do not change the name of the target used in the Makefile nor add additional file names to the Makefile, as we'll be grading your assignment with our own Makefile.

If you'd like to experiment with custom compiler optimization settings (the default is -O3), you can do this by setting, on the command line, a Makefile variable called MY_OPT. For example, if you'd like to specify -O4 -fopenmp, you may do so in one of two ways:

make MY_OPT=-O4\ -fopenmp

make MY_OPT="-O4 -fopenmp"

The effect of setting MY_OPT is to redefine the OPTIMIZATION macro in the Makefile (currently set to -O3). It follows that you may also define custom C pre-processor macros in a similar way:

make MY_OPT="-O4 -DFLAG"


Part 4. How to Take Timings

Use a qlogin node when taking timings. The provided code includes timer calls, which are based on gettimeofday(). For any given combination of N and optimization, take at least 3 timings and report the minimum.

You'll notice that at the end of the run, you'll get two lines of output as follows, which lists the input size -n, the number of repetitions -r, the Gigaflop rate and running time, and the grind time (the running time divided by the product of N and the number of repetitions):


        N    Reps      GF          t_blas      tg_blas
@   1024    50   2.23e+01   9.64e-02   8.97e-11

If you are doing several runs, you can quickly search for the string "@ " (starting in column 1) to extract the performance data from your job output files and process it for plotting (likely with a script).

Part 5. Tips on performance optimization

Basic cache blocking, as explained in class, is a requisite first step but alone is not sufficient to reach even half the processor's peak performance. To improve performance still further, try non-square tiles. Another good optimization is to tile for registers: unroll innermost loops and use named variables to store copies of the matrices. The tiles will be small, limited by the number of registers (16x128 bit registers on the Nehalem, see the details in Michael Thomadakis' paper). Though you won't be able to reach ATLAS' performance without auto-tuning and SSE intrinsics, you will be able to see an improvement beyond basic blocking if you try the strategies described above. See Brian Van Straalen's notes on vectorizing with SSE intrinsics or Jim Demmel's Lecture slides, slides 61-71. There are additional References below.

Feel free to learn from the source code of state-of-art BLAS implementations such as GotoBLAS and of course ATLAS, which is installed on Bang. However, you should not reuse those codes in your submission.

If you are working on a desktop or a laptop, shut down all open applications. Do not run on a machine shared with other users, unless you are sure that no-one else is running at the time you conduct your runs. (Even then beware of daemons and other system activities that can affect your results) If the timings are inconsistent across runs, other activities are occupying the processor and must be stopped.


Part 6. Turning in your assignment

6.1 Submission via GitLab

When you have completed the assignment, you must submit it. You will do this by pushing your changes to GitLab. Follow these steps (which are more or less the same as the steps from the "pushing changes to GitLab" section above:

  1. Run a ’git status’ to see what files have been changed.
  2. Use ’git add <files>’ to stage certain files for a commit, use ’git add .’ to add all files in the working directory to the commit (hopefully you will not be doing this at this late stage—all files should already be in your repository!)
  3. Use ’git commit -m "FINAL SUBMISSION"’ to commit the changes to your repository and indicate that you are done and this is your final submission.
  4. To push your changes onto your repository on GitLab run ’git push origin master’ Don’t forget this push! You must do this to get credit.
  5. As an added safety check, you should log on to GitLab on the web and verify that your push went through.

Some of the finer points about this process:

6.2. Required files in the submission

6.2.1. Source code

Even though we will be substituting fresh copies of all but one source module, include all code files your worked with, in case we need to unravel a problem with your turnin. For this reason, also include your Makefile.

6.2.2. 2 text documents

Your turnin must also fill in two important documents, which accompany the provided code. These documents are required and we will not report a grade for your assignment without them. A 10% penalty will be assessed in cases of missing forms, empty forms, or forms not properly filled out.

  1. A completed self-evaluation discussing your work; if in a team this form address the division of labor and other aspects of how you worked together as a team.
  2. A file named DECLARATION, that states that the work was your own, and that you did not violate the Academic Integrity policies in effect for the course. Modify the DECLARATION by filling in your correct login ID(s) and the date only. Don't change anything else.

6.2.3. Lab Report, a PDF document

This file must have the following format. The stem part of the file name (before the .pdf) should begin with "A1-report" and end with your repository name, e.g. A1-report-baden-powell.pdf.

Document your work in a well-written, two to three page report, including plots, which presents your results, analyzes them, and offers insight. Your report should present a clear evaluation of the design of your code, including bottlenecks of the implementation. If you improved performance of your code in a sequence of steps, document the process. If you like, summarize the information in a list or a table in your report. If necessary, provide pseudo code to illustrate the concepts. Be sure to thoroughly explain the results presented in your plots, relating them to how you designed the code. Discuss the design decisions you made to improve performance, including any negative results.

An important part of your report is your analysis. That is, to provide insight that explains your results. For this reason, if you are running out of time, put more effort into the writeup and your analysis rather than trying yet another performance enhancement. It can take time to collect, tabulate and plot results, as well as offer a reasonable explanation. We prefer a deeper analysis involving a few program optimizations over a shallower analysis over a larger number of optimizations. Spend more time discussing the optimizations that made a difference and less on those that made less of a difference. Negative results are also especially valued if you carefully document them, with the underlying causes, or best guesses if the causes are unclear.

Do not include full code listings in your writeup as these will be in your turnin.

Take care in how you plot your data, plotting only what's necessary to get your points across. Choose log and linear plots carefully, to take advantage of the plotting space. You must also include any plotted data in tabular form. Tabular data may be included electronically (in your turnin) as a spreadsheet or other document called, e.g. Data.xlsx, Data.txt. Be sure to provide a caption for each plot or table that describes the experiment you conducted, e.g. "strong scaling."

Cite any written works or software as appropriate in the text of the report. Citations should include any software you used that was written by someone else, or that was written by you for purposes other than this class. In such cases you must talk with us (and any code co-authors) prior to get approval.

7. Grading

There are 10 possible points on the assignment and your grade will depend on 4 factors: performance attained by your code, correctness, well-displayed results and comments. You must not only put comments inside your code, but every time you commit to your repository. There should be a steady stream of comments that enable us to retrace your development steps.

Your performance score is divided into two parts. You'll get the bulk of those points for reaching 4 GFlops, but to get all points on performance, you must realize 5 GFlops. Again, these figures are averages taken over the full range of input sizes specified in the driver program, and not for individual inputs. While it is possible to approach the speed of the ATLAS (about 6.8 GFlops (about 70% of the processor's peak theoretical speed) it can take time to realize this performance, so beware!

We will grade your code (on bang) using our own Makefile. Our Makefile will compile your code using gcc and and then link it with the test driver which is similar to dgemm-blocked.c We will use the same compilation flags as in the provided starter code. To get full credit, design, style and comments (including gitlab commit comments) count.


☛ Important.

Don't wait until the last minute to attempt a turnin for the first time. Try out the turnin process early on so you are sure that you you are familiar with the process, and that all the required additional files are present.

You will receive 0 points for this assignment if your code does not compile, including cases of non-compilation due to merge conflicts. If you developed your code on another machine you are responsible for properly testing on bang, else you may lose significant credit, possibly all 10 points depending on the circumstances. As mentioned previously, you must ensure that you resolve all of your merge conflicts and that your code compiles and runs correctly IMMEDIATELY BEFORE you push to GitLab.

For this assignment staff will attempt intervene manually to fix problems. However, the policy for such manual intervention is as follows. If any manual intervention is required by staff you will lose at least 2 points. Included are: incorrectly naming your GitLab repository, or misspelling the words FINAL SUBMISSION in the commit message. Lastly, the only files you should be pushing to GitLab are text files: source code and ASCII test files. Do not push large binaries such as the executables or media files, as doing so could lead to problems such as losing the ability to push to GitLab. Staff will not intervene under these circumstances and you you may be unable to complete your assignment by the deadline. If you commit binaries, you are doing so at your own risk.


Part 8. Sources

Here are various sources of information that can help you optimize your code. The primary sources are seminal references. The Intel "SSE cheat sheet" will come in handy.

Part 8.1. Primary sources

Part 8.2. Reference

Part 8.3. Documentation


[Tue Oct 6 14:47:24 PDT 2015]