1 // Copyright (c) 2007-2012 Hartmut Kaiser
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <hpx/hpx.hpp>
7 #include <hpx/hpx_init.hpp>
8 #include <hpx/util/format.hpp>
9
10 #include <boost/program_options.hpp>
11
12 #include <cstdint>
13 #include <iostream>
14 #include <string>
15 #include <vector>
16
17 ///////////////////////////////////////////////////////////////////////////////
18 // This example demonstrates the creation and use of different types of
19 // performance counters. It utilizes the sine component, which implements two
20 // of the demonstrated counters.
21 //
22 // The example prints the values of the counters after every fixed amount of
23 // time. This time is configurable by a command line option --pause=N, where
24 // N is the amount of milliseconds to wait in between the sample points. The
25 // default value is 500ms.
26 //
27 // Here is a short description of each of the counters:
28 //
29 // /sine{locality#0/instance#0}/immediate/explicit
30 // This is a custom performance counter fully implemented in the sine
31 // component. It evaluates a new value every 1000ms (1s) and delivers this
32 // value whenever it is queried.
33 //
34 // /sine{locality#0/total}/immediate/implicit
35 // This is an immediate counter implemented by registering a function with
36 // the counter framework. This function will be called whenever the counter
37 // value is queried. It calculates the current value of a sine based on the
38 // uptime of the counter.
39 //
40 // /statistics{/sine{locality#0/instance#1}/immediate/explicit}/average#100
41 // This is an aggregating counter calculating the average value of a given
42 // base counter (in this case /sine{locality#0/instance#1}/immediate/explicit,
43 // i.e. a second instance of the explicit counter). The base counter is
44 // evaluated every 100ms (as specified by the trailing parameter in the
45 // counter name). No special code in the sine example is needed for this
46 // counter as it reuses the explicit counter and the predefined averaging
47 // performance counter implemented in HPX.
48 //
49 // Additionally, this example demonstrates starting and stopping performance
50 // counters. It stops the evaluation of the first explicit counter instance
51 // every 5 seconds, restarting it after a while.
52
53 ///////////////////////////////////////////////////////////////////////////////
monitor(std::uint64_t pause,std::uint64_t values)54 int monitor(std::uint64_t pause, std::uint64_t values)
55 {
56 // Create the performances counters using their symbolic name.
57 std::uint32_t const prefix = hpx::get_locality_id();
58
59 using hpx::performance_counters::performance_counter;
60 performance_counter sine_explicit(hpx::util::format(
61 "/sine{{locality#{}/instance#{}}}/immediate/explicit",
62 prefix, 0));
63 performance_counter sine_implicit(hpx::util::format(
64 "/sine{{locality#{}/total}}/immediate/implicit",
65 prefix));
66 performance_counter sine_average(hpx::util::format(
67 "/statistics{{/sine{{locality#{}/instance#{}}}/immediate/explicit}}/average@100",
68 prefix, 1));
69
70 // We need to explicitly start all counters before we can use them. For
71 // certain counters this could be a no-op, in which case start will return
72 // 'false'.
73 sine_explicit.start();
74 sine_implicit.start();
75 sine_average.start();
76
77 // retrieve the counter values
78 std::uint64_t start_time = 0;
79 bool started = true;
80 while (values-- > 0)
81 {
82 // Query the performance counter.
83 using hpx::performance_counters::counter_value;
84 using hpx::performance_counters::status_is_valid;
85
86 counter_value value1 = sine_explicit.get_counter_value(hpx::launch::sync);
87 counter_value value2 = sine_implicit.get_counter_value(hpx::launch::sync);
88 counter_value value3 = sine_average.get_counter_value(hpx::launch::sync);
89
90 if (status_is_valid(value1.status_))
91 {
92 if (!start_time)
93 start_time = value2.time_;
94
95 hpx::util::format_to(std::cout, "{:.3}: {:.4}, {:.4}, {:.4}\n",
96 (value2.time_ - start_time) * 1e-9,
97 value1.get_value<double>(),
98 value2.get_value<double>() / 100000.,
99 value3.get_value<double>());
100 }
101
102 // stop/restart the sine_explicit counter after every 5 seconds of
103 // evaluation
104 bool should_run =
105 (int((value2.time_ - start_time) * 1e-9) / 5) % 2 != 0;
106 if (should_run == started) {
107 if (started) {
108 sine_explicit.stop();
109 started = false;
110 }
111 else {
112 sine_explicit.start();
113 started = true;
114 }
115 }
116
117 // give up control to the thread manager, we will be resumed after
118 // 'pause' ms
119 hpx::this_thread::suspend(std::chrono::milliseconds(pause));
120 }
121 return 0;
122 }
123
124 ///////////////////////////////////////////////////////////////////////////////
hpx_main(boost::program_options::variables_map & vm)125 int hpx_main(boost::program_options::variables_map& vm)
126 {
127 // retrieve the command line arguments
128 std::uint64_t const pause = vm["pause"].as<std::uint64_t>();
129 std::uint64_t const values = vm["values"].as<std::uint64_t>();
130
131 // do main work, i.e. query the performance counters
132 std::cout << "starting sine monitoring..." << std::endl;
133
134 int result = 0;
135 try {
136 result = monitor(pause, values);
137 }
138 catch(hpx::exception const& e) {
139 std::cerr << "sine_client: caught exception: " << e.what() << std::endl;
140 std::cerr << "Have you specified the command line option "
141 "--sine to enable the sine component?"
142 << std::endl;
143 }
144
145 // Initiate shutdown of the runtime system.
146 hpx::finalize();
147 return result;
148 }
149
150 ///////////////////////////////////////////////////////////////////////////////
main(int argc,char * argv[])151 int main(int argc, char* argv[])
152 {
153 using boost::program_options::options_description;
154 using boost::program_options::value;
155
156 // Configure application-specific options.
157 options_description desc_commandline("usage: sine_client [options]");
158 desc_commandline.add_options()
159 ("pause", value<std::uint64_t>()->default_value(500),
160 "milliseconds between each performance counter query")
161 ("values", value<std::uint64_t>()->default_value(100),
162 "number of performance counter queries to perform")
163 ;
164
165 std::vector<std::string> cfg = {
166 "hpx.components.sine.enabled! = 1"
167 };
168
169 // Initialize and run HPX.
170 return hpx::init(desc_commandline, argc, argv, cfg);
171 }
172
173