diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 44c94da8..5f2eb2ad 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Build Env run: | sudo apt-get update - sudo apt install clang llvm-dev libjansson-dev libssl-dev bison flex make cmake + sudo apt install clang llvm-dev libjansson-dev libssl-dev bison flex make cmake mpich clang++ --version - name: Compile check @@ -57,7 +57,7 @@ jobs: run: | python -m pip install --upgrade pip pytest setuptools cd src/python - python setup.py install + python -m pip install -r requirements.txt python -m pip list - name: Run Python Smoke Tests diff --git a/scripts/check-c-code-format.sh b/scripts/check-c-code-format.sh index fcfeb607..2ee2ce11 100755 --- a/scripts/check-c-code-format.sh +++ b/scripts/check-c-code-format.sh @@ -33,6 +33,7 @@ astyle --errors-to-stdout \ --max-code-length=80 \ --break-after-logical \ --indent-switches \ + --add-brackets \ ${FILES} # diff --git a/src/c/CMakeLists.txt b/src/c/CMakeLists.txt index 7d85eaa5..385cb658 100644 --- a/src/c/CMakeLists.txt +++ b/src/c/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.12) project(PerfFlowAspect VERSION "0.1.0") @@ -57,6 +57,27 @@ add_subdirectory(runtime) add_subdirectory(weaver) add_subdirectory(test) +add_library(perfflowaspect INTERFACE) +target_link_libraries(perfflowaspect INTERFACE perfflow_runtime perfflow_parser WeavePassPlugin) +install(TARGETS perfflowaspect + EXPORT perfflow_export + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + add_subdirectory(config) +message(STATUS "Config Dir: ${PERFFLOWASPECT_INSTALL_CONFIG_DIR}") + +if (NOT DEFINED PERFFLOWASPECT_INSTALL_CONFIG_DIR) + set(PERFFLOWASPECT_INSTALL_CONFIG_DIR "share") +endif() + +install(EXPORT perfflow_export + FILE perfflowaspect_targets.cmake + NAMESPACE perfflowaspect:: + DESTINATION ${CMAKE_INSTALL_PREFIX}/${PERFFLOWASPECT_INSTALL_CONFIG_DIR} +) + message(STATUS "PerfFlowAspect version: \"${PROJECT_VERSION}\"") diff --git a/src/c/config/CMakeLists.txt b/src/c/config/CMakeLists.txt index 2b9f8f50..3d87499c 100644 --- a/src/c/config/CMakeLists.txt +++ b/src/c/config/CMakeLists.txt @@ -42,11 +42,11 @@ configure_package_config_file( install(FILES ${CMAKE_CURRENT_BINARY_DIR}/perfflowaspect-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/perfflowaspect-config-version.cmake - perfflowaspect_setup_targets.cmake DESTINATION ${PERFFLOWASPECT_INSTALL_CMAKE_MODULE_DIR}) # Create pkg-config .pc file set(PKG_CONFIG_LIBDIR ${CMAKE_INSTALL_PREFIX}/${PERFFLOWASPECT_INSTALL_LIB_DIR}) + set(PKG_CONFIG_LIBS "-L\${libdir} -lperfflow_runtime -L\${libdir} -lperfflow_parser -lssl -lcrypto") configure_file( diff --git a/src/c/config/perfflowaspect-config.cmake.in b/src/c/config/perfflowaspect-config.cmake.in index cc09f430..db15c33b 100644 --- a/src/c/config/perfflowaspect-config.cmake.in +++ b/src/c/config/perfflowaspect-config.cmake.in @@ -3,8 +3,13 @@ if (NOT PERFFLOWASPECT_CONFIG_LOADED) set(PERFFLOWASPECT_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") set(PERFFLOWASPECT_LIB_DIR "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@") + include(CMakeFindDependencyMacro) + + find_dependency(OpenSSL REQUIRED) + # Library targets imported from file - include(${PERFFLOWASPECT_INSTALL_PREFIX}/share/perfflowaspect_setup_targets.cmake) + # include(${PERFFLOWASPECT_INSTALL_PREFIX}/share/perfflowaspect_setup_targets.cmake) + include(${PERFFLOWASPECT_INSTALL_PREFIX}/share/perfflowaspect_targets.cmake) set(PERFFLOWASPECT_CONFIG_LOADED TRUE) endif() diff --git a/src/c/config/perfflowaspect_setup_targets.cmake b/src/c/config/perfflowaspect_setup_targets.cmake deleted file mode 100644 index ca1b30f4..00000000 --- a/src/c/config/perfflowaspect_setup_targets.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# create convenience target that bundles all reg perfflowaspect deps -add_library(perfflowaspect::perfflowaspect INTERFACE IMPORTED) - -set_property(TARGET perfflowaspect::perfflowaspect - PROPERTY INTERFACE_LINK_LIBRARIES - perfflowaspect) - -if(NOT PerfFlowAspect_FIND_QUIETLY) - message(STATUS "PERFFLOWASPECT_VERSION = ${PERFFLOWASPECT_VERSION}") - message(STATUS "PERFFLOWASPECT_INSTALL_PREFIX = ${PERFFLOWASPECT_INSTALL_PREFIX}") - - set(_print_targets "") - set(_print_targets "perfflowaspect::perfflowaspect ") - message(STATUS "PerfFlowAspect imported targets: ${_print_targets}") - unset(_print_targets) -endif() diff --git a/src/c/parser/CMakeLists.txt b/src/c/parser/CMakeLists.txt index 927a9231..0b1a0f57 100644 --- a/src/c/parser/CMakeLists.txt +++ b/src/c/parser/CMakeLists.txt @@ -45,7 +45,7 @@ target_include_directories(perfflow_parser_static PRIVATE ${CMAKE_CURRENT_BINARY target_include_directories(perfflow_parser PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) install(TARGETS perfflow_parser - EXPORT perfflow_parser + EXPORT perfflow_export LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/c/runtime/CMakeLists.txt b/src/c/runtime/CMakeLists.txt index aba67c63..2a8d842b 100644 --- a/src/c/runtime/CMakeLists.txt +++ b/src/c/runtime/CMakeLists.txt @@ -12,7 +12,9 @@ set(perfflow_runtime_sources perfflow_runtime.cpp ) -set(perfflow_runtime_deps -ljansson -lssl -lcrypto +find_package(OpenSSL REQUIRED) + +set(perfflow_runtime_deps -ljansson ) add_library(perfflow_runtime SHARED @@ -20,10 +22,10 @@ add_library(perfflow_runtime SHARED ${perfflow_runtime_headers} ) -target_link_libraries(perfflow_runtime ${perfflow_runtime_deps}) +target_link_libraries(perfflow_runtime ${perfflow_runtime_deps} OpenSSL::SSL OpenSSL::Crypto) install(TARGETS perfflow_runtime - EXPORT perfflow_runtime + EXPORT perfflow_export LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/c/runtime/advice_base.hpp b/src/c/runtime/advice_base.hpp index 19cb7550..745d7ac9 100644 --- a/src/c/runtime/advice_base.hpp +++ b/src/c/runtime/advice_base.hpp @@ -16,10 +16,12 @@ struct advice_base_t virtual ~advice_base_t () {} virtual int before (const char *module, const char *function, - const char *flow) = 0; + const char *flow, + const char *pcut) = 0; virtual int after (const char *module, const char *function, - const char *flow) = 0; + const char *flow, + const char *pcut) = 0; virtual int before_async (const char *module, const char *function, const char *scope, diff --git a/src/c/runtime/advice_chrome_tracing.cpp b/src/c/runtime/advice_chrome_tracing.cpp index 699c433d..2d64aea0 100644 --- a/src/c/runtime/advice_chrome_tracing.cpp +++ b/src/c/runtime/advice_chrome_tracing.cpp @@ -22,6 +22,7 @@ #include #include #include +#include // TODO: only works for Linux #define my_gettid() ((pid_t)syscall(SYS_gettid)) @@ -39,24 +40,31 @@ int advice_chrome_tracing_t::get_timestamp(double &tstamp) int rc; struct timeval ts; if ((rc = gettimeofday(&ts, NULL)) < 0) + { return rc; + } tstamp = (double)ts.tv_sec * 1000000.f + (double)ts.tv_usec; return 0; } int advice_chrome_tracing_t::create_event(json_t **o, const char *module, - const char *function) + const char *function, + double &ts) { int rc, status; char *cxa; - double ts; json_t *json; pid_t pid, tid; std::string demangle; - if ((rc = get_timestamp(ts)) < 0) - return rc; + if (ts == 0) + { + if ((rc = get_timestamp(ts)) < 0) + { + return rc; + } + } pid = getpid(); tid = my_gettid(); @@ -64,7 +72,9 @@ int advice_chrome_tracing_t::create_event(json_t **o, demangle = (cxa) ? cxa : function; std::size_t pos = demangle.find_first_of('('); if (pos != std::string::npos) + { demangle = demangle.substr(0, pos); + } if (!(json = json_pack("{s:s s:s s:I s:I s:f}", "name", demangle.c_str(), @@ -84,8 +94,11 @@ int advice_chrome_tracing_t::create_event(json_t **o, int advice_chrome_tracing_t::encode_event(json_t *o, const char *ph, const char *scope, - const char *flow_enclose, int64_t id) + const char *flow_enclose, int64_t id, + double cpu_usage, long mem_usage) { + char *temp; + json_t *args_o = json_object(); if (!o || !ph) { errno = EINVAL; @@ -94,32 +107,72 @@ int advice_chrome_tracing_t::encode_event(json_t *o, const char *ph, json_t *ph_o; if (!(ph_o = json_string(ph))) + { goto json_memerror; + } if (json_object_set_new(o, "ph", ph_o) < 0) + { goto json_memerror; + } if (scope) { json_t *sc; if (!(sc = json_string(scope))) + { goto json_memerror; + } if (json_object_set_new(o, "scope", sc) < 0) + { goto json_memerror; + } } if (flow_enclose) { json_t *enclose; if (!(enclose = json_string("e"))) + { goto json_memerror; + } if (json_object_set_new(o, "bp", enclose) < 0) + { goto json_memerror; + } } if (id >= 0) { json_t *id_o; if (!(id_o = json_integer(static_cast(id)))) + { goto json_memerror; + } if (json_object_set_new(o, "id", id_o) < 0) + { + goto json_memerror; + } + } + if (std::string("C") == ph) + { + json_t *cpu_usage_o, *mem_usage_o; + if (!(cpu_usage_o = json_real(cpu_usage))) + { + goto json_memerror; + } + if (json_object_set_new(args_o, "cpu_usage", cpu_usage_o) < 0) + { + goto json_memerror; + } + if (!(mem_usage_o = json_integer(static_cast(mem_usage)))) + { goto json_memerror; + } + if (json_object_set_new(args_o, "memory_usage", mem_usage_o) < 0) + { + goto json_memerror; + } + if (json_object_set_new(o, "args", args_o) < 0) + { + goto json_memerror; + } } return 0; @@ -134,7 +187,9 @@ int advice_chrome_tracing_t::flush_if(size_t size) try { if ((rc = pthread_mutex_lock(&m_mutex)) < 0) + { return rc; + } m_oss.seekp(0, std::ios::end); std::stringstream::pos_type offset = m_oss.tellp(); if (offset >= size) @@ -149,12 +204,16 @@ int advice_chrome_tracing_t::flush_if(size_t size) m_oss.clear(); } if ((rc = pthread_mutex_unlock(&m_mutex)) < 0) + { return rc; + } } catch (std::ostream::failure &e) { if (errno == 0) + { errno = EIO; + } return -1; } return 0; @@ -179,6 +238,10 @@ int advice_chrome_tracing_t::cannonicalize_perfflow_options() { m_perfflow_options["log-enable"] = "True"; } + if (m_perfflow_options.find("cpu_mem_usage") == m_perfflow_options.end()) + { + m_perfflow_options["cpu_mem_usage"] = "False"; + } return 0; } @@ -193,7 +256,9 @@ int advice_chrome_tracing_t::parse_perfflow_options() std::string entry; ss << options; while (getline(ss, entry, ':')) + { options_list.push_back(entry); + } } for (auto &opt : options_list) { @@ -217,10 +282,14 @@ const std::string advice_chrome_tracing_t::get_foreign_wm() { char *foreign_job_id = getenv("SLURM_JOB_ID"); if (foreign_job_id) + { return "slurm"; + } foreign_job_id = getenv("LSB_JOBID"); if (foreign_job_id) + { return "lsf"; + } return ""; } @@ -233,14 +302,18 @@ const std::string advice_chrome_tracing_t::get_uniq_id_from_foreign_wm() char *job_id = getenv("SLURM_JOB_ID"); char *step_id = getenv("SLURM_STEP_ID"); if (job_id && step_id) + { uniq_id = std::string(job_id) + "." + std::string(step_id); + } } else if (foreign_wm == "lsf") { char *job_id = getenv("LSB_JOBID"); char *step_id = getenv("LS_JOBPID"); if (job_id && step_id) + { uniq_id = std::string(job_id) + "." + std::string(step_id); + } } return uniq_id; } @@ -283,7 +356,9 @@ const std::string advice_chrome_tracing_t::get_perfflow_instance_path() std::string uri_path = uri_copy.substr(found + 3); found = uri_path.find_last_of("/"); if (found != std::string::npos) + { uniq_id = uri_path.substr(0, found); + } } } unsigned char sha1[SHA_DIGEST_LENGTH]; @@ -305,9 +380,13 @@ const std::string advice_chrome_tracing_t::get_perfflow_instance_path() instance_path_c_str = getenv("PERFFLOW_INSTANCE_PATH"); if (!instance_path_c_str) + { instance_path = instance_id; + } else + { instance_path = std::string(instance_path_c_str) + "." + instance_id; + } return instance_path; } @@ -360,7 +439,9 @@ advice_chrome_tracing_t::advice_chrome_tracing_t () ss << include; while (getline(ss, entry, ',')) + { include_list.push_back(entry); + } char hn[128]; if (gethostname(hn, 128) < 0) @@ -372,13 +453,21 @@ advice_chrome_tracing_t::advice_chrome_tracing_t () for (auto &inc : include_list) { if (inc == "name") + { m_fn += "." + m_perfflow_options["name"]; + } else if (inc == "instance-path") + { m_fn += ".{" + inst_path + "}"; + } else if (inc == "hostname") + { m_fn += "." + std::string(hn); + } else if (inc == "pid") + { m_fn += "." + std::to_string(getpid()); + } } m_fn += ".pfw"; @@ -408,6 +497,24 @@ advice_chrome_tracing_t::advice_chrome_tracing_t () "invalid log-enable value"); } + std::string usage_enable = m_perfflow_options["cpu_mem_usage"]; + if (usage_enable == "False" || usage_enable == "false" || + usage_enable == "FALSE") + { + m_usage_enable = 0; + } + else if (usage_enable == "True" || usage_enable == "true" || + usage_enable == "TRUE") + { + m_usage_enable = 1; + } + else + { + throw std::system_error(errno, + std::system_category(), + "invalid usage-enable value"); + } + m_before_counter_mutex = PTHREAD_MUTEX_INITIALIZER; m_after_counter_mutex = PTHREAD_MUTEX_INITIALIZER; m_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -417,20 +524,58 @@ advice_chrome_tracing_t::~advice_chrome_tracing_t () { flush_if(1); if (m_ofs.is_open()) + { m_ofs.close(); + } } int advice_chrome_tracing_t::write_to_sstream(const char *str) { int rc; if ((rc = pthread_mutex_lock(&m_mutex)) < 0) + { return rc; + } m_oss << str << "," << std::endl; if ((rc = pthread_mutex_unlock(&m_mutex)) < 0) + { return rc; + } return rc; } +double advice_chrome_tracing_t::get_wall_time() +{ + struct timeval start; + double time_d; + if (gettimeofday(&start, NULL)) + { + return 0; + } + time_d = (double)start.tv_sec + (double)start.tv_usec * .000001; + return time_d; +} + +double advice_chrome_tracing_t::get_cpu_time() +{ + struct rusage usage; + struct timeval time_u; + double time_d; + getrusage(RUSAGE_SELF, &usage); + time_u = usage.ru_utime; + time_d = (double) time_u.tv_sec + (double) time_u.tv_usec / 1000000; + return time_d; +} + +long advice_chrome_tracing_t::get_memory_usage() +{ + struct rusage usage; + long max_ram_usage; + getrusage(RUSAGE_SELF, &usage); + max_ram_usage = usage.ru_maxrss; + return max_ram_usage; +} + int advice_chrome_tracing_t::with_flow(const char *module, const char *function, const char *flow, @@ -439,14 +584,17 @@ int advice_chrome_tracing_t::with_flow(const char *module, int rc; char *json_str; json_t *event, *ph; + double my_ts; if (m_enable_logging) { - if ((rc = create_event(&event, module, function)) < 0) + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { return rc; + } if (std::string("in") == flow) { - if ((rc = encode_event(event, "f", nullptr, "e", -1)) < 0) + if ((rc = encode_event(event, "f", nullptr, "e", -1, -1, -1)) < 0) { json_decref(event); return rc; @@ -454,7 +602,7 @@ int advice_chrome_tracing_t::with_flow(const char *module, } else if (std::string("out") == flow) { - if ((rc = encode_event(event, "s", nullptr, "e", -1)) < 0) + if ((rc = encode_event(event, "s", nullptr, "e", -1, -1, -1)) < 0) { json_decref(event); return rc; @@ -502,17 +650,23 @@ int advice_chrome_tracing_t::with_flow(const char *module, int advice_chrome_tracing_t::before(const char *module, const char *function, - const char *flow) + const char *flow, + const char *pcut) { int rc; char *json_str; - json_t *event, *ph; + json_t *event, *ph, *jtemp; + double my_ts = 0, cpu_start, wall_start; + std::string fname; + long mem_start; if (m_enable_logging) { - if ((rc = create_event(&event, module, function)) < 0) + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { return rc; - if ((rc = encode_event(event, "B", nullptr, nullptr, -1)) < 0) + } + if ((rc = encode_event(event, "B", nullptr, nullptr, -1, -1, -1)) < 0) { json_decref(event); return rc; @@ -529,17 +683,49 @@ int advice_chrome_tracing_t::before(const char *module, return rc; } + if (std::string("around") == pcut && m_usage_enable == 1) + { + jtemp = json_object_get(event, "name"); + std::string my_name = json_string_value(jtemp); + jtemp = json_object_get(event, "pid"); + int my_pid = (int) json_integer_value(jtemp); + jtemp = json_object_get(event, "tid"); + int my_tid = (int) json_integer_value(jtemp); + + fname = my_name + "_" + std::to_string(my_pid) + "_" + std::to_string( + my_tid) + ".txt"; + std::ofstream myfile(fname.c_str()); + cpu_start = get_cpu_time(); + wall_start = get_wall_time(); + mem_start = get_memory_usage(); + + if (myfile.is_open()) + { + myfile << std::to_string(cpu_start) << "\n"; + myfile << std::to_string(wall_start) << "\n"; + myfile << std::to_string(my_ts) << "\n"; + myfile << std::to_string(mem_start) << "\n"; + myfile.close(); + }; + } + free(json_str); json_decref(event); if ((rc = flush_if(FLUSH_SIZE)) < 0) + { return rc; + } if (std::string("NA") != flow) { const char *eff_flow = flow; if (std::string("inout") == flow) + { eff_flow = "in"; + } else if (std::string("outin") == flow) + { eff_flow = "out"; + } rc = with_flow("flow", "flow", eff_flow, 100); } return rc; @@ -552,11 +738,24 @@ int advice_chrome_tracing_t::before(const char *module, int advice_chrome_tracing_t::after(const char *module, const char *function, - const char *flow) + const char *flow, + const char *pcut) { + double cpu_usage, wall_time; + long mem_usage; + if (std::string("around") == pcut) + { + cpu_usage = get_cpu_time(); + wall_time = get_wall_time(); + mem_usage = get_memory_usage(); + } + int rc; char *json_str; - json_t *event, *ph; + json_t *event, *ph, *jtemp; + double my_ts = 0, prev_ts, cpu_start, wall_start, cpu_percentage; + std::string line, fname; + long mem_start; if (m_enable_logging) { @@ -564,15 +763,23 @@ int advice_chrome_tracing_t::after(const char *module, { const char *eff_flow = flow; if (std::string("inout") == flow) + { eff_flow = "out"; + } else if (std::string("outin") == flow) + { eff_flow = "in"; + } if ((rc = with_flow("flow", "flow", eff_flow, 100)) < 0) + { return rc; + } } - if ((rc = create_event(&event, module, function)) < 0) + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { return rc; - if ((rc = encode_event(event, "E", nullptr, nullptr, -1)) < 0) + } + if ((rc = encode_event(event, "E", nullptr, nullptr, -1, -1, -1)) < 0) { json_decref(event); return rc; @@ -588,6 +795,91 @@ int advice_chrome_tracing_t::after(const char *module, json_decref(event); return rc; } + + if (std::string("around") == pcut && m_usage_enable == 1) + { + jtemp = json_object_get(event, "name"); + std::string my_name = json_string_value(jtemp); + jtemp = json_object_get(event, "pid"); + int my_pid = (int) json_integer_value(jtemp); + jtemp = json_object_get(event, "tid"); + int my_tid = (int) json_integer_value(jtemp); + + fname = my_name + "_" + std::to_string(my_pid) + "_" + std::to_string( + my_tid) + ".txt"; + std::ifstream myfile(fname.c_str()); + if (myfile.is_open()) + { + std::vector lines; + while (getline(myfile, line)) + { + lines.push_back(line); + } + cpu_start = std::stod(lines[0]); + wall_start = std:: stod(lines[1]); + prev_ts = std::stod(lines[2]); + mem_start = std::stol(lines[3]); + myfile.close(); + + int status = remove(fname.c_str()); + if (status != 0) + { + std::perror("Error deleting file\n"); + } + } + + cpu_usage = cpu_usage - cpu_start; + if (cpu_usage < 0.0001) + { + cpu_usage = 0; + } + wall_time = wall_time - wall_start; + cpu_percentage = (cpu_usage / wall_time) * 100; + + if ((rc = create_event(&event, module, function, prev_ts)) < 0) + { + return rc; + } + if ((rc = encode_event(event, "C", nullptr, nullptr, -1, cpu_percentage, + mem_usage)) < 0) + { + json_decref(event); + return rc; + } + if (!(json_str = json_dumps(event, JSON_INDENT(0)))) + { + json_decref(event); + errno = ENOMEM; + return -1; + } + if ((rc = write_to_sstream(json_str)) < 0) + { + json_decref(event); + return rc; + } + + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { + return rc; + } + if ((rc = encode_event(event, "C", nullptr, nullptr, -1, 0.0, 0.0)) < 0) + { + json_decref(event); + return rc; + } + if (!(json_str = json_dumps(event, JSON_INDENT(0)))) + { + json_decref(event); + errno = ENOMEM; + return -1; + } + if ((rc = write_to_sstream(json_str)) < 0) + { + json_decref(event); + return rc; + } + } + free(json_str); json_decref(event); return flush_if(FLUSH_SIZE); @@ -606,18 +898,21 @@ int advice_chrome_tracing_t::before_async(const char *module, int rc; char *json_str; json_t *event, *ph, *sc; + double my_ts; if (m_enable_logging) { - if ((rc = create_event(&event, module, function)) < 0) + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { return rc; + } if ((rc = pthread_mutex_lock(&m_before_counter_mutex)) < 0) { json_decref(event); return rc; } if ((rc = encode_event(event, "b", scope, nullptr, - m_before_counter)) < 0) + m_before_counter, -1, -1)) < 0) { json_decref(event); return rc; @@ -642,14 +937,20 @@ int advice_chrome_tracing_t::before_async(const char *module, free(json_str); json_decref(event); if ((rc = flush_if(FLUSH_SIZE)) < 0) + { return rc; + } if (std::string("NA") != flow) { const char *eff_flow = flow; if (std::string("inout") == flow) + { eff_flow = "in"; + } else if (std::string("outin") == flow) + { eff_flow = "out"; + } rc = with_flow("flow", "flow", flow, 100); } return rc; @@ -668,6 +969,7 @@ int advice_chrome_tracing_t::after_async(const char *module, int rc; char *json_str; json_t *event, *ph, *sc; + double my_ts; if (m_enable_logging) { @@ -675,21 +977,29 @@ int advice_chrome_tracing_t::after_async(const char *module, { const char *eff_flow = flow; if (std::string("inout") == flow) + { eff_flow = "out"; + } else if (std::string("outin") == flow) + { eff_flow = "in"; + } if ((rc = with_flow("flow", "flow", eff_flow, 100)) < 0) + { return rc; + } } - if ((rc = create_event(&event, module, function)) < 0) + if ((rc = create_event(&event, module, function, my_ts)) < 0) + { return rc; + } if ((rc = pthread_mutex_lock(&m_after_counter_mutex)) < 0) { json_decref(event); return rc; } if ((rc = encode_event(event, "e", scope, - nullptr, m_after_counter)) < 0) + nullptr, m_after_counter, -1, -1)) < 0) { json_decref(event); return rc; diff --git a/src/c/runtime/advice_chrome_tracing.hpp b/src/c/runtime/advice_chrome_tracing.hpp index 94c5ba63..b3ec8bad 100644 --- a/src/c/runtime/advice_chrome_tracing.hpp +++ b/src/c/runtime/advice_chrome_tracing.hpp @@ -22,9 +22,9 @@ class advice_chrome_tracing_t : public advice_base_t advice_chrome_tracing_t (); virtual ~advice_chrome_tracing_t (); virtual int before (const char *module, - const char *function, const char *flow); + const char *function, const char *flow, const char *pcut); virtual int after (const char *module, - const char *function, const char *flow); + const char *function, const char *flow, const char *pcut); virtual int before_async (const char *module, const char *function, const char *scope, const char *flow); @@ -32,14 +32,17 @@ class advice_chrome_tracing_t : public advice_base_t const char *function, const char *scope, const char *flow); private: - int create_event (json_t **o, const char *module, const char *function); + int create_event (json_t **o, const char *module, const char *function, double &my_ts); int get_timestamp (double &tstamp); int encode_event (json_t *o, const char *ph, - const char *scope, const char *enclose, int64_t id); + const char *scope, const char *enclose, int64_t id, double cpu_usage, long mem_usage); int with_flow (const char *module, const char *function, const char *flow, int64_t id); int flush_if (size_t size); int write_to_sstream (const char *str); + double get_wall_time(); + double get_cpu_time(); + long get_memory_usage(); int cannonicalize_perfflow_options (); int parse_perfflow_options (); @@ -52,9 +55,10 @@ class advice_chrome_tracing_t : public advice_base_t std::ostringstream m_oss; std::ofstream m_ofs; std::string m_fn = ""; - int m_enable_logging = 0; + int m_enable_logging = 1; /* Default should be true */ int m_before_counter = 0; int m_after_counter = 0; + int m_usage_enable = 0; pthread_mutex_t m_before_counter_mutex; pthread_mutex_t m_after_counter_mutex; pthread_mutex_t m_mutex; diff --git a/src/c/runtime/perfflow_runtime.cpp b/src/c/runtime/perfflow_runtime.cpp index c035b812..61bc096e 100644 --- a/src/c/runtime/perfflow_runtime.cpp +++ b/src/c/runtime/perfflow_runtime.cpp @@ -49,14 +49,21 @@ extern "C" void perfflow_weave_before(int async, const char *module, const char *function, const char *scope, - const char *flow) + const char *flow, + const char *pcut) { if (advice == nullptr) + { return; + } if (async) + { advice->before_async(module, function, scope, flow); + } else - advice->before(module, function, flow); + { + advice->before(module, function, flow, pcut); + } return; } @@ -64,14 +71,21 @@ extern "C" void perfflow_weave_after(int async, const char *module, const char *function, const char *scope, - const char *flow) + const char *flow, + const char *pcut) { if (advice == nullptr) + { return; + } if (async) + { advice->after_async(module, function, scope, flow); + } else - advice->after(module, function, flow); + { + advice->after(module, function, flow, pcut); + } return; } diff --git a/src/c/test/CMakeLists.txt b/src/c/test/CMakeLists.txt index 33c819c8..84b49c33 100644 --- a/src/c/test/CMakeLists.txt +++ b/src/c/test/CMakeLists.txt @@ -1,14 +1,24 @@ set(SMOKETESTS smoketest smoketest2 + smoketest3 + smoketest_MPI + smoketest_MT ) +find_package(MPI REQUIRED) +find_package(Threads REQUIRED) +include_directories(${MPI_INCLUDE_PATH}) + set(perfflow_deps "-L../runtime -lperfflow_runtime -lcrypto") +set(THREADS_PREFER_PTHREAD_FLAG ON) message(STATUS "Adding CXX unit tests") foreach(TEST ${SMOKETESTS}) message(STATUS " [*] Adding test: ${TEST}") add_executable(${TEST} ${TEST}.cpp) + target_link_libraries(${TEST} ${MPI_LIBRARIES}) + target_link_libraries(${TEST} pthread) set_source_files_properties(${TEST}.cpp COMPILE_FLAGS "-Xclang -load -Xclang ../weaver/weave/libWeavePass.so -fPIC") target_link_libraries(${TEST} ${perfflow_deps}) endforeach() diff --git a/src/c/test/smoketest.cpp b/src/c/test/smoketest.cpp index 136b949b..5a10887b 100644 --- a/src/c/test/smoketest.cpp +++ b/src/c/test/smoketest.cpp @@ -33,7 +33,9 @@ int foo(const std::string &str) usleep(1000); bar(); if (str == "hello") + { return 1; + } return 0; } @@ -41,7 +43,9 @@ int main(int argc, char *argv[]) { printf("Inside main\n"); for (int i = 0; i < 4; i++) + { foo("hello"); + } return 0; } diff --git a/src/c/test/smoketest2.cpp b/src/c/test/smoketest2.cpp index 21b9e40f..d08a2d1d 100644 --- a/src/c/test/smoketest2.cpp +++ b/src/c/test/smoketest2.cpp @@ -29,7 +29,9 @@ int foo(const std::string &str) printf("Hello\n"); bar(); if (str == "hello") + { return 1; + } return 0; } diff --git a/src/c/test/smoketest3.cpp b/src/c/test/smoketest3.cpp new file mode 100644 index 00000000..4fbb7eb4 --- /dev/null +++ b/src/c/test/smoketest3.cpp @@ -0,0 +1,64 @@ +/************************************************************\ + * Copyright 2021 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#include +#include +#include + +__attribute__((annotate("@critical_path(pointcut='around')"))) +void bas() +{ + printf("bas\n"); +} + +__attribute__((annotate("@critical_path(pointcut='around')"))) +void bar() +{ + printf("bar\n"); + bas(); +} + +__attribute__((annotate("@critical_path()"))) +int foo(const std::string &str) +{ + printf("foo\n"); + usleep(1000); + bar(); + int temp = 0; + int temp1[1000000] = {25}; + int temp2[10000] = {22}; + int temp3[10000] = {0}; + + for (int i = 0; i < 10000; i++) + { + temp = temp + 1; + temp3[i] = temp1[i] * temp2[i]; + for (int j = i + 1; j < 10000; j++) + { + temp3[j] = temp3[j] / 3; + } + } + if (str == "hello") + { + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + printf("Inside main\n"); + foo("hello"); + return 0; +} + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/src/c/test/smoketest_MPI.cpp b/src/c/test/smoketest_MPI.cpp new file mode 100644 index 00000000..c217de75 --- /dev/null +++ b/src/c/test/smoketest_MPI.cpp @@ -0,0 +1,67 @@ +/************************************************************\ + * Copyright 2021 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#include +#include +#include + +using namespace std; + +#define MASTER 0 //main process + +__attribute__((annotate("@critical_path(pointcut='around')"))) +int foo(const string &str) +{ + printf("foo\n"); + int temp = 0; + int temp1[10000] = {25}; + int temp2[10000] = {22}; + int temp3[10000] = {0}; + for (int i = 0; i < 10000; i++) + { + temp = temp + 1; + temp3[i] = temp1[i] * temp2[i]; + for (int j = i + 1; j < 10000; j++) + { + temp3[j] = temp3[j] / 3; + } + } + if (str == "hello") + { + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int taskid, numProcs; + MPI_Status status; + + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &numProcs); + MPI_Comm_rank(MPI_COMM_WORLD, &taskid); + + //main process code + if (taskid == MASTER) + { + cout << "taskid: " << taskid << '\n'; + foo("hello"); + } + + //worker process code + if (taskid != MASTER) + { + cout << "taskid: " << taskid << '\n'; + foo("hello"); + } + + MPI_Finalize(); +} diff --git a/src/c/test/smoketest_MT.cpp b/src/c/test/smoketest_MT.cpp new file mode 100644 index 00000000..9190f2b3 --- /dev/null +++ b/src/c/test/smoketest_MT.cpp @@ -0,0 +1,42 @@ +/************************************************************\ + * Copyright 2021 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#include +#include +#include + +#define N 3 + +__attribute__((annotate("@critical_path(pointcut='around')"))) +void *foo(void *threadid) +{ + long tid; + tid = (long)threadid; + printf("This is worker_thread() %ld \n", tid); + pthread_exit(NULL); +} + +int main() +{ + pthread_t my_thread[N]; + + long id; + for (id = 1; id <= N; id++) + { + int ret = pthread_create(&my_thread[id], NULL, &foo, (void *)id); + if (ret != 0) + { + printf("Error: pthread_create() failed\n"); + exit(EXIT_FAILURE); + } + } + + pthread_exit(NULL); +} diff --git a/src/c/test/t0001-cbinding-basic.t.in b/src/c/test/t0001-cbinding-basic.t.in index 8bd17df9..410edbd0 100755 --- a/src/c/test/t0001-cbinding-basic.t.in +++ b/src/c/test/t0001-cbinding-basic.t.in @@ -162,4 +162,63 @@ test_expect_success 'PERFFLOW_OPTIONS: disable logging smoketest2' ' fi ' +test_expect_success 'c binding: smoketest3 runs ok in default' ' + ../smoketest3 && + rm perfflow.$(hostname).[0-9]*.pfw +' + +test_expect_success 'PERFFLOW_OPTIONS: disable logging smoketest3' ' + PERFFLOW_OPTIONS="log-enable=False" ../smoketest3 && + ! test -f perfflow.$(hostname).[0-9]*.pfw + if test -f perfflow.$(hostname).[0-9]*.pfw; then + rm perfflow.$(hostname).[0-9]*.pfw + fi +' + +test_expect_success 'PERFFLOW_OPTIONS: enable logging smoketest3' ' + PERFFLOW_OPTIONS="log-enable=True" ../smoketest3 && + test -f perfflow.$(hostname).[0-9]*.pfw && + rm perfflow.$(hostname).[0-9]*.pfw +' + +test_expect_success 'c binding: smoketest_MT runs ok in default' ' + ../smoketest_MT && + rm perfflow.$(hostname).[0-9]*.pfw +' + +test_expect_success 'PERFFLOW_OPTIONS: disable logging smoketest_MT' ' + PERFFLOW_OPTIONS="log-enable=False" ../smoketest_MT && + ! test -f perfflow.$(hostname).[0-9]*.pfw + if test -f perfflow.$(hostname).[0-9]*.pfw; then + rm perfflow.$(hostname).[0-9]*.pfw + fi +' + +test_expect_success 'PERFFLOW_OPTIONS: enable logging smoketest_MT' ' + PERFFLOW_OPTIONS="log-enable=True" ../smoketest_MT && + test -f perfflow.$(hostname).[0-9]*.pfw && + rm perfflow.$(hostname).[0-9]*.pfw +' + +test_expect_success 'c binding: smoketest_MPI runs ok in default' ' + mpirun -n 2 ../smoketest_MPI + rm perfflow.$(hostname).[0-9]*.pfw +' + +test_expect_success 'PERFFLOW_OPTIONS: disable logging smoketest_MPI' ' + PERFFLOW_OPTIONS="log-enable=False" mpirun -n 2 ../smoketest_MPI && + ls -1 perfflow.$(hostname).[0-9]*.pfw 2>/dev/null | wc -l && + test `ls -1 perfflow.$(hostname).[0-9]*.pfw 2>/dev/null | wc -l` -eq 0 && + if test `ls -1 perfflow.$(hostname).[0-9]*.pfw 2>/dev/null | wc -l` -gt 0; then + rm -f perfflow.$(hostname).[0-9]*.pfw + fi +' + +test_expect_success 'PERFFLOW_OPTIONS: enable logging smoketest_MPI' ' + PERFFLOW_OPTIONS="log-enable=True" mpirun -n 2 ../smoketest_MPI && + ls -1 perfflow.$(hostname).[0-9]*.pfw 2>/dev/null | wc -l && + test `ls -1 perfflow.$(hostname).[0-9]*.pfw 2>/dev/null | wc -l` -eq 2 && + rm perfflow.$(hostname).[0-9]*.pfw +' + test_done diff --git a/src/c/weaver/weave/CMakeLists.txt b/src/c/weaver/weave/CMakeLists.txt index 001941e4..6aab8fdd 100644 --- a/src/c/weaver/weave/CMakeLists.txt +++ b/src/c/weaver/weave/CMakeLists.txt @@ -15,8 +15,20 @@ set_target_properties(WeavePass PROPERTIES find_library(JANSSON_LIB jansson) target_link_libraries(WeavePass perfflow_parser_static "${JANSSON_LIB}") +add_library(WeavePassPlugin INTERFACE) +target_compile_options(WeavePassPlugin INTERFACE + "SHELL:$>$>" +) + +install(TARGETS WeavePassPlugin + EXPORT perfflow_export + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + install(TARGETS WeavePass - EXPORT WeavePass + EXPORT perfflow_export LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/c/weaver/weave/perfflow_weave.cpp b/src/c/weaver/weave/perfflow_weave.cpp index d2c9b929..edae7b2b 100644 --- a/src/c/weaver/weave/perfflow_weave.cpp +++ b/src/c/weaver/weave/perfflow_weave.cpp @@ -32,10 +32,12 @@ using namespace llvm; ******************************************************************************/ bool WeavingPass::insertAfter(Module &m, Function &f, StringRef &a, - int async, std::string &scope, std::string &flow) + int async, std::string &scope, std::string &flow, std::string pcut) { if (m.empty() || f.empty()) + { return false; + } auto &context = m.getContext(); Type *voidType = Type::getVoidTy(context); @@ -47,6 +49,7 @@ bool WeavingPass::insertAfter(Module &m, Function &f, StringRef &a, params.push_back(int8PtrType); params.push_back(int8PtrType); params.push_back(int8PtrType); + params.push_back(int8PtrType); // voidType is return type, parms are parameters and no variable length args FunctionType *weaveFuncTy = FunctionType::get(voidType, params, false); @@ -67,12 +70,14 @@ bool WeavingPass::insertAfter(Module &m, Function &f, StringRef &a, Value *v2 = builder.CreateGlobalStringPtr(f.getName(), "str"); Value *v3 = builder.CreateGlobalStringPtr(StringRef(scope), "str"); Value *v4 = builder.CreateGlobalStringPtr(StringRef(flow), "str"); + Value *v5 = builder.CreateGlobalStringPtr(StringRef(pcut), "str"); std::vector args; args.push_back(ConstantInt::get(Type::getInt32Ty(context), async)); args.push_back(v1); args.push_back(v2); args.push_back(v3); args.push_back(v4); + args.push_back(v5); builder.CreateCall(after, args); } } @@ -80,10 +85,12 @@ bool WeavingPass::insertAfter(Module &m, Function &f, StringRef &a, } bool WeavingPass::insertBefore(Module &m, Function &f, StringRef &a, - int async, std::string &scope, std::string &flow) + int async, std::string &scope, std::string &flow, std::string pcut) { if (m.empty() || f.empty()) + { return false; + } auto &context = m.getContext(); Type *voidType = Type::getVoidTy(context); @@ -95,6 +102,7 @@ bool WeavingPass::insertBefore(Module &m, Function &f, StringRef &a, params.push_back(int8PtrType); params.push_back(int8PtrType); params.push_back(int8PtrType); + params.push_back(int8PtrType); // voidType is return type, params are parameters and no variable length args FunctionType *weaveFuncTy = FunctionType::get(voidType, params, false); @@ -109,6 +117,7 @@ bool WeavingPass::insertBefore(Module &m, Function &f, StringRef &a, Value *v2 = builder.CreateGlobalStringPtr(f.getName(), "str"); Value *v3 = builder.CreateGlobalStringPtr(StringRef(scope), "str"); Value *v4 = builder.CreateGlobalStringPtr(StringRef(flow), "str"); + Value *v5 = builder.CreateGlobalStringPtr(StringRef(pcut), "str"); builder.SetInsertPoint(&entry, entry.begin()); std::vector args; args.push_back(ConstantInt::get(Type::getInt32Ty(context), async)); @@ -116,6 +125,7 @@ bool WeavingPass::insertBefore(Module &m, Function &f, StringRef &a, args.push_back(v2); args.push_back(v3); args.push_back(v4); + args.push_back(v5); builder.CreateCall(before, args); return true; @@ -132,7 +142,9 @@ bool WeavingPass::doInitialization(Module &m) { auto annotations = m.getNamedGlobal("llvm.global.annotations"); if (!annotations) + { return false; + } bool changed = false; auto a = cast (annotations->getOperand(0)); @@ -150,29 +162,35 @@ bool WeavingPass::doInitialization(Module &m) { if (pcut == "around" || pcut == "before") changed = insertBefore(m, *fn, - anno, 0, scope, flow) || changed; + anno, 0, scope, flow, pcut) || changed; else if (pcut == "around_async" || pcut == "before_async") + { changed = insertBefore(m, *fn, - anno, 1, scope, flow) || changed; + anno, 1, scope, flow, pcut) || changed; + } if (pcut == "around" || pcut == "after") { if (pcut == "around") { if (flow == "in" || flow == "out") + { flow = "NA"; + } } changed = insertAfter(m, *fn, - anno, 0, scope, flow) || changed; + anno, 0, scope, flow, pcut) || changed; } else if (pcut == "around_async" || pcut == "after_async") { if (pcut == "around") { if (flow == "in" || flow == "out") + { flow = "NA"; + } } changed = insertAfter(m, *fn, - anno, 1, scope, flow) || changed; + anno, 1, scope, flow, pcut) || changed; } } else diff --git a/src/c/weaver/weave/perfflow_weave.hpp b/src/c/weaver/weave/perfflow_weave.hpp index aa11eec4..3db17445 100644 --- a/src/c/weaver/weave/perfflow_weave.hpp +++ b/src/c/weaver/weave/perfflow_weave.hpp @@ -31,9 +31,9 @@ class WeavingPass : public FunctionPass private: bool insertAfter (Module &m, Function &f, StringRef &a, - int async, std::string &scope, std::string &flow); + int async, std::string &scope, std::string &flow, std::string pcut); bool insertBefore (Module &m, Function &f, StringRef &a, - int async, std::string &scope, std::string &flow); + int async, std::string &scope, std::string &flow, std::string pcut); }; } diff --git a/src/python/perfflowaspect/advice_chrome.py b/src/python/perfflowaspect/advice_chrome.py index 805d4a40..18f57dde 100644 --- a/src/python/perfflowaspect/advice_chrome.py +++ b/src/python/perfflowaspect/advice_chrome.py @@ -18,6 +18,7 @@ import logging import functools import hashlib +import psutil from urllib.parse import urlparse from .aspect_base import perfflowaspect @@ -115,6 +116,14 @@ def set_perfflow_instance_path(path): os.environ["PERFFLOW_INSTANCE_PATH"] = path +def set_metrics_var(value): + os.environ["CPU_MEM_USAGE"] = value + + +def get_metrics_var(): + return os.getenv("CPU_MEM_USAGE") + + @perfflowaspect class ChromeTracingAdvice: """Chrome Tracing Advice Class: define pointcuts for this advice""" @@ -139,6 +148,14 @@ class ChromeTracingAdvice: inst_path = get_perfflow_instance_path() set_perfflow_instance_path(inst_path) + metrics_var = get_metrics_var() + if metrics_var is None: + set_metrics_var("False") + if metrics_var in ["True", "true", "TRUE"]: + metrics_var = True + elif metrics_var in ["False", "false", "FALSE"]: + metrics_var = False + fn = "perfflow" for inc in perfflow_options["log-filename-include"].split(","): if inc == "name": @@ -274,8 +291,36 @@ def trace(*args, **kwargs): event = ChromeTracingAdvice.__create_event_from_func(func) event["ph"] = "B" ChromeTracingAdvice.__flush_log(json.dumps(event) + ",") + + if ChromeTracingAdvice.metrics_var: + p = psutil.Process(os.getpid()) + cpu_start = p.cpu_times() + cpu_start = cpu_start[0] + mem_before = p.memory_info().rss + time_start = time.time() + rc = func(*args, **kwargs) + + if ChromeTracingAdvice.metrics_var: + time_end = time.time() - time_start + cpu_end = p.cpu_times() + cpu_end = cpu_end[0] + cpu_end = cpu_end - cpu_start + cpu_usage = (cpu_end / time_end) * 100 + mem_usage = p.memory_info().rss + if mem_usage > 0: + mem_usage = mem_usage / 1000 + event["ph"] = "C" + event["args"] = {"cpu_usage": cpu_usage, "memory_usage": mem_usage} + ChromeTracingAdvice.__flush_log(json.dumps(event) + ",") + event["ts"] = time.time() * 1000000 + + if ChromeTracingAdvice.metrics_var: + event["args"] = {"cpu_usage": 0, "memory_usage": 0} + ChromeTracingAdvice.__flush_log(json.dumps(event) + ",") + del event["args"] + event["ph"] = "E" ChromeTracingAdvice.__flush_log(json.dumps(event) + ",") return rc @@ -332,8 +377,8 @@ def trace(*args, **kwargs): event["id"] = 8192 event["ph"] = "b" counter = counter + 1 - counter_mutex.release() ChromeTracingAdvice.__flush_log(json.dumps(event) + ",") + counter_mutex.release() rc = func(*args, **kwargs) event["ts"] = time.time() * 1000000 event["ph"] = "e" diff --git a/src/python/requirements.txt b/src/python/requirements.txt new file mode 100644 index 00000000..a4d92cc0 --- /dev/null +++ b/src/python/requirements.txt @@ -0,0 +1 @@ +psutil diff --git a/src/python/setup.py b/src/python/setup.py index 6d8fed9a..815ba256 100644 --- a/src/python/setup.py +++ b/src/python/setup.py @@ -34,7 +34,7 @@ def load_readme(): author_email="ahn1@llnl.gov, herbein1@llnl.gov, corbett8@llnl.gov, dinatale3@llnl.gov", packages=["perfflowaspect"], entry_points={}, - install_requires=[], + install_requires=["psutil"], extras_require={}, long_description=load_readme(), long_description_content_type="text/markdown", diff --git a/src/python/test/smoketest2.py b/src/python/test/smoketest2.py new file mode 100644 index 00000000..0a794dbf --- /dev/null +++ b/src/python/test/smoketest2.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +import perfflowaspect +import perfflowaspect.aspect + + +@perfflowaspect.aspect.critical_path(pointcut="around") +def bas(): + print("bas") + + +@perfflowaspect.aspect.critical_path(pointcut="around") +def bar(): + print("bar") + bas() + + +@perfflowaspect.aspect.critical_path() +def foo(msg): + print("foo") + temp = 0 + temp1 = [25] * 10000 + temp2 = [22] * 10000 + temp3 = [0] * 10000 + for i in range(10000): + temp = temp + 1 + temp3[i] = temp1[i] * temp2[i] + for j in range(i + 1, 10000): + temp3[j] = temp3[j] / 3 + bar() + if msg == "hello": + return 1 + return 0 + + +def main(): + print("Inside main") + foo("hello") + return 0 + + +if __name__ == "__main__": + main()