From 92f9257fe5eac044d7406ed2803db2aa01f4180f Mon Sep 17 00:00:00 2001 From: alexvangogen Date: Wed, 19 Aug 2020 01:17:05 +0300 Subject: [PATCH] Support several search scopes and scopes that must be ignored This implements feature proposed in #69. --- src/native/args.h | 6 ++-- src/native/entry.cc | 25 ++++++++++++++-- src/native/profiler.cc | 65 +++++++++++++++++++++++++++++++++--------- src/native/profiler.h | 9 ++++++ 4 files changed, 87 insertions(+), 18 deletions(-) diff --git a/src/native/args.h b/src/native/args.h index dfafcbb..db8c745 100644 --- a/src/native/args.h +++ b/src/native/args.h @@ -7,7 +7,8 @@ enum profiler_option { _unknown, - _package, + _search_scopes, + _ignored_scopes, _progress_point, _end_to_end, _warmup, @@ -18,7 +19,8 @@ namespace agent_args { profiler_option from_string(std::string &option) { - if (option == "pkg" || option == "package") return _package; + if (option == "pkg" || option == "package" || option == "search") return _search_scopes; + if (option == "ignore") return _ignored_scopes; if (option == "progress-point") return _progress_point; if (option == "end-to-end") return _end_to_end; if (option == "warmup") return _warmup; diff --git a/src/native/entry.cc b/src/native/entry.cc index 0ca95cb..0448ada 100644 --- a/src/native/entry.cc +++ b/src/native/entry.cc @@ -127,6 +127,25 @@ static void releaseCreateLock() { std::atomic_thread_fence(std::memory_order_release); } +bool is_prefix(const char* prefix, char* str) +{ + return strstr(str, prefix) == str + sizeof(char); +} + +using is_prefix_pred_t = std::function; + +bool contains_prefix(std::vector& elements, is_prefix_pred_t predicate) +{ + return std::find_if(std::begin(elements), std::end(elements), predicate) != std::end(elements); +} + +// TODO faster search (trie maybe) +bool is_in_allowed_scope(char *class_sig) +{ + auto predicate = [&class_sig](std::string &scope) { return is_prefix(scope.c_str(), class_sig); }; + return !contains_prefix(Profiler::get_ignored_scopes(), predicate) + && contains_prefix(Profiler::get_search_scopes(), predicate); +} // Calls GetClassMethods on a given class to force the creation of // jmethodIDs of it. @@ -153,9 +172,9 @@ void CreateJMethodIDsForClass(jvmtiEnv *jvmti, jclass klass) { logger->info( "Creating JMethod IDs. [Class: {class}] [Scope: {scope}]", fmt::arg("class", ksig.Get()), fmt::arg("scope", package_str)); - if( strstr(ksig.Get(), package_str.c_str()) == ksig.Get() ) { - prof->addInScopeMethods(method_count, methods.Get()); - + if (is_in_allowed_scope(ksig.Get())) + { + Profiler::addInScopeMethods(method_count, methods.Get()); } //TODO: this matches a prefix. class name AA will match a progress diff --git a/src/native/profiler.cc b/src/native/profiler.cc index eea20ef..e6010d9 100644 --- a/src/native/profiler.cc +++ b/src/native/profiler.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include "display.h" #include "globals.h" @@ -96,6 +97,8 @@ bool Profiler::prof_ready = false; std::string Profiler::package; struct ProgressPoint* Profiler::progress_point = nullptr; std::string Profiler::progress_class; +std::vector Profiler::search_scopes; +std::vector Profiler::ignored_scopes; static std::atomic call_index(0); static JVMPI_CallFrame static_call_frames[NUM_CALL_FRAMES]; @@ -144,10 +147,27 @@ void Profiler::ParseOptions(const char *options) agent_args::report_error(fmt::format("Unknown option: {}", option).c_str()); break; - case _package: - Profiler::package = value; - prepare_scope(Profiler::package); + case _search_scopes: + { + std::stringstream search_scopes_stream(value); + while (std::getline(search_scopes_stream, item, '|')) + { + prepare_scope(item); + add_search_scope(item); + } break; + } + + case _ignored_scopes: + { + std::stringstream ignore_scopes_stream(value); + while (std::getline(ignore_scopes_stream, item, '|')) + { + prepare_scope(item); + add_ignored_scope(item); + } + break; + } case _progress_point: { @@ -175,16 +195,25 @@ void Profiler::ParseOptions(const char *options) } } - logger->info( - "Profiler arguments:\n" - "\tprogress point: {}:{}\n" - "\tscope: {}\n" - "\twarmup: {}us\n" - "\tend-to-end: {}\n" - "\texperiment duration: {}", - progress_class, progress_point->lineno, Profiler::package, warmup_time, end_to_end, fix_exp); - - if (Profiler::package.empty() || (!end_to_end && (progress_class.empty() || progress_point->lineno == -1))) + const char *const delim = ", "; + + std::stringstream joint_search_scopes; + std::copy(search_scopes.begin(), search_scopes.end(), std::ostream_iterator(joint_search_scopes, delim)); + + std::stringstream joint_ignored_scopes; + std::copy(ignored_scopes.begin(), ignored_scopes.end(), + std::ostream_iterator(joint_ignored_scopes, delim)); + + logger->info("Profiler arguments:\n" + "\tprogress point: {}:{}\n" + "\tsearch scopes: {}\n" + "\tignored scopes: {}\n" + "\twarmup: {}us\n" + "\tend-to-end: {}\n" + "\tfixed experiment duration: {}", + progress_class, progress_point->lineno, joint_search_scopes.str(), joint_ignored_scopes.str(), + warmup_time, end_to_end, fix_exp); + if (search_scopes.empty() || (!end_to_end && (progress_class.empty() || progress_point->lineno == -1))) { agent_args::report_error("Missing package, progress class, or progress point"); } @@ -647,6 +676,16 @@ void Profiler::prepare_scope(std::string& scope) { std::replace(scope.begin(), scope.end(), '.', '/'); } +void Profiler::add_search_scope(string &scope) +{ + search_scopes.push_back(scope); +} + +void Profiler::add_ignored_scope(std::string& scope) +{ + ignored_scopes.push_back(scope); +} + void Profiler::Handle(int signum, siginfo_t *info, void *context) { if( !prof_ready ) { return; diff --git a/src/native/profiler.h b/src/native/profiler.h index e06d5a6..d37a2b8 100644 --- a/src/native/profiler.h +++ b/src/native/profiler.h @@ -97,6 +97,9 @@ class Profiler { static std::shared_ptr &getLogger() { return logger; }; + static std::vector& get_search_scopes() { return search_scopes; } + static std::vector& get_ignored_scopes() { return ignored_scopes; } + static std::unordered_set &getInScopeMethods() { return in_scope_ids; } static struct Experiment &getCurrentExperiment() { return current_experiment; } @@ -167,6 +170,9 @@ class Profiler { static void prepare_scope(std::string &scope); + static void add_search_scope(std::string &scope); + static void add_ignored_scope(std::string &scope); + static jobject mbean; static jmethodID mbean_cache_method_id; @@ -227,6 +233,9 @@ class Profiler { static bool fix_exp; + static std::vector search_scopes; + static std::vector ignored_scopes; + static std::shared_ptr logger; };