Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmt_throughputbenchmark
[Package bslmt]

Provide a performance test harness for multi-threaded components. More...

Namespaces

namespace  bslmt

Detailed Description

Outline
Purpose:
Provide a performance test harness for multi-threaded components.
Classes:
bslmt::ThroughputBenchmark multi-threaded performance test harness
Description:
This component defines a mechanism, bslmt::ThroughputBenchmark, that provides performance testing for multi- threaded components. The results are loaded into a bslmt::ThroughputBenchmarkResult object, which provides access to counts of the work done by each thread, thread group, and sample, divided by the number of actual seconds of execution.
Structure of a Test:
A test is composed from one or more thread groups, each running one or more threads. Each thread in a thread group executes a thread function, with a simulated work load executing between subsequent calls to the thread function. To provide reliability, the test is executed multiple times. A single execution of a test is referred to as a "sample execution" and its result referred to as a "sample". To support fine tuning of the test, it is possible to provide initialize and cleanup functions for a sample and / or a thread.
Usage:
This section illustrates intended use of this component.
Example 1: Test Performance of bsl::queue<int>:
In the following example we test the throughput of a bsl::queue<int> in a multi-threaded environment, where multiple "producer" threads are pushing elements, and multiple "consumer" threads are popping these elements.
First, we define a global queue, a mutex to protect this queue, and a semaphore for a "pop" operation to block on:
  bsl::queue<int>  myQueue;
  bslmt::Mutex     myMutex;
  bslmt::Semaphore mySem;
Next, we define a counter value we push in:
  int              counterValue = 0;
Then, we define simple push and pop functions that manipulate this queue:
  void myPush(int threadIndex)
      // Push an element into 'myQueue', using the specified 'threadIndex'.
  {
      bslmt::LockGuard<bslmt::Mutex> guard(&myMutex);
      myQueue.push(1000000 * threadIndex + counterValue++);
      mySem.post();
  }

  void myPop(int)
      // Pop an element from 'myQueue'.
  {
      mySem.wait();
      bslmt::LockGuard<bslmt::Mutex> guard(&myMutex);
      myQueue.pop();
  }
Next, we define a thread "cleanup" function for the push thread group, which pushes a couple of extra elements to make sure that the pop thread group will not hang on an empty queue:
  void myCleanup()
      // Cleanup function.
  {
      bslmt::LockGuard<bslmt::Mutex> guard(&myMutex);
      for (int i = 0; i < 10; ++i) {
          myQueue.push(counterValue++);
          mySem.post();
      }
  }
Then, we create a bslmt::ThroughputBenchmark object and add push and pop thread groups, each with 2 threads and a work load (arithmetic operations to consume an amount of time) of 100:
  bslmt::ThroughputBenchmark myBench;
  myBench.addThreadGroup(
                      myPush,
                      2,
                      100,
                      bslmt::ThroughputBenchmark::InitializeThreadFunction(),
                      myCleanup);
  const int consumerGroupIdx = myBench.addThreadGroup(myPop, 2, 100);
Now, we create a bslmt::ThroughputBenchmarkResult object to contain the result, and call execute to run the benchmark for 500 millseconds 10 times:
  bslmt::ThroughputBenchmarkResult myResult;
  myBench.execute(&myResult, 500, 10);
Finally, we print the median of the throughput of the consumer thread group.
  double median;
  myResult.getMedian(&median, consumerGroupIdx);
  bsl::cout << "Throughput:" << median << "\n";