ALP User Documentation 0.7.0
Algebraic Programming User Documentation
benchmark.hpp
Go to the documentation of this file.
1
2/*
3 * Copyright 2021 Huawei Technologies Co., Ltd.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
28#ifndef _H_GRB_BENCH_BASE
29#define _H_GRB_BENCH_BASE
30
31#include <chrono>
32#include <ios>
33#include <limits>
34#include <string>
35
37#include <graphblas/ops.hpp>
38#include <graphblas/rc.hpp>
39#include <graphblas/utils.hpp>
40#include <graphblas/utils/TimerResults.hpp>
41
42#include "collectives.hpp"
43#include "config.hpp"
44#include "exec.hpp"
45
46#ifndef _GRB_NO_STDIO
47 #include <iostream>
48#endif
49
50#ifndef _GRB_NO_EXCEPTIONS
51 #include <stdexcept>
52#endif
53
54#include <math.h>
55
56
82namespace grb {
83
84 namespace internal {
85
91 class BenchmarkerBase {
92
93 protected:
94
95#ifndef _GRB_NO_STDIO
104 static void printTimeSinceEpoch( const bool printHeader = true ) {
105 const auto now = std::chrono::system_clock::now();
106 const auto since = now.time_since_epoch();
107 if( printHeader ) {
108 std::cout << "Time since epoch (in ms.): ";
109 }
110 std::cout << std::chrono::duration_cast<
111 std::chrono::milliseconds
112 >( since ).count() << "\n";
113 }
114#endif
115
119 static void benchmark_calc_inner(
120 const size_t loop,
121 const size_t total,
122 grb::utils::TimerResults &inner_times,
123 grb::utils::TimerResults &total_times,
124 grb::utils::TimerResults &min_times,
125 grb::utils::TimerResults &max_times,
126 grb::utils::TimerResults * sdev_times
127 ) {
128 inner_times.normalize( total );
129 total_times.accum( inner_times );
130 min_times.min( inner_times );
131 max_times.max( inner_times );
132 sdev_times[ loop ] = inner_times;
133 }
134
138 static void benchmark_calc_outer(
139 const size_t total,
140 grb::utils::TimerResults &total_times,
141 grb::utils::TimerResults &min_times,
142 grb::utils::TimerResults &max_times,
143 grb::utils::TimerResults * sdev_times,
144 const size_t pid
145 ) {
146 total_times.normalize( total );
147 grb::utils::TimerResults sdev;
148 // compute standard dev of average times, leaving sqrt calculation until
149 // the output of the values
150 sdev.set( 0 );
151 for( size_t i = 0; i < total; i++ ) {
152 double diff = sdev_times[ i ].io - total_times.io;
153 sdev.io += diff * diff;
154 diff = sdev_times[ i ].preamble - total_times.preamble;
155 sdev.preamble += diff * diff;
156 diff = sdev_times[ i ].useful - total_times.useful;
157 sdev.useful += diff * diff;
158 diff = sdev_times[ i ].postamble - total_times.postamble;
159 sdev.postamble += diff * diff;
160 }
161 // unbiased normalisation of the standard deviation
162 sdev.normalize( total - 1 );
163
164#ifndef _GRB_NO_STDIO
165 // output results
166 if( pid == 0 ) {
167 std::cout << "Overall timings (io, preamble, useful, postamble):\n"
168 << std::scientific;
169 std::cout << "Avg: " << total_times.io << ", " << total_times.preamble
170 << ", " << total_times.useful << ", " << total_times.postamble << "\n";
171 std::cout << "Min: " << min_times.io << ", " << min_times.preamble << ", "
172 << min_times.useful << ", " << min_times.postamble << "\n";
173 std::cout << "Max: " << max_times.io << ", " << max_times.preamble << ", "
174 << max_times.useful << ", " << max_times.postamble << "\n";
175 std::cout << "Std: " << sqrt( sdev.io ) << ", " << sqrt( sdev.preamble )
176 << ", " << sqrt( sdev.useful ) << ", " << sqrt( sdev.postamble ) << "\n";
177 #if __GNUC__ > 4
178 std::cout << std::defaultfloat;
179 #endif
180 printTimeSinceEpoch();
181 }
182#else
183 // we ran the benchmark, but may not have a way to output it in this case
184 // this currently only is touched by the #grb::banshee backend, which
185 // provides other timing mechanisms.
186 (void) min_times;
187 (void) max_times;
188 (void) pid;
189#endif
190 }
191
213 template<
214 typename U,
215 enum Backend implementation = config::default_backend
216 >
217 static RC benchmark(
218 void ( *alp_program )( const void *, const size_t, U & ),
219 const void * data_in,
220 const size_t in_size,
221 U &data_out,
222 const size_t inner,
223 const size_t outer,
224 const size_t pid
225 ) {
226 const double inf = std::numeric_limits< double >::infinity();
227 grb::utils::TimerResults total_times, min_times, max_times;
228 grb::utils::TimerResults * sdev_times =
229 new grb::utils::TimerResults[ outer ];
230 total_times.set( 0 );
231 min_times.set( inf );
232 max_times.set( 0 );
233
234 // outer loop
235 for( size_t out = 0; out < outer; ++out ) {
236 grb::utils::TimerResults inner_times;
237 inner_times.set( 0 );
238
239 // inner loop
240 for( size_t in = 0; in < inner; in++ ) {
241 data_out.times.set( 0 );
242 ( *alp_program )( data_in, in_size, data_out );
244 data_out.times.io, 0, grb::operators::max< double >() );
246 data_out.times.preamble, 0, grb::operators::max< double >() );
248 data_out.times.useful, 0, grb::operators::max< double >() );
250 data_out.times.postamble, 0, grb::operators::max< double >() );
251 inner_times.accum( data_out.times );
252 }
253
254 // calculate performance stats
255 benchmark_calc_inner( out, inner, inner_times, total_times, min_times,
256 max_times, sdev_times );
257
258#ifndef _GRB_NO_STDIO
259 // give experiment output line
260 if( pid == 0 ) {
261 std::cout << "Outer iteration #" << out << " timings (io, preamble, "
262 << "useful, postamble, time since epoch): ";
263 std::cout << inner_times.io << ", " << inner_times.preamble << ", "
264 << inner_times.useful << ", " << inner_times.postamble << ", ";
265 printTimeSinceEpoch( false );
266 }
267#endif
268
269 // pause for next outer loop
270 if( sleep( 1 ) != 0 ) {
271#ifndef _GRB_NO_STDIO
272 std::cerr << "Sleep interrupted, assume benchmark is unreliable; "
273 << "exiting.\n";
274#endif
275 abort();
276 }
277 }
278
279 // calculate performance stats
280 benchmark_calc_outer( outer, total_times, min_times, max_times, sdev_times,
281 pid );
282 delete [] sdev_times;
283
284 return SUCCESS;
285 }
286
308 template<
309 typename T, typename U,
310 enum Backend implementation = config::default_backend
311 >
312 static RC benchmark(
313 void ( *alp_program )( const T &, U & ),
314 const T &data_in,
315 U &data_out,
316 const size_t inner,
317 const size_t outer,
318 const size_t pid
319 ) {
320 const double inf = std::numeric_limits< double >::infinity();
321 grb::utils::TimerResults total_times, min_times, max_times;
322 grb::utils::TimerResults * sdev_times =
323 new grb::utils::TimerResults[ outer ];
324 total_times.set( 0 );
325 min_times.set( inf );
326 max_times.set( 0 );
327
328 // outer loop
329 for( size_t out = 0; out < outer; ++out ) {
330 grb::utils::TimerResults inner_times;
331 inner_times.set( 0 );
332
333 // inner loop
334 for( size_t in = 0; in < inner; ++in ) {
335 data_out.times.set( 0 );
336
337 ( *alp_program )( data_in, data_out );
338 grb::collectives< implementation >::reduce( data_out.times.io, 0,
340 grb::collectives< implementation >::reduce( data_out.times.preamble, 0,
342 grb::collectives< implementation >::reduce( data_out.times.useful, 0,
344 grb::collectives< implementation >::reduce( data_out.times.postamble, 0,
346 inner_times.accum( data_out.times );
347 }
348
349 // calculate performance stats
350 benchmark_calc_inner( out, inner, inner_times, total_times, min_times,
351 max_times, sdev_times );
352
353#ifndef _GRB_NO_STDIO
354 // give experiment output line
355 if( pid == 0 ) {
356 std::cout << "Outer iteration #" << out << " timings "
357 << "(io, preamble, useful, postamble, time since epoch): " << std::fixed
358 << inner_times.io << ", " << inner_times.preamble << ", "
359 << inner_times.useful << ", " << inner_times.postamble << ", ";
360 printTimeSinceEpoch( false );
361 std::cout << std::scientific;
362 }
363#endif
364
365 // pause for next outer loop
366 if( sleep( 1 ) != 0 ) {
367#ifndef _GRB_NO_STDIO
368 std::cerr << "Sleep interrupted, assume benchmark is unreliable; "
369 << "exiting.\n";
370#endif
371 abort();
372 }
373 }
374
375 // calculate performance stats
376 benchmark_calc_outer( outer, total_times, min_times, max_times, sdev_times,
377 pid );
378 delete[] sdev_times;
379
380 return SUCCESS;
381 }
382
383
384 public:
385
386 BenchmarkerBase() {
387#ifndef _GRB_NO_STDIO
388 printTimeSinceEpoch();
389#endif
390 }
391
392 };
393
394 } // namespace internal
395
404 template< enum EXEC_MODE mode, enum Backend implementation >
406
407 public :
408
438 const size_t process_id = 0,
439 size_t nprocs = 1,
440 std::string hostname = "localhost",
441 std::string port = "0"
442 ) {
443 (void)process_id; (void)nprocs; (void)hostname; (void)port;
444#ifndef _GRB_NO_EXCEPTIONS
445 throw std::logic_error( "Benchmarker class called with unsupported mode or "
446 "implementation" );
447#endif
448 }
449
485 template< typename T, typename U >
487 void ( *alp_program )( const T &, U & ),
488 const T &data_in,
489 U &data_out,
490 const size_t inner,
491 const size_t outer,
492 const bool broadcast = false
493 ) const {
494 (void) alp_program;
495 (void) data_in;
496 (void) data_out;
497 (void) inner;
498 (void) outer;
499 (void) broadcast;
500
501 // stub implementation, should be overridden by specialised implementation.
502 // furthermore, it should be impossible to call this function without
503 // triggering an exception during construction of this stub class, so we
504 // just return PANIC here
505 return PANIC;
506 }
507
545 template< typename U >
547 void ( *alp_program )( const void *, const size_t, U & ),
548 const void * data_in, const size_t in_size,
549 U &data_out,
550 const size_t inner, const size_t outer,
551 const bool broadcast = false
552 ) const {
553 (void) alp_program;
554 (void) data_in;
555 (void) in_size;
556 (void) data_out;
557 (void) inner;
558 (void) outer;
559 (void) broadcast;
560
561 // stub implementation, should be overridden by specialised implementation.
562 // furthermore, it should be impossible to call this function without
563 // triggering an exception during construction of this stub class, so we
564 // just return PANIC here
565 return PANIC;
566 }
567
591 static RC finalize() {
593 }
594
595 };
596
597} // end namespace ``grb''
598
599#endif // end _H_GRB_BENCH_BASE
600
This file contains a register of all backends that are either implemented, under implementation,...
A class that follows the API of the grb::Launcher, but instead of launching the given ALP program onc...
Definition: benchmark.hpp:405
Benchmarker(const size_t process_id=0, size_t nprocs=1, std::string hostname="localhost", std::string port="0")
Constructs an instance of the benchmarker class.
Definition: benchmark.hpp:437
RC exec(void(*alp_program)(const void *, const size_t, U &), const void *data_in, const size_t in_size, U &data_out, const size_t inner, const size_t outer, const bool broadcast=false) const
Benchmarks a given ALP program.
Definition: benchmark.hpp:546
static RC finalize()
Releases all ALP resources.
Definition: benchmark.hpp:591
RC exec(void(*alp_program)(const T &, U &), const T &data_in, U &data_out, const size_t inner, const size_t outer, const bool broadcast=false) const
Benchmarks a given ALP program.
Definition: benchmark.hpp:486
static RC finalize()
Releases all ALP resources.
Definition: exec.hpp:322
static RC reduce(IOType &inout, const size_t root=0, const Operator op=Operator())
Schedules a reduce operation of a single object of type IOType per process.
Definition: collectives.hpp:191
This operator takes the maximum of the two input parameters and writes the result to the output varia...
Definition: ops.hpp:243
Specifies some basic collectives which may be used within a multi-process ALP program.
Specifies the grb::Launcher functionalities.
Backend
A collection of all backends.
Definition: backends.hpp:46
The ALP/GraphBLAS namespace.
Definition: graphblas.hpp:452
RC
Return codes of ALP primitives.
Definition: rc.hpp:47
@ PANIC
Generic fatal error code.
Definition: rc.hpp:68
@ SUCCESS
Indicates the primitive has executed successfully.
Definition: rc.hpp:54
Provides a set of standard binary operators.
Defines the ALP error codes.
Contains the configuration parameters for the reference and reference_omp backends.