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