BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_throughputbenchmarkresult.h
Go to the documentation of this file.
1/// @file bslmt_throughputbenchmarkresult.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_throughputbenchmarkresult.h -*-C++-*-
8
9#ifndef INCLUDED_BSLMT_THROUGHPUTBENCHMARKRESULT
10#define INCLUDED_BSLMT_THROUGHPUTBENCHMARKRESULT
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslmt_throughputbenchmarkresult bslmt_throughputbenchmarkresult
16/// @brief Provide result repository for throughput performance test harness.
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslmt
20/// @{
21/// @addtogroup bslmt_throughputbenchmarkresult
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslmt_throughputbenchmarkresult-purpose"> Purpose</a>
26/// * <a href="#bslmt_throughputbenchmarkresult-classes"> Classes </a>
27/// * <a href="#bslmt_throughputbenchmarkresult-description"> Description </a>
28/// * <a href="#bslmt_throughputbenchmarkresult-usage"> Usage </a>
29/// * <a href="#bslmt_throughputbenchmarkresult-example-1-calculate-median-and-percentiles"> Example 1: Calculate Median and Percentiles </a>
30///
31/// # Purpose {#bslmt_throughputbenchmarkresult-purpose}
32/// Provide result repository for throughput performance test harness.
33///
34/// # Classes {#bslmt_throughputbenchmarkresult-classes}
35///
36/// - bslmt::ThroughputBenchmarkResult: results for multi-threaded benchmarks
37///
38/// @see bslmt_throughputbenchmark
39///
40/// # Description {#bslmt_throughputbenchmarkresult-description}
41/// This component defines a mechanism,
42/// `bslmt::ThroughputBenchmarkResult`, which represents counts of the work done
43/// by each thread, thread group, and sample, divided by the number of actual
44/// seconds that the sample took to execute. Each specific result can be
45/// retrieved by calling `getValue`, and relevant percentiles can be retrieved
46/// using `getMedian`, `getPercentile`, `getPercentiles`, and
47/// `getThreadPercentiles`.
48///
49/// ## Usage {#bslmt_throughputbenchmarkresult-usage}
50///
51///
52/// This section illustrates intended use of this component.
53///
54/// ### Example 1: Calculate Median and Percentiles {#bslmt_throughputbenchmarkresult-example-1-calculate-median-and-percentiles}
55///
56///
57/// In the following example we populate a `bslmt::ThroughputBenchmarkResult`
58/// object and calculate median and percentiles.
59///
60/// First, we define a vector with thread group sizes:
61/// @code
62/// bsl::vector<int> threadGroupSizes;
63/// threadGroupSizes.resize(2);
64/// threadGroupSizes[0] = 3;
65/// threadGroupSizes[1] = 2;
66/// @endcode
67/// Next, we define a `bslmt::ThroughputBenchmarkResult` with 10 samples and the
68/// previously defined thread group sizes:
69/// @code
70/// bslmt::ThroughputBenchmarkResult myResult(10, threadGroupSizes);
71/// @endcode
72/// Then, we populate the object with throughputs:
73/// @code
74/// for (int tgId = 0; tgId < 2; ++tgId) {
75/// for (int tId = 0; tId < myResult.numThreads(tgId); ++tId) {
76/// for (int sId = 0; sId < 10; ++sId) {
77/// double throughput = static_cast<double>(rand());
78/// myResult.setThroughput(tgId, tId, sId, throughput);
79/// }
80/// }
81/// }
82/// @endcode
83/// Now, we calculate median of the first thread group and print it out:
84/// @code
85/// double median;
86/// myResult.getMedian(&median, 0);
87/// bsl::cout << "Median of first thread group:" << median << "\n";
88/// @endcode
89/// Finally, we calculate percentiles 0, 0.25, 0.5, 0.75, and 1.0 of the first
90/// thread group and print it out:
91/// @code
92/// bsl::vector<double> percentiles(5);
93/// myResult.getPercentiles(&percentiles, 0);
94/// for (int i = 0; i < 5; ++i) {
95/// bsl::cout << "Percentile " << 25 * i << "% is:"
96/// << percentiles[i] << "\n";
97/// }
98/// @endcode
99/// @}
100/** @} */
101/** @} */
102
103/** @addtogroup bsl
104 * @{
105 */
106/** @addtogroup bslmt
107 * @{
108 */
109/** @addtogroup bslmt_throughputbenchmarkresult
110 * @{
111 */
112
113#include <bslscm_version.h>
114
115#include <bslma_allocator.h>
117
119
120#include <bsls_assert.h>
121#include <bsls_keyword.h>
122#include <bsls_types.h>
123
124#include <bsl_vector.h>
125
126
127namespace bslmt {
128
129class ThroughputBenchmarkResult_TestUtil;
130
131 // ===============================
132 // class ThroughputBenchmarkResult
133 // ===============================
134
135/// This class provides support for output of multi-threaded performance
136/// benchmark results. The results are counts of work done during the
137/// benchmark time period divided by the time period.
138///
139/// See @ref bslmt_throughputbenchmarkresult
141
142 public:
143 // PUBLIC TYPES
146
147 private:
148 // DATA
149
150 /// Count of work done, collected from the various threads, and the
151 /// various samples, divided by the actual time period a sample took.
152 /// The inner-most vectors (the `DoubleVector`) are the data for the
153 /// specific threads within a thread group. The middle vector is
154 /// indexed over the thread groups. The outer vector is indexed over
155 /// the samples. That is, to access sample S1, thread group G1, and
156 /// thread index T1 within G1, we refer to
157 /// `d_vecThroughputs[S1][G1][T1]`.
158 bsl::vector<bsl::vector<DoubleVector> > d_vecThroughputs;
159
160 // PRIVATE ACCESSORS
161
162 /// Load into the specified `throughputs` vector a sum of the work done
163 /// by all the threads in the specified `threadGroupIndex`. The size of
164 /// `throughputs` must match the number of samples.
165 ///
166 /// \pre The behavior is undefined unless `0 <= threadGroupIndex < numThreadGroups` and
167 /// `throughputs->size() == numSamples()`.
168 void getSortedSumThroughputs(bsl::vector<double> *throughputs,
169 int threadGroupIndex) const;
170
171 // FRIENDS
173
174 public:
175 // TRAITS
178
179 // CREATORS
180
181 /// Create an empty `ThroughputBenchmarkResult` object. Optionally
182 /// specify a `basicAllocator` used to supply memory. If
183 /// `basicAllocator` is 0, the currently installed default allocator is used.
184 ///
185 /// \note Note that this object has to be initialized before it can be
186 /// used.
187 explicit ThroughputBenchmarkResult(bslma::Allocator *basicAllocator = 0);
188
189 /// Create a `ThroughputBenchmarkResult` object with the specified
190 /// `numSamples` the number of samples in the benchmark, and the
191 /// specified `threadGroupSizes`, the number of threads in each of the
192 /// thread groups. Optionally specify a `basicAllocator` used to supply
193 /// memory. If `basicAllocator` is 0, the currently installed default allocator is used.
194 ///
195 /// \pre The behavior is undefined unless
196 /// `0 < numSamples`, `0 < threadGroupSizes.size()`, and
197 /// `0 < threadGroupSizes[N]` for all valid `N`.
199 const bsl::vector<int>& threadGroupSizes,
200 bslma::Allocator *basicAllocator = 0);
201
202 /// Create a `ThroughputBenchmarkResult` object having the value of the
203 /// specified `original`. Optionally specify a `basicAllocator` used to
204 /// supply memory. If `basicAllocator` is 0, the currently installed
205 /// default allocator is used.
207 const ThroughputBenchmarkResult& original,
208 bslma::Allocator *basicAllocator = 0);
209
210 /// Create a `ThroughputBenchmarkResult` object having the same value
211 /// and the same allocator as the specified `original` object. The
212 /// value of `original` becomes unspecified but valid, and its allocator
213 /// remains unchanged.
217
218 /// Create a `ThroughputBenchmarkResult` object having the same value as
219 /// the specified `original` object, using the specified
220 /// `basicAllocator` to supply memory. If `basicAllocator` is 0, the
221 /// currently installed default allocator is used. The allocator of
222 /// `original` remains unchanged. If `original` and the newly created
223 /// object have the same allocator then the value of `original` becomes
224 /// unspecified but valid, and no exceptions will be thrown; otherwise
225 /// `original` is unchanged (and an exception may be thrown).
228 bslma::Allocator *basicAllocator);
229
230 /// Destroy this object.
232
233 // MANIPULATORS
234
235 /// Assign to this object the value of the specified `rhs` benchmark
236 /// result, and return a reference providing modifiable access to this
237 /// object.
239
240 /// Assign to this object the value of the specified `rhs` object, and
241 /// return a non-`const` reference to this object. The allocators of
242 /// this object and `rhs` both remain unchanged. If `rhs` and this
243 /// object have the same allocator then the value of `rhs` becomes
244 /// unspecified but valid, and no exceptions will be thrown; otherwise
245 /// `rhs` is unchanged (and an exception may be thrown).
248
249 /// Initialize a default constructed `ThroughputBenchmarkResult` object
250 /// with the specified `numSamples` number of samples in the benchmark,
251 /// and the specified `threadGroupSizes`, the number of threads in each
252 /// of the thread groups. If any data was previously kept, it is lost.
253 ///
254 /// \pre The behavior is undefined unless `0 < numSamples`,
255 /// `0 < threadGroupSizes.size()`, and `0 < threadGroupSizes[N]` for all
256 /// valid N.
257 void initialize(int numSamples, const bsl::vector<int>& threadGroupSizes);
258
259 /// Set the throughput related to the specified `threadIndex` thread, in
260 /// the specified `threadGroupIndex`, and the specified `sampleIndex` to the specified `value`.
261 ///
262 /// \pre The behavior is undefined unless
263 /// `0 <= value`, `0 <= threadIndex < numThreads(threadGroupIndex)`,
264 /// `0 <= threadGroupIndex < numThreadGroups()`, and
265 /// `0 <= sampleIndex < numSamples()`.
266 void setThroughput(int threadGroupIndex,
267 int threadIndex,
268 int sampleIndex,
269 double value);
270
271 // ACCESSORS
272
273 // Object state
274
275 /// Return the number of test samples.
276 int numSamples() const;
277
278 /// Return the number of thread groups.
279 int numThreadGroups() const;
280
281 /// Return the number of threads in the specified `threadGroupIdx`.
282 ///
283 /// \pre The behavior is undefined unless
284 /// `0 <= threadGroupIndex < numThreadGroups()`.
285 int numThreads(int threadGroupIndex) const;
286
287 /// Return the total number of threads.
288 int totalNumThreads() const;
289
290 // Results
291
292 /// Return the throughput of work done on the specified `threadIndex`
293 /// thread, in the specified `threadGroupIndex`, and the specified `sampleIndex` sample.
294 ///
295 /// \pre The behavior is undefined unless
296 /// `0 <= threadIndex < numThreads(threadGroupIndex)`,
297 /// `0 <= threadGroupIndex < numThreadGroups()`, and
298 /// `0 <= sampleIndex < numSamples()`.
299 double getValue(int threadGroupIndex,
300 int threadIndex,
301 int sampleIndex) const;
302
303 /// Load into the specified `median` the median throughput (count /
304 /// second) of the work done by all the threads in the specified `threadGroupIndex`.
305 ///
306 /// \pre The behavior is undefined unless
307 /// `0 <= threadGroupIndex < numThreadGroups`.
308 void getMedian(double *median, int threadGroupIndex) const;
309
310 /// Load into the specified `percentile` the specified `percentage`
311 /// throughput (count / second) of the work done by all the threads in
312 /// the specified `threadGroupIndex`. A `percentage` of 0.0 is the
313 /// minimum, and a `percentage` of 1.0 is the maximum.
314 ///
315 /// \pre The behavior is undefined unless `0 <= threadGroupIndex < numThreadGroups` and
316 /// `0.0 <= percentage <= 1.0`.
317 void getPercentile(double *percentile,
318 double percentage,
319 int threadGroupIndex) const;
320
321 /// Load into the specified `percentiles` vector a uniform breakdown of
322 /// percentage throughput (count / second) of the work done by all the
323 /// threads in the specified `threadGroupIndex`. The size of
324 /// `percentiles` controls how many percentages are provided. For
325 /// example, a size of 5 will return the percentages 0, 0.25, 0.5, 0.75, 1.
326 ///
327 /// \pre The behavior is undefined unless
328 /// `0 <= threadGroupIndex < numThreadGroups` and
329 /// `2 <= percentiles->size()`.
331 int threadGroupIndex) const;
332
333 /// Load into the specified `percentiles` vector of vectors a uniform
334 /// breakdown of percentage throughput (count / second) of the work done
335 /// on the specified `threadGroupIndex` for each of the threads in it.
336 /// The size of `percentiles` controls how many percentages are
337 /// provided. For example, a size of 5 will return the percentages 0,
338 /// 0.25, 0.5, 0.75, 1. The size of each of the vectors inside `stats`
339 /// must be `numThreads(threadGroupId)`.
340 ///
341 /// \pre The behavior is undefined unless `0 <= threadGroupId < numThreadGroups`,
342 /// `2 <= percentiles.size()`, and
343 /// `percentiles[N].size() == numThreads(threadGroupIndex)` for all
344 /// N.
346 bsl::vector<bsl::vector<double> > *percentiles,
347 int threadGroupIndex) const;
348
349 // Aspects
350
351 /// Return the allocator used by this object.
353
354};
355
356 // ========================================
357 // class ThroughputBenchmarkResult_TestUtil
358 // ========================================
359
360/// This component-private class provides modifiable access to the
361/// non-public attributes of a `ThroughPutBenchmarkResult` object supplied
362/// on construction, and is provided for use exclusively in the test driver
363/// of this component.
364///
365/// See @ref bslmt_throughputbenchmarkresult
367
368 // DATA
370
371 public:
372 // CREATORS
373
374 /// Create a `ThroughputBenchmarkResult_TestUtil` object to test
375 /// contents of the specified `data`.
378
379 /// Destroy this object.
381
382 // MANIPULATORS
383
384 /// Return a reference providing modifiable access to the
385 /// `d_vecThroughputs` data member of `ThroughputBenchmarkResult`.
387};
388
389// ============================================================================
390// INLINE DEFINITIONS
391// ============================================================================
392
393 // -------------------------------
394 // class ThroughputBenchmarkResult
395 // -------------------------------
396
397// MANIPULATORS
398inline
400 int threadIndex,
401 int sampleIndex,
402 double value)
403{
404 BSLS_ASSERT(0 <= value);
405 BSLS_ASSERT(0 <= threadGroupIndex);
406 BSLS_ASSERT(numThreadGroups() > threadGroupIndex);
407 BSLS_ASSERT(0 <= threadIndex);
408 BSLS_ASSERT(numThreads(threadGroupIndex) > threadIndex);
409 BSLS_ASSERT(0 <= sampleIndex);
410 BSLS_ASSERT(numSamples() > sampleIndex);
411
412 d_vecThroughputs[sampleIndex][threadGroupIndex][threadIndex] = value;
413}
414
415// ACCESSORS
416 // Object state
417inline
419{
420 return static_cast<int>(d_vecThroughputs.size());
421}
422
423inline
425{
426 if (0 == numSamples()) {
427 return 0; // RETURN
428 }
429 return static_cast<int>(d_vecThroughputs[0].size());
430}
431
432inline
433int ThroughputBenchmarkResult::numThreads(int threadGroupIndex) const
434{
435 BSLS_ASSERT(0 <= threadGroupIndex);
436 BSLS_ASSERT(numThreadGroups() > threadGroupIndex);
437
438 return static_cast<int>(d_vecThroughputs[0][threadGroupIndex].size());
439}
440
441inline
443{
444 if (0 == numSamples()) {
445 return 0; // RETURN
446 }
447
448 int nThreadGroups = numThreadGroups();
449 int nThreads = 0;
450 for (int i = 0; i < nThreadGroups; ++i) {
451 nThreads += numThreads(i);
452 }
453 return nThreads;
454}
455
456 // Results
457inline
458double ThroughputBenchmarkResult::getValue(int threadGroupIndex,
459 int threadIndex,
460 int sampleIndex) const
461{
462 BSLS_ASSERT(0 <= threadGroupIndex);
463 BSLS_ASSERT(numThreadGroups() > threadGroupIndex);
464 BSLS_ASSERT(0 <= threadIndex);
465 BSLS_ASSERT(numThreads(threadGroupIndex) > threadIndex);
466 BSLS_ASSERT(0 <= sampleIndex);
467 BSLS_ASSERT(numSamples() > sampleIndex);
468
469 return d_vecThroughputs[sampleIndex][threadGroupIndex][threadIndex];
470}
471
472 // Aspects
473inline
475{
476 return d_vecThroughputs.get_allocator().mechanism();
477}
478
479 // ----------------------------------------
480 // class ThroughputBenchmarkResult_TestUtil
481 // ----------------------------------------
482
483// CREATORS
484inline
490
491// MANIPULATORS
492inline
495{
496 return d_data.d_vecThroughputs;
497}
498
499} // close package namespace
500
501
502#endif
503
504// ----------------------------------------------------------------------------
505// Copyright 2019 Bloomberg Finance L.P.
506//
507// Licensed under the Apache License, Version 2.0 (the "License");
508// you may not use this file except in compliance with the License.
509// You may obtain a copy of the License at
510//
511// http://www.apache.org/licenses/LICENSE-2.0
512//
513// Unless required by applicable law or agreed to in writing, software
514// distributed under the License is distributed on an "AS IS" BASIS,
515// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
516// See the License for the specific language governing permissions and
517// limitations under the License.
518// ----------------------------- END-OF-FILE ----------------------------------
519
520/** @} */
521/** @} */
522/** @} */
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
Definition bslmt_throughputbenchmarkresult.h:366
ThroughputBenchmarkResult_TestUtil(ThroughputBenchmarkResult &data)
Definition bslmt_throughputbenchmarkresult.h:485
bsl::vector< bsl::vector< bsl::vector< double > > > & throughputs()
Definition bslmt_throughputbenchmarkresult.h:494
~ThroughputBenchmarkResult_TestUtil()=default
Destroy this object.
Definition bslmt_throughputbenchmarkresult.h:140
int numThreadGroups() const
Return the number of thread groups.
Definition bslmt_throughputbenchmarkresult.h:424
double getValue(int threadGroupIndex, int threadIndex, int sampleIndex) const
Definition bslmt_throughputbenchmarkresult.h:458
ThroughputBenchmarkResult(bslma::Allocator *basicAllocator=0)
void getPercentile(double *percentile, double percentage, int threadGroupIndex) const
BSLMF_NESTED_TRAIT_DECLARATION(ThroughputBenchmarkResult, bslma::UsesBslmaAllocator)
ThroughputBenchmarkResult(const ThroughputBenchmarkResult &original, bslma::Allocator *basicAllocator=0)
void getMedian(double *median, int threadGroupIndex) const
void setThroughput(int threadGroupIndex, int threadIndex, int sampleIndex, double value)
Definition bslmt_throughputbenchmarkresult.h:399
ThroughputBenchmarkResult(int numSamples, const bsl::vector< int > &threadGroupSizes, bslma::Allocator *basicAllocator=0)
int totalNumThreads() const
Return the total number of threads.
Definition bslmt_throughputbenchmarkresult.h:442
bslma::Allocator * allocator() const
Return the allocator used by this object.
Definition bslmt_throughputbenchmarkresult.h:474
bsls::Types::Int64 Int64
Definition bslmt_throughputbenchmarkresult.h:144
ThroughputBenchmarkResult(bslmf::MovableRef< ThroughputBenchmarkResult > original) BSLS_KEYWORD_NOEXCEPT
void getPercentiles(bsl::vector< double > *percentiles, int threadGroupIndex) const
bsl::vector< double > DoubleVector
Definition bslmt_throughputbenchmarkresult.h:145
int numThreads(int threadGroupIndex) const
Definition bslmt_throughputbenchmarkresult.h:433
~ThroughputBenchmarkResult()=default
Destroy this object.
ThroughputBenchmarkResult & operator=(const ThroughputBenchmarkResult &rhs)
int numSamples() const
Return the number of test samples.
Definition bslmt_throughputbenchmarkresult.h:418
void getThreadPercentiles(bsl::vector< bsl::vector< double > > *percentiles, int threadGroupIndex) const
ThroughputBenchmarkResult(bslmf::MovableRef< ThroughputBenchmarkResult > original, bslma::Allocator *basicAllocator)
void initialize(int numSamples, const bsl::vector< int > &threadGroupSizes)
ThroughputBenchmarkResult & operator=(bslmf::MovableRef< ThroughputBenchmarkResult > rhs)
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_NOEXCEPT
Definition bsls_keyword.h:674
Definition bslmt_barrier.h:344
Definition bslma_usesbslmaallocator.h:344
long long Int64
Definition bsls_types.h:134