Due Dates

  • Checkpoint: GOL Code Modifications: before 11:59pm, Wednesday September. 8 push to git repo (I recommend completing this before the due date so you can focus on experiements)

  • Complete Report: at begining of class, Thursday September. 16 turn in hard-copy of your report in class, and push report.tex (and any other files used in report) to your Lab1 repo.

Lab1 Partners

This lab will be done with your Lab 1 Partner

See the documentation on the course webpage about working with partners. It is a brief guide for effective practices and my expectations for how CS students should be working together on labs.

Lab 1 Goals

  • Reminder and practice of pthread programming and thread synchronization

  • Reminder and practice of C programming, using libraries, and C programming tools:

    • 2D arrays and file I/O in C

    • pointers, dynamic memory allocation, and pass by reference

    • debugging threaded programs (gdb and valgrind)

    • using getops library

  • Designing and running experiments for scalability analysis.

  • Evaluating experimental results.

  • Writing a report describing your experimental design and results.

Overview

Main part of lab

Although there is some coding to do that involve changes to your CS31 gol program, the main focus of this lab consists of designing and running experiments to evaluate the scalability of a 2D grid pthreads program. Specifically, this includes:

  1. Developing hypotheses about the scalability pthreads GOL

  2. Designing experiments to test your hypotheses about scalability.

  3. Running initial experiments and analyzing the results to see if you need to re-design your experiments.

  4. Collecting and evaluating experimental results.

  5. Presenting your experimental study in a written report.

The coding part

You will begin this lab by making some minor modifications to your pthreads GOL program from CS31, and then evaluate its scalability.

You and your partner will start with one of your solutions to the CS31 pthreads GOL lab. And review the CS31 sequential GOL lab for input file format and GOL rules. It is possible that your pthreads gol lab may have had slightly different specifications than this one from Fall'17, which is fine for your starting point for this lab. If you used the ParaVisi gui animation in your lab, you will not need that feature in this lab, but you may continue to support it in your code.

gol code changes from CS 31 version

At a minimum you will change your CS31 pthreads gol code in the following ways (more details in GOL Code Requirements):

  1. Use different command line options and use the getops library to parse command line options.

  2. Covert your torus GOL world to a 2D GOL world. This means that edge and corner cells will have fewer neighbors than middle cells.

  3. Fix any bugs and inefficiencies with your CS31 solution, and fix any problems with poor modular design, with missing error handling, and with missing comments.

  4. You do not need to support the ParaVisi animation option. It is fine if you do, but you do not need to (if your ParaVisi part is broken, just comment it out). You should still support the ascii visualization run mode though.

Starting Point Code

Lab 1 repo

If you have not already done so, both you and your partner should:

  1. Create a cs87/Labs subdirectory on the CS system:

    cd
    mkdir cs87
    mkdir cs87/Labs
    cd cs87/Labs
  2. Clone your Lab 1 repo from the CS87 git org:

    git clone [your_Lab01_ssh_URL]

    If all was successful, you should see the following files when you run ls:

    Makefile report.tex run.sh testedges.txt

    If this didn’t work, or for more detailed instructions on git see: Git Help Page

Pick a gol.c starting point

Next, decide whose pthread GOL program you want to use as a starting point. Read over the GOL Code Requirements for the specific pthread code requirements for this lab (particularly requriement (4)). You should look at the code structure of each solution, try running each one (use the Makefile in this repo to build them, not the one you used in CS31), try run in valgrind, and then together decide whose solution you will use as your starting point. I will help you pick one too.

Leave a top-level comment in .c and .h file(s) indicating the authors of your starting point code.

Whichever one you are starting with (or if you want to start from scratch together that is fine too), copy the over pthreads gol.c (and any other .h or .c files) into your cs87 Lab01 repo to use as the starting point for this lab. Make sure the copied version compiles and runs (note: you need to use the Makefile in this repo not yours from CS31), and then add it and any input test files you copied over to your git repo, commit, and push:

cp ~you/cs31/Labs/LabX/gol.c .
git add gol.c
git add Makefile
git add mytestfile.txt
...
git commit
git push

Your partner should now be able to do git pull to grab what you pushed to your shared repo.

You may also want to add to your repo some gol input files that you may have from CS31 for initializing a GOL board (you can easily create new ones too, and you will want to create new ones for large scale experiments).

GOL Code Requirements

Changes from CS31 GOL

