1 ////////////////////////////////////////////////////////////////////////////////
2 //  Copyright (c) 2011 Bryce Adelstein-Lelbach
3 //  Copyright (c) 2012-2017 Hartmut Kaiser
4 //  Copyright (c) 2016 Thomas Heller
5 //
6 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 ////////////////////////////////////////////////////////////////////////////////
9 
10 #include <hpx/config.hpp>
11 #include <hpx/lcos/base_lco_with_value.hpp>
12 #include <hpx/performance_counters/counter_creators.hpp>
13 #include <hpx/performance_counters/counters.hpp>
14 #include <hpx/performance_counters/manage_counter_type.hpp>
15 #include <hpx/runtime/agas/interface.hpp>
16 #include <hpx/runtime/agas/namespace_action_code.hpp>
17 #include <hpx/runtime/agas/server/symbol_namespace.hpp>
18 #include <hpx/runtime/naming/split_gid.hpp>
19 #include <hpx/throw_exception.hpp>
20 #include <hpx/util/assert.hpp>
21 #include <hpx/util/bind_back.hpp>
22 #include <hpx/util/bind_front.hpp>
23 #include <hpx/util/format.hpp>
24 #include <hpx/util/get_and_reset_value.hpp>
25 #include <hpx/util/insert_checked.hpp>
26 #include <hpx/util/regex_from_pattern.hpp>
27 #include <hpx/util/scoped_timer.hpp>
28 #include <hpx/util/unlock_guard.hpp>
29 
30 #include <atomic>
31 #include <cstddef>
32 #include <cstdint>
33 #include <map>
34 #include <memory>
35 #include <mutex>
36 #include <string>
37 #include <utility>
38 #include <vector>
39 
40 #include <boost/regex.hpp>
41 
42 namespace hpx { namespace agas
43 {
44 
bootstrap_symbol_namespace_gid()45 naming::gid_type bootstrap_symbol_namespace_gid()
46 {
47     return naming::gid_type(HPX_AGAS_SYMBOL_NS_MSB, HPX_AGAS_SYMBOL_NS_LSB);
48 }
49 
bootstrap_symbol_namespace_id()50 naming::id_type bootstrap_symbol_namespace_id()
51 {
52     return naming::id_type(HPX_AGAS_SYMBOL_NS_MSB, HPX_AGAS_SYMBOL_NS_LSB
53       , naming::id_type::unmanaged);
54 }
55 
56 namespace server
57 {
58 
59 // register all performance counter types exposed by this component
register_counter_types(error_code & ec)60 void symbol_namespace::register_counter_types(
61     error_code& ec
62     )
63 {
64     performance_counters::create_counter_func creator(
65         util::bind_back(&performance_counters::agas_raw_counter_creator
66       , agas::server::symbol_namespace_service_name));
67 
68     for (std::size_t i = 0;
69           i != detail::num_symbol_namespace_services;
70           ++i)
71     {
72         // global counters are handled elsewhere
73         if (detail::symbol_namespace_services[i].code_ == symbol_ns_statistics_counter)
74             continue;
75 
76         std::string name(detail::symbol_namespace_services[i].name_);
77         std::string help;
78         std::string::size_type p = name.find_last_of('/');
79         HPX_ASSERT(p != std::string::npos);
80 
81         if (detail::symbol_namespace_services[i].target_
82             == detail::counter_target_count)
83             help = hpx::util::format(
84                 "returns the number of invocations of the AGAS service '{}'",
85                 name.substr(p+1));
86         else
87             help = hpx::util::format(
88                 "returns the overall execution time of the AGAS service '{}'",
89                 name.substr(p+1));
90 
91         performance_counters::install_counter_type(
92             agas::performance_counter_basename + name
93           , performance_counters::counter_raw
94           , help
95           , creator
96           , &performance_counters::locality_counter_discoverer
97           , HPX_PERFORMANCE_COUNTER_V1
98           , detail::symbol_namespace_services[i].uom_
99           , ec
100           );
101         if (ec) return;
102     }
103 }
104 
register_global_counter_types(error_code & ec)105 void symbol_namespace::register_global_counter_types(
106     error_code& ec
107     )
108 {
109     performance_counters::create_counter_func creator(
110         util::bind_back(&performance_counters::agas_raw_counter_creator
111       , agas::server::symbol_namespace_service_name));
112 
113     for (std::size_t i = 0;
114           i != detail::num_symbol_namespace_services;
115           ++i)
116     {
117         // local counters are handled elsewhere
118         if (detail::symbol_namespace_services[i].code_ != symbol_ns_statistics_counter)
119             continue;
120 
121         std::string help;
122         if (detail::symbol_namespace_services[i].target_ == detail::counter_target_count)
123             help = "returns the overall number of invocations \
124                     of all symbol AGAS services";
125         else
126             help = "returns the overall execution time of all symbol AGAS services";
127 
128         performance_counters::install_counter_type(
129             std::string(agas::performance_counter_basename) +
130                 detail::symbol_namespace_services[i].name_
131           , performance_counters::counter_raw
132           , help
133           , creator
134           , &performance_counters::locality_counter_discoverer
135           , HPX_PERFORMANCE_COUNTER_V1
136           , detail::symbol_namespace_services[i].uom_
137           , ec
138           );
139         if (ec) return;
140     }
141 }
142 
register_server_instance(char const * servicename,std::uint32_t locality_id,error_code & ec)143 void symbol_namespace::register_server_instance(
144     char const* servicename
145   , std::uint32_t locality_id
146   , error_code& ec
147     )
148 {
149     // set locality_id for this component
150     if (locality_id == naming::invalid_locality_id)
151         locality_id = 0;        // if not given, we're on the root
152 
153     this->base_type::set_locality_id(locality_id);
154 
155     // now register this AGAS instance with AGAS :-P
156     instance_name_ = agas::service_name;
157     instance_name_ += servicename;
158     instance_name_ += agas::server::symbol_namespace_service_name;
159 
160     // register a gid (not the id) to avoid AGAS holding a reference to this
161     // component
162     agas::register_name(launch::sync, instance_name_,
163         get_unmanaged_id().get_gid(), ec);
164 }
165 
unregister_server_instance(error_code & ec)166 void symbol_namespace::unregister_server_instance(
167     error_code& ec
168     )
169 {
170     agas::unregister_name(launch::sync, instance_name_, ec);
171     this->base_type::finalize();
172 }
173 
finalize()174 void symbol_namespace::finalize()
175 {
176     if (!instance_name_.empty())
177     {
178         error_code ec(lightweight);
179         agas::unregister_name(launch::sync, instance_name_, ec);
180     }
181 }
182 
bind(std::string key,naming::gid_type gid)183 bool symbol_namespace::bind(
184     std::string key
185   , naming::gid_type gid
186     )
187 { // {{{ bind implementation
188     // parameters
189     util::scoped_timer<std::atomic<std::int64_t> > update(
190         counter_data_.bind_.time_,
191         counter_data_.bind_.enabled_
192     );
193     counter_data_.increment_bind_count();
194 
195     std::unique_lock<mutex_type> l(mutex_);
196 
197     gid_table_type::iterator it = gids_.find(key);
198     gid_table_type::iterator end = gids_.end();
199 
200     if (it != end)
201     {
202         std::int64_t const credits = naming::detail::get_credit_from_gid(gid);
203         naming::gid_type raw_gid = *(it->second);
204 
205         naming::detail::strip_internal_bits_from_gid(raw_gid);
206         naming::detail::strip_internal_bits_from_gid(gid);
207 
208         // increase reference count
209         if (raw_gid == gid)
210         {
211             LAGAS_(info) << hpx::util::format(
212                 "symbol_namespace::bind, key({1}), gid({2}), old_credit({3}), "
213                 "new_credit({4})",
214                 key, gid,
215                 naming::detail::get_credit_from_gid(*(it->second)),
216                 naming::detail::get_credit_from_gid(*(it->second)) + credits);
217 
218             // REVIEW: do we need to add the credit of the argument to the table?
219             naming::detail::add_credit_to_gid(*(it->second), credits);
220 
221             return true;
222         }
223 
224         if (LAGAS_ENABLED(info))
225         {
226             naming::detail::add_credit_to_gid(gid, credits);
227             LAGAS_(info) << hpx::util::format(
228                 "symbol_namespace::bind, key({1}), gid({2}), response(no_success)",
229                 key, gid);
230         }
231 
232         return false;
233     }
234 
235     if (HPX_UNLIKELY(!util::insert_checked(gids_.insert(
236             std::make_pair(key, std::make_shared<naming::gid_type>(gid))))))
237     {
238         l.unlock();
239 
240         HPX_THROW_EXCEPTION(lock_error
241           , "symbol_namespace::bind"
242           , "GID table insertion failed due to a locking error or "
243             "memory corruption");
244     }
245 
246     // handle registered events
247     typedef on_event_data_map_type::iterator iterator;
248     std::pair<iterator, iterator> p = on_event_data_.equal_range(key);
249 
250     std::vector<hpx::id_type> lcos;
251     if (p.first != p.second)
252     {
253         iterator it = p.first;
254         while (it != p.second)
255         {
256             lcos.push_back((*it).second);
257             ++it;
258         }
259 
260         on_event_data_.erase(p.first, p.second);
261 
262         // notify all LCOS which were registered with this name
263         for (hpx::id_type const& id : lcos)
264         {
265             // re-locate the entry in the GID table for each LCO anew, as we
266             // need to unlock the mutex protecting the table for each iteration
267             // below
268             gid_table_type::iterator gid_it = gids_.find(key);
269             if (gid_it == gids_.end())
270             {
271                 l.unlock();
272 
273                 HPX_THROW_EXCEPTION(invalid_status
274                   , "symbol_namespace::bind"
275                   , "unable to re-locate the entry in the GID table");
276             }
277 
278             // hold on to the gid while the map is unlocked
279             std::shared_ptr<naming::gid_type> current_gid = gid_it->second;
280 
281             {
282                 util::unlock_guard<std::unique_lock<mutex_type> > ul(l);
283 
284                 // split the credit as the receiving end will expect to keep the
285                 // object alive
286                 naming::gid_type new_gid =
287                     naming::detail::split_gid_if_needed(*current_gid).get();
288 
289                 // trigger the lco
290                 set_lco_value(id, std::move(new_gid));
291             }
292         }
293     }
294 
295     l.unlock();
296 
297     LAGAS_(info) << hpx::util::format(
298         "symbol_namespace::bind, key({1}), gid({2})",
299         key, gid);
300 
301     return true;
302 } // }}}
303 
resolve(std::string const & key)304 naming::gid_type symbol_namespace::resolve(std::string const& key)
305 { // {{{ resolve implementation
306     // parameters
307     util::scoped_timer<std::atomic<std::int64_t> > update(
308         counter_data_.resolve_.time_,
309         counter_data_.resolve_.enabled_
310     );
311     counter_data_.increment_resolve_count();
312 
313     std::unique_lock<mutex_type> l(mutex_);
314 
315     gid_table_type::iterator it = gids_.find(key);
316     gid_table_type::iterator end = gids_.end();
317 
318     if (it == end)
319     {
320         LAGAS_(info) << hpx::util::format(
321             "symbol_namespace::resolve, key({1}), response(no_success)",
322             key);
323 
324         return naming::invalid_gid;
325     }
326 
327     // hold on to gid before unlocking the map
328     std::shared_ptr<naming::gid_type> current_gid(it->second);
329 
330     l.unlock();
331     naming::gid_type gid = naming::detail::split_gid_if_needed(*current_gid).get();
332 
333     LAGAS_(info) << hpx::util::format(
334         "symbol_namespace::resolve, key({1}), gid({2})",
335         key, gid);
336 
337     return gid;
338 } // }}}
339 
unbind(std::string const & key)340 naming::gid_type symbol_namespace::unbind(std::string const& key)
341 { // {{{ unbind implementation
342     util::scoped_timer<std::atomic<std::int64_t> > update(
343         counter_data_.unbind_.time_,
344         counter_data_.unbind_.enabled_
345     );
346     counter_data_.increment_unbind_count();
347 
348     std::lock_guard<mutex_type> l(mutex_);
349 
350     gid_table_type::iterator it = gids_.find(key);
351     gid_table_type::iterator end = gids_.end();
352 
353     if (it == end)
354     {
355         LAGAS_(info) << hpx::util::format(
356             "symbol_namespace::unbind, key({1}), response(no_success)",
357             key);
358 
359         return naming::invalid_gid;
360     }
361 
362     naming::gid_type const gid = *(it->second);
363 
364     gids_.erase(it);
365 
366     LAGAS_(info) << hpx::util::format(
367         "symbol_namespace::unbind, key({1}), gid({2})",
368         key, gid);
369 
370     return gid;
371 } // }}}
372 
373 // TODO: catch exceptions
iterate(std::string const & pattern)374 symbol_namespace::iterate_names_return_type symbol_namespace::iterate(
375     std::string const& pattern)
376 { // {{{ iterate implementation
377     util::scoped_timer<std::atomic<std::int64_t> > update(
378         counter_data_.iterate_names_.time_,
379         counter_data_.iterate_names_.enabled_
380     );
381     counter_data_.increment_iterate_names_count();
382 
383     std::map<std::string, naming::gid_type> found;
384 
385     if (pattern.find_first_of("*?[]") != std::string::npos)
386     {
387         std::string str_rx(util::regex_from_pattern(pattern, throws));
388         boost::regex rx(str_rx, boost::regex::perl);
389 
390         std::unique_lock<mutex_type> l(mutex_);
391         for (gid_table_type::iterator it = gids_.begin(); it != gids_.end();
392              ++it)
393         {
394             if (!boost::regex_match(it->first, rx))
395                 continue;
396 
397             // hold on to entry while map is unlocked
398             std::shared_ptr<naming::gid_type> current_gid(it->second);
399             util::unlock_guard<std::unique_lock<mutex_type> > ul(l);
400 
401             found[it->first] =
402                 naming::detail::split_gid_if_needed(*current_gid).get();
403         }
404     }
405     else
406     {
407         std::unique_lock<mutex_type> l(mutex_);
408         for (gid_table_type::iterator it = gids_.begin(); it != gids_.end();
409              ++it)
410         {
411             if (!pattern.empty() && pattern != it->first)
412                 continue;
413 
414             // hold on to entry while map is unlocked
415             std::shared_ptr<naming::gid_type> current_gid(it->second);
416             util::unlock_guard<std::unique_lock<mutex_type> > ul(l);
417 
418             found[it->first] =
419                 naming::detail::split_gid_if_needed(*current_gid).get();
420         }
421     }
422 
423     LAGAS_(info) << "symbol_namespace::iterate";
424 
425     return found;
426 } // }}}
427 
on_event(std::string const & name,bool call_for_past_events,hpx::id_type lco)428 bool symbol_namespace::on_event(
429     std::string const& name
430   , bool call_for_past_events
431   , hpx::id_type lco
432     )
433 { // {{{ on_event implementation
434     util::scoped_timer<std::atomic<std::int64_t> > update(
435         counter_data_.on_event_.time_,
436         counter_data_.on_event_.enabled_
437     );
438     counter_data_.increment_on_event_count();
439 
440     std::unique_lock<mutex_type> l(mutex_);
441 
442     bool handled = false;
443     if (call_for_past_events)
444     {
445         gid_table_type::iterator it = gids_.find(name);
446         if (it != gids_.end())
447         {
448             // hold on to entry while map is unlocked
449             std::shared_ptr<naming::gid_type> current_gid(it->second);
450 
451             // split the credit as the receiving end will expect to keep the
452             // object alive
453             {
454                 util::unlock_guard<std::unique_lock<mutex_type> > ul(l);
455                 naming::gid_type new_gid = naming::detail::split_gid_if_needed(
456                     *current_gid).get();
457 
458                 // trigger the lco
459                 handled = true;
460 
461                 // trigger LCO as name is already bound to an id
462                 set_lco_value(lco, std::move(new_gid));
463             }
464         }
465     }
466 
467     if (!handled)
468     {
469         on_event_data_map_type::iterator it = on_event_data_.insert(
470             on_event_data_map_type::value_type(std::move(name), lco));
471 
472         // This overload of insert always returns the iterator pointing
473         // to the inserted value. It should never point to end
474         HPX_ASSERT(it != on_event_data_.end());
475     }
476     l.unlock();
477 
478     LAGAS_(info) << "symbol_namespace::on_event";
479 
480     return true;
481 } // }}}
482 
statistics_counter(std::string const & name)483 naming::gid_type symbol_namespace::statistics_counter(std::string const& name)
484 { // {{{ statistics_counter implementation
485     LAGAS_(info) << "symbol_namespace::statistics_counter";
486 
487     performance_counters::counter_path_elements p;
488     performance_counters::get_counter_path_elements(name, p);
489 
490     if (p.objectname_ != "agas")
491     {
492         HPX_THROW_EXCEPTION(bad_parameter,
493             "symbol_namespace::statistics_counter",
494             "unknown performance counter (unrelated to AGAS)");
495     }
496 
497     namespace_action_code code = invalid_request;
498     detail::counter_target target = detail::counter_target_invalid;
499     for (std::size_t i = 0;
500           i != detail::num_symbol_namespace_services;
501           ++i)
502     {
503         if (p.countername_ == detail::symbol_namespace_services[i].name_)
504         {
505             code = detail::symbol_namespace_services[i].code_;
506             target = detail::symbol_namespace_services[i].target_;
507             break;
508         }
509     }
510 
511     if (code == invalid_request || target == detail::counter_target_invalid)
512     {
513         HPX_THROW_EXCEPTION(bad_parameter,
514             "symbol_namespace::statistics_counter",
515             "unknown performance counter (unrelated to AGAS)");
516     }
517 
518     typedef symbol_namespace::counter_data cd;
519 
520     util::function_nonser<std::int64_t(bool)> get_data_func;
521     if (target == detail::counter_target_count)
522     {
523         switch (code) {
524         case symbol_ns_bind:
525             get_data_func = util::bind_front(&cd::get_bind_count,
526                 &counter_data_);
527             counter_data_.bind_.enabled_ = true;
528             break;
529         case symbol_ns_resolve:
530             get_data_func = util::bind_front(&cd::get_resolve_count,
531                 &counter_data_);
532             counter_data_.resolve_.enabled_ = true;
533             break;
534         case symbol_ns_unbind:
535             get_data_func = util::bind_front(&cd::get_unbind_count,
536                 &counter_data_);
537             counter_data_.unbind_.enabled_ = true;
538             break;
539         case symbol_ns_iterate_names:
540             get_data_func = util::bind_front(&cd::get_iterate_names_count,
541                 &counter_data_);
542             counter_data_.iterate_names_.enabled_ = true;
543             break;
544         case symbol_ns_on_event:
545             get_data_func = util::bind_front(&cd::get_on_event_count,
546                 &counter_data_);
547             counter_data_.on_event_.enabled_ = true;
548             break;
549         case symbol_ns_statistics_counter:
550             get_data_func = util::bind_front(&cd::get_overall_count,
551                 &counter_data_);
552             counter_data_.enable_all();
553             break;
554         default:
555             HPX_THROW_EXCEPTION(bad_parameter
556               , "symbol_namespace::statistics"
557               , "bad action code while querying statistics");
558         }
559     }
560     else {
561         HPX_ASSERT(detail::counter_target_time == target);
562         switch (code) {
563         case symbol_ns_bind:
564             get_data_func = util::bind_front(&cd::get_bind_time,
565                 &counter_data_);
566             counter_data_.bind_.enabled_ = true;
567             break;
568         case symbol_ns_resolve:
569             get_data_func = util::bind_front(&cd::get_resolve_time,
570                 &counter_data_);
571             counter_data_.resolve_.enabled_ = true;
572             break;
573         case symbol_ns_unbind:
574             get_data_func = util::bind_front(&cd::get_unbind_time,
575                 &counter_data_);
576             counter_data_.unbind_.enabled_ = true;
577             break;
578         case symbol_ns_iterate_names:
579             get_data_func = util::bind_front(&cd::get_iterate_names_time,
580                 &counter_data_);
581             counter_data_.iterate_names_.enabled_ = true;
582             break;
583         case symbol_ns_on_event:
584             get_data_func = util::bind_front(&cd::get_on_event_time,
585                 &counter_data_);
586             counter_data_.on_event_.enabled_ = true;
587             break;
588         case symbol_ns_statistics_counter:
589             get_data_func = util::bind_front(&cd::get_overall_time,
590                 &counter_data_);
591             counter_data_.enable_all();
592             break;
593         default:
594             HPX_THROW_EXCEPTION(bad_parameter
595               , "symbol_namespace::statistics"
596               , "bad action code while querying statistics");
597         }
598     }
599 
600     performance_counters::counter_info info;
601     performance_counters::get_counter_type(name, info);
602 
603     performance_counters::complement_counter_info(info);
604 
605     using performance_counters::detail::create_raw_counter;
606     naming::gid_type gid = create_raw_counter(info, get_data_func, hpx::throws);
607     return naming::detail::strip_credits_from_gid(gid);
608 } // }}}
609 
610 // access current counter values
get_bind_count(bool reset)611 std::int64_t symbol_namespace::counter_data::get_bind_count(bool reset)
612 {
613     return util::get_and_reset_value(bind_.count_, reset);
614 }
615 
get_resolve_count(bool reset)616 std::int64_t symbol_namespace::counter_data::get_resolve_count(bool reset)
617 {
618     return util::get_and_reset_value(resolve_.count_, reset);
619 }
620 
get_unbind_count(bool reset)621 std::int64_t symbol_namespace::counter_data::get_unbind_count(bool reset)
622 {
623     return util::get_and_reset_value(unbind_.count_, reset);
624 }
625 
get_iterate_names_count(bool reset)626 std::int64_t symbol_namespace::counter_data::get_iterate_names_count(bool reset)
627 {
628     return util::get_and_reset_value(iterate_names_.count_, reset);
629 }
630 
get_on_event_count(bool reset)631 std::int64_t symbol_namespace::counter_data::get_on_event_count(bool reset)
632 {
633     return util::get_and_reset_value(on_event_.count_, reset);
634 }
635 
get_overall_count(bool reset)636 std::int64_t symbol_namespace::counter_data::get_overall_count(bool reset)
637 {
638     return util::get_and_reset_value(bind_.count_, reset) +
639         util::get_and_reset_value(resolve_.count_, reset) +
640         util::get_and_reset_value(unbind_.count_, reset) +
641         util::get_and_reset_value(iterate_names_.count_, reset) +
642         util::get_and_reset_value(on_event_.count_, reset);
643 }
644 
enable_all()645 void symbol_namespace::counter_data::enable_all()
646 {
647     bind_.enabled_ = true;
648     resolve_.enabled_ = true;
649     unbind_.enabled_ = true;
650     iterate_names_.enabled_ = true;
651     on_event_.enabled_ = true;
652 }
653 
654 // access execution time counters
get_bind_time(bool reset)655 std::int64_t symbol_namespace::counter_data::get_bind_time(bool reset)
656 {
657     return util::get_and_reset_value(bind_.time_, reset);
658 }
659 
get_resolve_time(bool reset)660 std::int64_t symbol_namespace::counter_data::get_resolve_time(bool reset)
661 {
662     return util::get_and_reset_value(resolve_.time_, reset);
663 }
664 
get_unbind_time(bool reset)665 std::int64_t symbol_namespace::counter_data::get_unbind_time(bool reset)
666 {
667     return util::get_and_reset_value(unbind_.time_, reset);
668 }
669 
get_iterate_names_time(bool reset)670 std::int64_t symbol_namespace::counter_data::get_iterate_names_time(bool reset)
671 {
672     return util::get_and_reset_value(iterate_names_.time_, reset);
673 }
674 
get_on_event_time(bool reset)675 std::int64_t symbol_namespace::counter_data::get_on_event_time(bool reset)
676 {
677     return util::get_and_reset_value(on_event_.time_, reset);
678 }
679 
get_overall_time(bool reset)680 std::int64_t symbol_namespace::counter_data::get_overall_time(bool reset)
681 {
682     return util::get_and_reset_value(bind_.time_, reset) +
683         util::get_and_reset_value(resolve_.time_, reset) +
684         util::get_and_reset_value(unbind_.time_, reset) +
685         util::get_and_reset_value(iterate_names_.time_, reset) +
686         util::get_and_reset_value(on_event_.time_, reset);
687 }
688 
689 // increment counter values
increment_bind_count()690 void symbol_namespace::counter_data::increment_bind_count()
691 {
692     if (bind_.enabled_)
693     {
694         ++bind_.count_;
695     }
696 }
697 
increment_resolve_count()698 void symbol_namespace::counter_data::increment_resolve_count()
699 {
700     if (resolve_.enabled_)
701     {
702         ++resolve_.count_;
703     }
704 }
705 
increment_unbind_count()706 void symbol_namespace::counter_data::increment_unbind_count()
707 {
708     if (unbind_.enabled_)
709     {
710         ++unbind_.count_;
711     }
712 }
713 
increment_iterate_names_count()714 void symbol_namespace::counter_data::increment_iterate_names_count()
715 {
716     if (iterate_names_.enabled_)
717     {
718         ++iterate_names_.count_;
719     }
720 }
721 
increment_on_event_count()722 void symbol_namespace::counter_data::increment_on_event_count()
723 {
724     if (on_event_.enabled_)
725     {
726         ++on_event_.count_;
727     }
728 }
729 
730 }}}
731 
732