EDAN25 Multicore Programming Lab 5

The course home page is here.

The purpose of this lab is to understand C++ Atomics and compare its use with locking.


  1. Log in to power.cs.lth.se.

  2. Download the file lab5.zip, unpack, cd to it and type ./t

  3. The program a.cc should compile and then abort due to wrong output.

  4. The program has one producer and four consumers. The computation is to compute factorial for small integers and accumulate the sum of these into a variable sum. Of course, we need some synchronization...

  5. Add a mutex variable and a condition-variable to the worklist_t class to protect it. Also protect the sum variable. Read the hint in the get method (and change the #if 0 to #if 1, or remove the #if/#endif pair).

  6. Your program should work now, and it will time itself 10 times.

  7. The Power architecture has a register timebase which can be used for fine-grained timing measurements. This register is read in tbr.s. How often this register is incremented is different for different Power implementations, but can be read on Linux in the "file" /proc/cpuinfo (files in that directory are not real files but are created by the kernel when somebody needs them). Due to cache and scheduling effects the execution time varies between runs, which is normal with many multithreaded programs.

  8. Although most of the time is spent in the put and get functions, a first step in improving the performance in this program is to make the sum variable atomic.

    Copy the a.cc file to b.cc. In general, make optimizations in new files and call them c.cc, d.cc, e.cc, etc. This will make performance comparison easier.



  9. You can declare sum as follows:static std::atomic sum;

  10. Did you notice any difference when using an atomic variable?

  11. Copy b.cc to c.cc, and implement a spinlock with an atomic flag. A spinlock is a "busy wait" lock which is suitable in multicores when the expected waiting time is low.

  12. To implement a spinlock class, you probably find the following useful:

  13. Copy c.cc to d.cc.
  14. Copy c.cc to d.cc again and use instead sum.fetch_add(f, std::memory_order_relaxed).

  15. Copy d.cc to e.cc and try to use other atomic operations to get the execution time below one second. A hint is to use flag.compare_exchange_weak with explicit memory ordering in the spinlock. To do that, you cannot use the type std::atomic_flag. Use instead for instance std::atomic flag.





Wed Oct 7 10:35:02 CEST 2015