Your pthreads GOL solution should meet the requirements of the CS31 pthreads GOL lab assignment, with the following changes:

  1. Turn your torus world into a 2D world. In the 2D version of GOL, edge cells only have 5 neighbors and corner cells have only have 3. For example, the x’s mark the set of neighbors for the three grid cells indicated with a 1 in this world (note: cells have 3, 5 or 8 neighbors):

    1  x  0  0  0  0  0  0  0
    x  x  0  0  0  0  0  0  0
    0  0  0  0  0  0  0  0  0
    0  0  x  x  x  0  0  0  0
    0  0  x  1  x  0  0  0  0
    0  0  x  x  x  0  0  0  0
    0  0  0  0  0  0  0  0  0
    0  0  0  x  x  x  0  0  0
    0  0  0  x  1  x  0  0  0

    You can test correctness with the testedges.txt file (patterns on edges should not wrap around the world across iterations).

  2. Your code should compile with the -Werror=vla gcc flag, don’t remove this from your Makefile. If it doesn’t compile with this flag, it means you have one or more functions in your program that use run-time variable sized array allocation on the stack. This is bad. Instead, space should be dynamically allocated on the heap (via malloc) and then passed into functions that need to use it. You should fix this.

  3. Review your CS31 solution and fix any bugs (including running through valgrind), and any inefficiencies in its parallelization. Your solution should only malloc up space once for the shared game board(s), and malloc up this space before any pthreads are created. All functions that need to access the board(s) should be passed the board(s) as parameters. There should be no mallocs in the function(s) that solves a single iteration of GOL. Make sure that no calls to usleep are made when the program is run without printing out the game board at each iteration. Examine synchronization calls and see if you have any unnecessary synchronization. Often, synchronization needed for printing (ASCII animation run mode) is in the main control flow, and should be moved into the printing execution path only. And make sure it is implemented using good modular design and is well commented. Fix it if not.

  4. Your program should support the following command line options, using this syntax ( options in [ ] are optional (meaning the user does not need to include them in a command line)), and use the getops library to define command line options and parse argv command lines:

       ./gol -t t { -n n -m m -k k [-s] | -f infile} [-x] [-c]
           -t  t:      number of threads
           -n  n:      number of rows in the game board
           -m  m:      number of columns in the game board
           -k  k:      number of iterations
           -s:         initialize to oscillator pattern (default is random)
           -f infile:  read in board config info from an input file
           -x:         disable ascii animation (printing out board every iteration)
                       (default is to run with animation/printing)
           -c:         do column partitioning (default is row portioning)
           -h:         print out this help message

    This syntax for command line arguments supports command line arguments in any order and optional command line arguments. Optional command line arguments are ones the user does not need to specify in a command line, they are not optionally required for you to support: (you need to implement support for all optional and all required command line options in your program). You will use getopt to parse command line arguments (more details below). The example getopt code on this page uses a C switch statement. If you are not familiar with switch statments, see Chapter 2.9.1 switch stmt in the Dive Into Systems textbook.

    NOTE: if your CS31 pthreads gol also included a run mode with a ParaVisi gui animation, you DO NOT need to support this run mode for this assignment. If you choose to leave it in, then you should add another command line option to enable this run mode (-g). Otherwise, remove the Paravisi gui code paths from your gol.c file. I suggest making this change before the others, and compile and test out your gol with the CS31 command line options, then commit these changes before doing the others.

Command Line Options

The command line options specify how to initialize the game and how to run the simulation.

There are two ways to run gol and initialize the game board:

  1. the -f command line option means that the GOL problem size and initial state are read in from a file:

    ./gol -t 16 -f infile  # init to values read in from the file "infile"
  2. or the -n -m -k [-s] command line options are used to specifying the dimensions, number of iterations, and the starting point world initial configuration:

    ./gol -t 4 -n 20 -m 30 -k 100 -s   # init a 20x30 board to oscillator pattern
    ./gol -t 4 -n 20 -m 30 -k 100   # init a 20x30 board to random pattern
                                    # about 25% of randomly selected cells
                                    # to 1 works okay, but you decide
                                    # use column-portioning across threads

These two modes are independent---you cannot have a command line with both the -f and -m options.

The -t option is required and works with both initialization modes.

