1 //  Copyright (c)      2011 Bryce Lelbach
2 //  Copyright (c) 2009-2010 Dylan Stark
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 // #define HPX_USE_WINDOWS_PERFORMANCE_COUNTERS 1
8 
9 #include <hpx/hpx_init.hpp>
10 #include <hpx/exception.hpp>
11 #include <hpx/include/performance_counters.hpp>
12 #include <hpx/include/lcos.hpp>
13 #include <hpx/runtime/actions/plain_action.hpp>
14 #include <hpx/runtime/threads/thread_helpers.hpp>
15 #include <hpx/lcos/future.hpp>
16 #include <hpx/state.hpp>
17 #include <hpx/util/format.hpp>
18 
19 #include <cstdint>
20 #include <iostream>
21 #include <memory>
22 #include <string>
23 #include <vector>
24 
25 // include Windows specific performance counter binding
26 #if defined(HPX_WINDOWS) && HPX_USE_WINDOWS_PERFORMANCE_COUNTERS != 0
27 #include "win_perf_counters.hpp"
28 #endif
29 
30 ///////////////////////////////////////////////////////////////////////////////
stop_monitor(std::shared_ptr<hpx::promise<void>> p)31 void stop_monitor(std::shared_ptr<hpx::promise<void> > p)
32 {
33     p->set_value();      // Kill the monitor.
34 }
35 
36 ///////////////////////////////////////////////////////////////////////////////
monitor(double runfor,std::string const & name,std::uint64_t pause)37 int monitor(double runfor, std::string const& name, std::uint64_t pause)
38 {
39 #if defined(HPX_WINDOWS) && HPX_USE_WINDOWS_PERFORMANCE_COUNTERS != 0
40     hpx::register_shutdown_function(&uninstall_windows_counters);
41 #endif
42 
43     // Resolve the GID of the performance counter using it's symbolic name.
44     hpx::naming::id_type id = hpx::performance_counters::get_counter(name);
45     if (!id)
46     {
47         hpx::util::format_to(std::cout,
48             "error: performance counter not found ({})",
49             name) << std::endl;
50         return 1;
51     }
52 
53     std::uint32_t const locality_id = hpx::get_locality_id();
54     if (locality_id == hpx::naming::get_locality_id_from_gid(id.get_gid()))
55     {
56         hpx::util::format_to(std::cout,
57             "error: cannot query performance counters on its own locality ({})",
58             name) << std::endl;
59         return 1;
60     }
61 
62     std::shared_ptr<hpx::promise<void> > stop_flag =
63         std::make_shared<hpx::promise<void> >();
64     hpx::future<void> f = stop_flag->get_future();
65 
66     hpx::register_shutdown_function(
67         hpx::util::bind(&stop_monitor, stop_flag));
68 
69     std::int64_t zero_time = 0;
70 
71     hpx::util::high_resolution_timer t;
72     while (runfor < 0 || t.elapsed() < runfor)
73     {
74         // stop collecting data when the runtime is exiting
75         if (!hpx::is_running() || f.is_ready())
76             return 0;
77 
78         // Query the performance counter.
79         using namespace hpx::performance_counters;
80         counter_value value =
81             stubs::performance_counter::get_value(hpx::launch::sync, id);
82 
83         if (status_is_valid(value.status_))
84         {
85             if (!zero_time)
86                 zero_time = value.time_;
87 
88             hpx::util::format_to(std::cout,
89                 "  {},{},{}[s],{}\n",
90                 name,
91                 value.count_,
92                 double((value.time_ - zero_time) * 1e-9),
93                 value.value_);
94 
95 #if defined(HPX_WINDOWS) && HPX_USE_WINDOWS_PERFORMANCE_COUNTERS != 0
96             update_windows_counters(value.value_);
97 #endif
98         }
99 
100         // Schedule a wakeup.
101         hpx::this_thread::suspend(pause);
102     }
103 
104     return hpx::disconnect();
105 }
106 
107 ///////////////////////////////////////////////////////////////////////////////
hpx_main(boost::program_options::variables_map & vm)108 int hpx_main(boost::program_options::variables_map& vm)
109 {
110     std::cout << "starting monitor" << std::endl;
111 
112     std::string const name = vm["name"].as<std::string>();
113     std::uint64_t const pause = vm["pause"].as<std::uint64_t>();
114     double const runfor = vm["runfor"].as<double>();
115 
116     return monitor(runfor, name, pause);
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////
main(int argc,char * argv[])120 int main(int argc, char* argv[])
121 {
122     // Configure application-specific options.
123     boost::program_options::options_description
124        desc_commandline("Usage: " HPX_APPLICATION_STRING " [options]");
125 
126     using boost::program_options::value;
127     desc_commandline.add_options()
128         ( "name", value<std::string>()->default_value(
129               "/threadqueue{locality#0/total}/length")
130         , "symbolic name of the performance counter")
131 
132         ( "pause", value<std::uint64_t>()->default_value(500)
133         , "milliseconds between each performance counter query")
134 
135         ( "runfor", value<double>()->default_value(-1)
136         , "time to wait before this application exits ([s], default: run forever)")
137         ;
138 
139 #if defined(HPX_WINDOWS) && HPX_USE_WINDOWS_PERFORMANCE_COUNTERS != 0
140     hpx::register_startup_function(&install_windows_counters);
141 #endif
142 
143     // Initialize and run HPX, enforce connect mode as we connect to an existing
144     // application.
145     std::vector<std::string> const cfg = {
146         "hpx.run_hpx_main!=1"
147     };
148 
149     hpx::util::function_nonser<void()> const empty;
150     return hpx::init(desc_commandline, argc, argv, cfg, empty,
151         empty, hpx::runtime_mode_connect);
152 }
153 
154