Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic histogram performance counter implementation #2

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/manual/existing_performance_counters.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,46 @@ system and application performance.
]
]

[/////////////////////////////////////////////////////////////////////////////]
[table for Generic Histogram Performance Counter
[[Counter Type] [Counter Instance Formatting] [Description] [Parameters]]
[ [`Histogram-Performance-Counter`]
[`locality#*/total`

where:[br] `*` is the locality id of the locality the average time
between parcels for the given action should be queried for. The
locality id is a (zero based) number identifying the locality.]
[Returns a histogram representing the data collected for the
base counter which has been queried.

This counter returns an array of values, where the first three values
represent the three parameters used for the histogram followed by
one value for each of the histogram buckets.

The first unit of measure displayed for this counter (`[ns]`) refers to
the lower and upper boundary values in the returned histogram data only.
The second unit of measure displayed (`[0.1%]`) refers to the actual
histogram data.

For each bucket the counter shows a value between `0` and `1000`,
which corresponds to a percentage value between `0%` and `100%`.
]
[The action type and optional histogram parameters. The action type is
the string which has been used while registering the action with
__hpx__, e.g. which has been passed as the second parameter to the macro
[macroref HPX_REGISTER_ACTION `HPX_REGISTER_ACTION`] or
[macroref HPX_REGISTER_ACTION_ID `HPX_REGISTER_ACTION_ID`].

The action type may be followed by a comma separated list of up-to
three numbers: the lower and upper boundaries for the collected
histogram, and the number of buckets for the histogram to generate.
By default these three numbers will be assumed to be `0` (`[ns]`,
lower bound), `1000000` (`[ns]`, upper bound), and `20` (number of
buckets to generate).
]
]
]

[/////////////////////////////////////////////////////////////////////////////]
[table Performance Counters for Elementary Arithmetic Operations
[[Counter Type] [Counter Instance Formatting] [Description] [Parameters]]
Expand Down
10 changes: 10 additions & 0 deletions hpx/performance_counters/counters_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,11 @@ namespace hpx { namespace performance_counters
// be registered with the counter types.
HPX_EXPORT naming::gid_type arithmetics_counter_extended_creator(
counter_info const&, error_code&);

// Creation function for histogram performance counters; to
// be registered with the counter types.
HPX_EXPORT naming::gid_type get_histogram_counter_creator(
counter_info const&, error_code&);

// Creation function for uptime counters.
HPX_EXPORT naming::gid_type uptime_counter_creator(
Expand Down Expand Up @@ -583,6 +588,11 @@ namespace hpx { namespace performance_counters
counter_info const& info,
std::vector<std::string> const& base_counter_names,
error_code& ec = throws);

// \brief Create a new histogram performance counter instance
HPX_EXPORT naming::gid_type get_histogram_counter(
std::string const& name, std::int64_t min_boundary,
std::int64_t max_boundary, std::int64_t num_buckets);

// \brief Create a new performance counter instance based on given
// counter info
Expand Down
42 changes: 42 additions & 0 deletions hpx/performance_counters/registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,39 @@ namespace hpx { namespace performance_counters

public:
registry() {}

typedef util::function_nonser<std::vector<std::int64_t>(bool)>
get_histogram_values_type;
typedef util::function_nonser<
void(std::int64_t, std::int64_t, std::int64_t,
get_histogram_values_type&)
> get_histogram_creator_type;

typedef std::unordered_map<
std::string, counter_functions, hpx::util::jenkins_hash
> map_type;

static registry& instance();

void register_action(std::string const& name,
get_histogram_creator_type
histogram_counter_creator);

struct counter_functions
{
get_histogram_creator_type histogram_counter_creator;
std::int64_t min_boundary, max_boundary, num_buckets;
};
/// \brief Create a new histogram performance counter instance
get_histogram_creator_type get_histogram_counter(
std::string const& name, std::int64_t min_boundary,
std::int64_t max_boundary, naming::gid_type& id, std::int64_t num_buckets);

static std::vector<std::int64_t> empty_histogram(bool)
{
std::vector<std::int64_t> result = { 0, 0, 1, 0 };
return result;
}

/// \brief Add a new performance counter type to the (local) registry
counter_status add_counter_type(counter_info const& info,
Expand Down Expand Up @@ -165,6 +198,15 @@ namespace hpx { namespace performance_counters

private:
counter_type_map_type countertypes_;

struct tag {};

friend struct hpx::util::static_<
registry, tag
>;

mutable mutex_type mtx_;
map_type map_;
};
}}

Expand Down
121 changes: 121 additions & 0 deletions hpx/performance_counters/server/histogram_performance_counters.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) 2018 Surya Priy
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(HPX_PERFORMANCE_COUNTERS_SERVER_HISTOGRAM_PERFORMANCE_COUNTER)
#define HPX_PERFORMANCE_COUNTERS_SERVER_HISTOGRAM_PERFORMANCE_COUNTER

#include <hpx/config.hpp>
#include <hpx/lcos/local/spinlock.hpp>
#include <hpx/performance_counters/server/base_performance_counter.hpp>
#include <hpx/runtime/components/server/component_base.hpp>
#include <hpx/runtime/naming/id_type.hpp>
#include <hpx/util/interval_timer.hpp>
#include <hpx/util/detail/pp/nargs.hpp>
#include <hpx/util/function.hpp>
#include <hpx/util/histogram.hpp>
#include <hpx/util/pool_timer.hpp>

#include <boost/smart_ptr/scoped_ptr.hpp>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
#include <vector>

#include <hpx/config/warnings_prefix.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace hpx { namespace performance_counters { namespace server
{

///////////////////////////////////////////////////////////////////////////
// This counter exposes the histogram for counters processed during the
// given base time interval. The counter relies on querying a steadily
// growing counter value.
class histogram_performance_counter
{
typedef hpx::lcos::local::spinlock mutex_type;

// avoid warnings about using this in member initializer list
histogram_performance_counter* this_() { return this; }

public:
histogram_counter() {}
typedef histogram_performance_counter type_holder;
typedef base_performance_counter base_type_holder;

std::vector<std::int64_t>
get_histogram(bool reset);
void get_histogram_creator(
std::int64_t min_boundary, std::int64_t max_boundary,
std::int64_t num_buckets,
util::function_nonser<std::vector<std::int64_t>(bool)>& result);

// register the given action
static void register_action(char const* action, error_code& ec);

get_histogram_values_type get_histogram_counter(
std::string const& name, std::int64_t min_boundary,
std::int64_t max_boundary, naming::gid_type& gid,
std::int64_t num_buckets);

histogram_performance_counter(counter_info const& info,
std::string const& base_counter_name,
std::int64_t min_boundary, std::int64_t max_boundary,
std::int64_t num_buckets, bool reset_base_counter);

bool start();

bool stop();

void reset_counter_value();

void on_terminate() {}

/// \brief finalize() will be called just before the instance gets
/// destructed
void finalize()
{
base_performance_counter::finalize();
base_type::finalize();
}

protected:
bool evaluate_base_counter(counter_value& value);
bool evaluate();
bool ensure_base_counter();

private:
typedef lcos::local::spinlock mutex_type;
mutable mutex_type mtx_;

hpx::util::interval_timer timer_; ///< base time interval in milliseconds
std::string base_counter_name_; ///< name of base counter to be queried
naming::id_type base_counter_id_;

boost::scoped_ptr<detail::counter_type_from_histogram_base> value_;
counter_value prev_value_;
bool has_prev_value_;

bool reset_base_counter_;

typedef boost::accumulators::accumulator_set<
double, // collects percentiles
boost::accumulators::features<hpx::util::tag::histogram>
> histogram_collector_type;

std::unique_ptr<histogram_collector_type> data_histogram;
std::int64_t histogram_min_boundary_;
std::int64_t histogram_max_boundary_;
std::int64_t histogram_num_buckets_;

// base counters to be queried
performance_counter_set counters_;

};
}}}

#endif
14 changes: 14 additions & 0 deletions src/performance_counters/counters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,20 @@ namespace hpx { namespace performance_counters
gid, ec);
return gid;
}

// \brief Create a new aggregating histogram performance counter instance
// based on given base counter name and given base time interval
// (milliseconds).
naming::gid_type get_histogram_counter(
std::string const& name, std::int64_t min_boundary,
std::int64_t max_boundary, std::int64_t num_buckets)
{
naming::gid_type gid;
get_runtime().get_counter_registry().
get_histogram_counter(name, min_boundary,
max_boundary, gid, num_buckets);
return gid;
}

///////////////////////////////////////////////////////////////////////
counter_status add_counter(naming::id_type const& id,
Expand Down
100 changes: 100 additions & 0 deletions src/performance_counters/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <hpx/performance_counters/registry.hpp>
#include <hpx/performance_counters/server/arithmetics_counter.hpp>
#include <hpx/performance_counters/server/arithmetics_counter_extended.hpp>
#include <hpx/performance_counters/server/histogram_performance_counter.hpp>
#include <hpx/performance_counters/server/elapsed_time_counter.hpp>
#include <hpx/performance_counters/server/raw_counter.hpp>
#include <hpx/performance_counters/server/raw_values_counter.hpp>
Expand All @@ -35,6 +36,7 @@
#include <string>
#include <utility>
#include <vector>
#include <mutex>

///////////////////////////////////////////////////////////////////////////////
namespace hpx { namespace performance_counters
Expand All @@ -55,6 +57,104 @@ namespace hpx { namespace performance_counters
}
return it;
}

registry& registry::instance()
{
hpx::util::static_<registry, tag> registry;
return registry.get();
}

void registry::register_action(
std::string const& name,
get_histogram_creator_type histogram_counter_creator)
{
if (name.empty())
{
HPX_THROW_EXCEPTION(bad_parameter,
"registry::register_action",
"Cannot register an action with an empty name");
}

std::lock_guard<mutex_type> l(mtx_);

auto it = map_.find(name);
if (it == map_.end())
{
counter_functions data =
{
histogram_counter_creator,
0, 0, 1
};

map_.emplace(name, std::move(data));
}
else
{
(*it).second.histogram_counter_creator =
histogram_counter_creator;

if ((*it).second.min_boundary != (*it).second.max_boundary)
{
// instantiate actual histogram collection
registry::get_histogram_values_type result;
histogram_counter_creator(
(*it).second.min_boundary, (*it).second.max_boundary,
(*it).second.num_buckets, result);
}
}
}

void registry::register_action(std::string const& name)
{
if (name.empty())
{
HPX_THROW_EXCEPTION(bad_parameter,
"registry::register_action",
"Cannot register an action with an empty name");
}

std::lock_guard<mutex_type> l(mtx_);

auto it = map_.find(name);
if (it == map_.end())
{
map_.emplace(name, counter_functions());
}
}

registry::get_histogram_values_type
registry::get_histogram_counter(
std::string const& name, std::int64_t min_boundary,
std::int64_t max_boundary, naming::gid_type& gid,
std::int64_t num_buckets)
{
std::unique_lock<mutex_type> l(mtx_);

map_type::iterator it = map_.find(name);
if (it == map_.end())
{
l.unlock();
HPX_THROW_EXCEPTION(bad_parameter,
"registry::"
"get_histogram_counter",
"unknown action type");
return &registry::empty_histogram;
}

if ((*it).second.histogram_counter_creator.empty())
{
// no parcel of this type has been sent yet
(*it).second.min_boundary = min_boundary;
(*it).second.max_boundary = max_boundary;
(*it).second.num_buckets = num_buckets;
return registry::get_histogram_values_type();
}

registry::get_histogram_values_type result;
(*it).second.histogram_counter_creator(
min_boundary, max_boundary, num_buckets, result);
return result;
}

registry::counter_type_map_type::const_iterator
registry::locate_counter_type(std::string const& type_name) const
Expand Down
Loading