The -x and -c options are optional and work with either initialization mode. The -x option is necessary when running timed experiments. If the -f option is NOT used, then the board is initialized to one of two patterns:

  1. The -s option specifies that the board should initialize a single oscillator pattern in (or close to) the center of the board. The oscillator pattern is 3 live cells in a row, either vertically or horizontally.

  2. If -s isn’t specified, then the board should be initialized to some random pattern. To generate random numbers in C use the rand function. You will also likely want to seed the random number generator by calling srand and passing it the current time value. Here is some example of how to call srand and rand:

    #include <stdlib.h>
    #include <time.h>
    
    srand(time(NULL)); // call ONLY ONE TIME in program to seed rand num generator
    
    int val = rand();  // returns the next random number between 0 and RAND_MAX

    Use the random value in some function to decide if a cell is 1 or 0. The mod operator in C is % (e.g. 10 % 3 is 1) Be careful in your random init function to make sure you are not setting too large a proportion of the world’s cell to live…​all cells may die after a few iterations if the world is too overpopulated.

Here are some example command lines:

# initialize 20x30 board to an oscillator pattern, run with 8 threads
# print out board to stdout after each iteration:
./gol -t 8 -n 20 -m 30 -k 100 -s

# initialize program from data read in from "infile", run with 16 threads,
# column partition, do not print any output to stdout for this run
./gol -t 16 -f infile -c -x

# run with 4 threads, init board from file, row partition, do not print to stdout
./gol -t 4 -f infile -x

Your program should handle badly formed command lines (e.g. print out an error message and exit instead of using incompatible or incomplete command line options).

File Format

The input file format is identical to that of the sequential (and pthreads) GOL labs from CS31: GOL file format

Additional Requirements

In addition to the requirements listed above, your GOL solution should:

  • Have timing code in your solution around the GOL main computation (don’t include grid initialization or outputting the result to a file). Use gettimeofday.

  • Calls your program makes to usleep and system("clear") to implement animation of the game board should only be made when the program is run in board printing mode; runs with the -x command line option should not trigger any calls to usleep).

  • Use perror to report errors from system calls.

  • Detect and handle all errors. Your program can call exit(1) if the error is unrecoverable (after printing out an error message of course) This means that any time you call a function that returns a value, there should be a check for error return values and they should be handled: do not just assume that every function call and every system call is always successful.

  • Your solution should be correct, robust, and free of valgrind errors

  • Your code should be well-commented code and use good modular design. See my C documentation for C references and a C code style guide.

Experiments

Designing

You will design and run experiments that will answer questions about the scalability of your solution. Your experiments should answer questions about scalability in different ways. Some parameters to consider varying in your experiments:

  • The grid sizes. Try different powers of two (64, 128, 256, 512, 1024, 2048, …​) You do not have to try every power of two between your min and max sizes, but run a several intermediate sizes between your smallest-sized and largest-sized boards.

  • The number of threads. Again, increase by powers of two: (1, 2, 4, 8, 16, 32, …​), and/or multiples of the number of cores on the machine you are running, and again you do not need to include every power of two between your min and max.

  • Compare row-wise vs. column-wise board partitioning.

  • The number of iterations (try a couple different values that show differences across runs). In general you should you should run each gol experiment for many iterations so that there are multiple synchronization points in a run and as a result you can see some synchronization effects on scalability.

    Number of iterations alone is not a particularly interesting test, but you want to play around with this a bit to find good numbers to get some meaningful runtimes (e.g., if all your column vs. row partitioning experiements run in just a few seconds, the results are not meaningful for making any conclusions about the effects of partitioning).

    When you first test out some of your experiment sizes, particularly for your experiments evaluating the scalability of board sizes that scale up to very large sizes, you may want to reduce the number of total gol iterations to something relatively small so that the really large board size runs don’t take forever. However, you should still have several iterations per run in this case so that there are some synchronization overheads.

When running scalability studies you need to make sure that you have problem sizes that are large enough to result in fairly long run times for at least some numbers of threads. For example, if the single threaded run takes 1.3 seconds and the 16 threaded run takes 1.2, it is pretty difficult to draw any conclusions about scalability by comparing these two small runtimes. Instead, you want some runs that take many seconds to many minutes.

Also, think about what you are holding constant and what you are varying in a particular set of experimental runs so that the results of the experiment produces meaningful results for testing your hypothesis.

Running Experiments

As you run experiments, make sure you are doing so in a way that doesn’t interfere with others. We describe some resources below (and in Handy Resources) to help you ensure this. You can also make use of machines that are dedicated for CS87 students. Also, remember to remove all output statements from the code you time (run without printing the board or anything else).

You should run multiple runs of each experiment. For example, don’t just do a single timed run of 16 threads for 512x512 and 10 iterations, but run this same experiment multiple times (5 or 10 times each). The purpose of multiple runs is to determine how consistent your times are (look at the standard deviation across runs), and to also see if you have some odd outliers (which may indicate that something else was running on the computer that interfered with a run, and that you should discard this result).

Be careful to control experimental runs as much as possible. If other people are using the machine you using to run experiments, their use can interfere with your results. Here are some resources to see what is going on on machines:

  • who to see who else is on a machine you are running on, and try another machine if you are not alone.

  • top -H or htop to see the system load on the machine. The -H lists individual threads running on the machine (you can see your 4, 8, 16, etc running). htop provides a nice gui interface to these data.

  • Memory usage: make sure that the grid sizes are not too large to fit in RAM. I don’t think this really will be a problem, but double check your a run with your largest sizes before running experiments to see if the system is swapping. htop will show if the swap partition is being used, you can also look at some information in /proc. As your programs run, in another window run:

    watch -n 1 cat /proc/swaps
    Filename                                Type            Size    Used    Priority
    /dev/sda2                               partition       2072344 0       -1

    If you notice the Used value going above 0, your grid sizes are too big to fit into RAM (or there are too many other memory intensive applications running on this machine), and you need to find an idle machine.

  • Using screen or tmux for running long-running experiments is useful. Also making use of script and writing and using bash shell scripts to run experiments is very helpful. See Resources for Experiments and Writing for more details on using these.

  • cron is useful for submitting jobs on a specific machine at a particular time (for example, you could use cron to run your experiement run script at 3am). See Handy Resources for more information about cron.

Machines for Experiments

CS lab machines

You should use CS lab machines to develop and run your set of experiments, any lab machines are fine to use. However, please avoid running intensive experiments on CS lab machines in 240, 256 or Clothier during times when classes are scheduled in those room. Trying some experiements on machines with different numbers of cores.

  • To find machines with different numbers of cores, start by looking at Lab Machine specs page contains information about most of the CS lab machines, including the number of cores (click on the processors link). The number of CPUs is the number of hyperthreaded cores, and the number of cores is the number of actual physical cores. All lab machines have multi-core processors, most of which are dual-hyperthreaded (e.g. physically 8 cores, but logically 16 cores).

    To determine the number of physical vs. hyperthreaded cores, log into the machine and cat out the /proc/cpuinfo file or run lscpu:

    ssh rattata       # ssh into lab machine of interest (rattata in this example)
    
    lscpu         # total cores is (num cores per socket) * (num sockets)  (8 total)
                  # total hyperthreaded cores is listed as num cpus (16 total)
                  # or (theads/core)*(cores/socket)*(sockets)
    
    lscpu | grep -E '^Thread|^Core|^Socket|^CPU\('  # list just fields of interest
    
      CPU(s):                          16           # total hyperthreaded cpus
      Thread(s) per core:              2            # hyperthreads per core
      Core(s) per socket:              8            # cores per chip
      Socket(s):                       1            # number of chips
    
    # lscpu gets its info from /proc/cpuinfo which you can also use to see
    # this an other cpu information:
    
    cat /proc/cpuinfo                    # list info for each hyperthread cpu
    
    cat /proc/cpuinfo | grep processor   # number of hyperthreaded cpus per chip (16 total)
    cat /proc/cpuinfo | grep cores       # the number of physical cores per chip
                                         # (8 total, each is dual-hyperthreaded)
    
    # total number of cores is (number per chip * number of chips) the physical id
    # total number of hyperthreaded cores is  (number per chip * number of chips)
    # the physical id listed with each cpu indicates the number of chips
    # (1+max physical id) is number  of chips  (rattata has 1)
    
    # you can pipe output to grep to list only the fields of interest for each cpu
    cat /proc/cpuinfo | grep -E '^siblings|^core|^cpu\ cores|^physical'

machines just for CS87 students

  • CS87 students also have exclusive access to a set of 8 core machines, and have access to chervil with 16 physical cores and 32 hyper-threaded cores.

    • There are 12 machines reserved for only for cs87 students. You may use these for both your initial experiments, and some final experiements. Most are 8-core machines, but some are only 4-core. You should share all of these for testing, but I’ve assigned you each a "first choice" machine for your initial testing and experiment development to distribute the load. You can also use any other CS lab machine, but check the load. If a machine is down email local-staff, and again, you should all share these machines.

      cs87a (8 core): Group 1           stew    (4 core): Group 9
      cs87b (8 core): Group 2           moltres (4 core): Group 10
      cs87c (8 core): Group 3          cucumber (4 core):
      cs87d (8 core): Group 4          cardamom (4 core):
      cs87e (8 core): Group 5
      cs87f (8 core): Group 6
      cs87g (8 core): Group 7
      cs87h (8 core): Group 8
    • chervil is one of my research machines with 16 physical cores, and 32 hyper-threaded cores. Only CS87 students have access to it. For at least some, and possibly all, of your final experiment runs use chervil. You may use chervil to develop and test your set of experiments too, but please be mindful that all groups need some alone time on this machine for final experiment runs. I will likely set up a google signup sheet next week to reserve times to run your experiements alone on chervil.

      This machine will provide an isolated platform for final experiment runs. Each group will need to take turns on this machine for running their final set of experiments, so as not to interfere with each other’s results.

      I’ll add a google sign-up sheet for you to reserve some runtimes on chervil over the next week.

Using and finding machines for experiments

  • As much as possible, it is good to run all or each related set experiments on the same machine, or at least on identical machines. However, it may be intersting to see a few runs of the same problem size on machines with different numbers of cores.

  • You should use chervil (our 16 core machine) for final runs of some of your experiements (not all have to be run on chervil, but this is a machine that has the most physical cores, so will be useful for some stress testing of some of your experiements).

  • Finally, be aware of other groups wanting to run experiments on the 8 and 12 node machines reserved for our class and on chervil. So, please don’t run experiments on a machine for hours and hours or days and days. And, logout when you are not using a machine to run experiments. You can run who to see if someone is logged in, and run run top -H or htop to help you guess/see if a machine is currently used, before deciding it is okay for you to use to run super intensive experiments. And please log out of CS lab machines when you are done using them so that it is easier for others to tell if the machine really is being used or someone just didn’t logout and left atom and web browsers running (this is the normal state in which you will find most CS lab machines, and it is often difficult to tell if someone is actually using the machine when you ssh into one…​just check by running who and top, and guess as best you can). And remember, for the machines reserved for 87, someone may be logged out but running a lot of experiements in a screen or tmux session, so make sure to run top for a minute or so to be certain it is not in use.

    Here is some information about tools (like htop and smarterSSH to help you find machines with low load on our system for running your experiments.

Written Report

Write a 3-4 page report (3 is min, 4 is max) that describes the results of your experimentation. You must use the latex and the report.tex template included in your Lab 1 repo.

  • report.tex contains some commented-out examples of latex formatting for figures, tables, lists, etc. Uncomment to try out.

  • make report compiles report.pdf, make clean to clean up all pdflatex generated files.

  • report.tex is a simplified version of my latex report template (available here ~newhall/public/latex_examples/report). It includes some examples of some latex formatting (tables and including figure) that you want to use in your report.

  • see my latex links below for help with latex.

Your report should include the following sections:

  • Introduction: a brief introduction to what this report is about

  • A description of the experiments you ran. For each experiment presented:

    • What is the hypothesis the experiment is designed to test?

    • What was the experiment?

    • Why does this experiment test this hypothesis?

    • What did you vary, what machine(s) did you run on, how many runs of each experiment.

    • Also, briefly describe what you thought the expected outcome would be and why? It is fine if your expected outcome was different than what your experimental results show.

  • Experimental results: present your results AND describe what they show. You can use tables or graphs to present the data. Choose quality over quantity in the data you present. A couple graphs and/or tables with data that show scalability results in terms of number of threads and problem size is fine. It is also okay to present and discuss negative results…​ "we thought the X experiment would be better because…​,but as shown in Table 2, the Y experiment performed better. This is (or we think that this is) because …​".

    There is, however, a difference between negative results (well designed experiments that produce unexpected results) and bad results (results from poorly designed experiments).

    Also, here is a nice description of strong and weak scalability. You do not need to present your result data in terms of strong and weak scalability functions (and it is fine (and likely) that you will have results that only measure strong scalability). Instead, using Speed-up (Sequential Time/Parallel Time) or average run times (with stddev) over different axes of change is likely a more meaningful way to present your results. However, it may be useful to know the difference between these two when presenting or discussing some of your results in your report.

  • Conclusions: what did you learn from your experiments? what do they say about the scalability of your solution? did they match your expectations? if not, do you have an idea of why not?

Handy Resources

top level help pages

for pthreads GOL

  • The CS31 pthreads GOL lab and the CS31 sequential GOL lab assignment have hints and resource for implementing the GOL and pthreads GOL programs. Note who is responsible for allocating and freeing memory space passed to (and returned by) these routines, and note return values and check for and handle error return values.

  • The man pages for C library, system calls, and pthread functions are very helpful.

    In addition I have links to pthreads documentations and tutorials off my help pages.

  • getopt command line parsing.

    I also have an example program using getopts that you can copy over and try out:

    cp -r ~newhall/public/getopts_example/* .
  • Chapter 2 of Dive into Systems covers C programming, structs, pointers, pass-by-pointer parameters, switch statment, dynamic memory allocation, etc. And some other C programming references.

  • rand and srand C library random number generator and seeding function (pass srand time(NULL) to seed with current time).

  • valgrind and gdb guides. Also see Chapter 3. Also, guide for using gdb to debug pthread programs.

  • atoi converts a string to an integer. For example, int x = atoi("1234"), assigns x the int value 1234. See the man page for more info and similar functions: (man 3 atoi)

  • use perror to print out error messages from failed system calls:

    FILE *in;
    in = fopen(input_file, "r");
    if(in == NULL) {
      perror("fopen failed. Exiting\n");
      exit(1);
    }
  • gettimeofday to add timing code around jut the GOL game playing part of your code (you should already have this in your CS31 starting point, see the CS31 GOL assignment page for more details if not)

  • File I/O in C (you should not need to modify the file I/O part from your CS31 solution).

  • make and writing Makefiles

Experiments and Writing

  • See the Running Experiments section for information about choosing machines and running on chervil.

  • Here are some useful tools vim, ssh, scp, tmux, finding idle machines, latex, git, …​

  • See my Tools for examining system and runtime state for some tools you can use to determine the

    • top, htop, who, xload to get system usage info. top -H or htop dynamic display of information about system resource usage of the current threads that are the biggest consumers of CPUs. You should see your gol threads rise to the top (when running without any animation). You can also use this to see if someone else is using a machine for experiments (in which case you should pick another one).

    • proc/ more useful system info. You can cat out files in here to find system-wide or per-process information: meminfo prints information about system memory use; cpuinfo prints information about the cpus, including L1 cache and cache line sizes.

      $ cat /proc/cpuinfo
      $ cat /proc/cpuinfo | grep cores
      $ cat /proc/cpuinfo | grep procesor
      $ cat /proc/meminfo
  • My Tools for running experiments and collecting performance measurements screen or tmux, script, cron, and bash scripts may be particularly useful. To avoid losing test results, I suggest either redirecting test output to a file, or running experiments in script, which will save all terminal output in a file (the default name is typescript). Just run script outfile, start your experiments on the command line, and then run exit to exit out of script. All the terminal output will be saved in a file named outfile. You can clean up the output file a bit by running dos2unix on it:

    $ script results
    Script started, file is results
    % ./run
      ...
    % exit
    Script done, file is results
    $ dos2unix -f results
    $ dos2unix -f results
  • time ./a.out show the total runtime, and user and system times associated with executing a.out.

  • shell scripts: You can write and use shell scripts for running a set of experiments. With your repo is one example of a bash script for running a set of experiments that you can use as a starting point for different run scripts to run sets of your experiments. Here is another example

    To run a bash script file, first make sure the script file is executable:

    ls -l                   # lists file permissions (rwx)  x: execute is set
    chomd 700 testrun.sh    # sets rwx permission for file owner if needed
    ./testrun.sh            # then you can run the script
    ./testrun.sh  > resultfile

    It is often useful to redirect the output from these runs to a file. For, example to redirect stdout and stderr to a file named "resultfile":

    ./testrun.sh  > resultfile

    Or to run your bash script inside script to capture its output to a file.

    See bash shell programing links for more information.

  • tmux or screen are useful for running a long set of experiments: you can run scripts from within a screen session late at night, wake up the next morning re-attach to the screen session and see the results.

  • latex info and latex links. latex is Unix’s document writing software. You do not have to use latex for writing your report, but it has very good support for some things that are common in scientific writing such as representing mathematical expressions, so you may want to give it a try. I have some example latex documents that you can grab to use as a starting point in ~newhall/public/latex_examples/.