From f8f6757d14d4bc1c9f0bd5e4b25644e4d0039615 Mon Sep 17 00:00:00 2001 From: Alexey Cheptsov Date: Wed, 31 May 2017 11:24:13 +0200 Subject: [PATCH] Clone from the orginal location --- Client/.gitignore | 14 + Client/Makefile | 164 +++++ Client/README.md | 145 ++++ Client/ext/CuTest/AllTests.c | 46 ++ Client/ext/CuTest/CuTest.c | 362 ++++++++++ Client/ext/CuTest/CuTest.h | 139 ++++ Client/ext/CuTest/LICENSE | 20 + Client/ext/queue/excess_concurrent_queue.cpp | 65 ++ Client/ext/queue/excess_concurrent_queue.h | 49 ++ Client/scripts/demo_a.sh | 98 +++ Client/scripts/demo_b.sh | 46 ++ Client/scripts/start.sh | 69 ++ Client/scripts/stop.sh | 23 + Client/setup.sh | 243 +++++++ Client/src/agent/main.c | 286 ++++++++ Client/src/agent/main.h | 24 + Client/src/agent/plugin_discover.c | 173 +++++ Client/src/agent/plugin_discover.h | 42 ++ Client/src/agent/plugin_manager.c | 66 ++ Client/src/agent/plugin_manager.h | 66 ++ Client/src/agent/thread_handler.c | 236 +++++++ Client/src/agent/thread_handler.h | 9 + Client/src/api/Makefile | 41 ++ Client/src/api/README.md | 87 +++ Client/src/api/app_alexy/Elements.h | 277 ++++++++ Client/src/api/app_alexy/Makefile | 31 + Client/src/api/app_alexy/Solver.h | 93 +++ .../app_alexy/Ventilation_2D_compbased.cpp | 289 ++++++++ Client/src/api/app_alexy/setenv.sh | 3 + Client/src/api/src/disk_monitor.c | 81 +++ Client/src/api/src/disk_monitor.h | 17 + Client/src/api/src/mf_api.c | 296 +++++++++ Client/src/api/src/mf_api.h | 41 ++ Client/src/api/src/power_monitor.c | 319 +++++++++ Client/src/api/src/power_monitor.h | 58 ++ Client/src/api/src/resources_monitor.c | 150 +++++ Client/src/api/src/resources_monitor.h | 21 + Client/src/api/test/Makefile | 34 + Client/src/api/test/setenv.sh | 3 + Client/src/api/test/test_mf_api.c | 374 +++++++++++ Client/src/core/mf_debug.h | 67 ++ Client/src/mf_config.ini | 73 ++ Client/src/parser/Makefile | 40 ++ Client/src/parser/libs/ini/LICENSE | 26 + Client/src/parser/libs/ini/ini.c | 181 +++++ Client/src/parser/libs/ini/ini.h | 77 +++ Client/src/parser/src/mf_parser.c | 176 +++++ Client/src/parser/src/mf_parser.h | 85 +++ Client/src/plugins/Board_power/Makefile | 52 ++ Client/src/plugins/Board_power/setenv.sh | 3 + .../src/mf_Board_power_connector.c | 401 +++++++++++ .../src/mf_Board_power_connector.h | 50 ++ .../Board_power/src/mf_plugin_Board_power.c | 98 +++ .../src/utils/mf_Board_power_client.c | 95 +++ Client/src/plugins/CPU_perf/Makefile | 52 ++ Client/src/plugins/CPU_perf/setenv.sh | 3 + .../CPU_perf/src/mf_CPU_perf_connector.c | 272 ++++++++ .../CPU_perf/src/mf_CPU_perf_connector.h | 50 ++ .../plugins/CPU_perf/src/mf_plugin_CPU_perf.c | 101 +++ .../CPU_perf/src/utils/mf_CPU_perf_client.c | 96 +++ Client/src/plugins/CPU_temperature/Makefile | 52 ++ Client/src/plugins/CPU_temperature/setenv.sh | 3 + .../src/mf_CPU_temperature_connector.c | 205 ++++++ .../src/mf_CPU_temperature_connector.h | 50 ++ .../src/mf_plugin_CPU_temperature.c | 96 +++ .../src/utils/mf_CPU_temperature_client.c | 95 +++ Client/src/plugins/Linux_resources/Makefile | 48 ++ .../src/mf_Linux_resources_connector.c | 466 +++++++++++++ .../src/mf_Linux_resources_connector.h | 44 ++ .../src/mf_plugin_Linux_resources.c | 92 +++ .../src/utils/mf_Linux_resources_client.c | 94 +++ Client/src/plugins/Linux_sys_power/Makefile | 56 ++ .../src/mf_Linux_sys_power_connector.c | 627 ++++++++++++++++++ .../src/mf_Linux_sys_power_connector.h | 44 ++ .../src/mf_plugin_Linux_sys_power.c | 93 +++ .../src/utils/mf_Linux_sys_power_client.c | 95 +++ Client/src/plugins/NVML/Makefile | 62 ++ .../src/plugins/NVML/src/mf_NVML_connector.c | 259 ++++++++ .../src/plugins/NVML/src/mf_NVML_connector.h | 50 ++ Client/src/plugins/NVML/src/mf_plugin_NVML.c | 92 +++ .../plugins/NVML/src/utils/mf_NVML_client.c | 95 +++ Client/src/plugins/RAPL_power/Makefile | 56 ++ Client/src/plugins/RAPL_power/setenv.sh | 3 + .../RAPL_power/src/mf_RAPL_power_connector.c | 315 +++++++++ .../RAPL_power/src/mf_RAPL_power_connector.h | 44 ++ .../RAPL_power/src/mf_plugin_RAPL_power.c | 92 +++ .../src/utils/mf_RAPL_power_client.c | 95 +++ Client/src/plugins/README.md | 305 +++++++++ Client/src/plugins/utils/plugin_utils.h | 35 + Client/src/publisher/Makefile | 35 + Client/src/publisher/src/publisher.c | 295 ++++++++ Client/src/publisher/src/publisher.h | 32 + Server/.gitignore | 3 + Server/CHANGES | 6 + Server/LICENSE | 202 ++++++ Server/README.md | 180 +++++ Server/VERSION | 1 + Server/app.js | 84 +++ Server/bin/www | 139 ++++ Server/elasticsearch.yml | 96 +++ Server/package.json | 29 + Server/routes/v1/apidoc.json | 24 + Server/routes/v1/configs.js | 243 +++++++ Server/routes/v1/experiments.js | 249 +++++++ Server/routes/v1/index.js | 15 + Server/routes/v1/metrics.js | 483 ++++++++++++++ Server/routes/v1/profiles.js | 389 +++++++++++ Server/routes/v1/resources.js | 234 +++++++ Server/routes/v1/runtime.js | 290 ++++++++ Server/routes/v1/statistics.js | 495 ++++++++++++++ Server/routes/v1/workflows.js | 244 +++++++ Server/setup.sh | 101 +++ Server/start.sh | 71 ++ Server/stop.sh | 54 ++ Server/views/error.jade | 6 + Server/views/layout.jade | 3 + 116 files changed, 14264 insertions(+) create mode 100644 Client/.gitignore create mode 100644 Client/Makefile create mode 100644 Client/README.md create mode 100644 Client/ext/CuTest/AllTests.c create mode 100644 Client/ext/CuTest/CuTest.c create mode 100644 Client/ext/CuTest/CuTest.h create mode 100644 Client/ext/CuTest/LICENSE create mode 100644 Client/ext/queue/excess_concurrent_queue.cpp create mode 100644 Client/ext/queue/excess_concurrent_queue.h create mode 100755 Client/scripts/demo_a.sh create mode 100755 Client/scripts/demo_b.sh create mode 100755 Client/scripts/start.sh create mode 100755 Client/scripts/stop.sh create mode 100755 Client/setup.sh create mode 100644 Client/src/agent/main.c create mode 100644 Client/src/agent/main.h create mode 100644 Client/src/agent/plugin_discover.c create mode 100644 Client/src/agent/plugin_discover.h create mode 100644 Client/src/agent/plugin_manager.c create mode 100644 Client/src/agent/plugin_manager.h create mode 100644 Client/src/agent/thread_handler.c create mode 100644 Client/src/agent/thread_handler.h create mode 100644 Client/src/api/Makefile create mode 100644 Client/src/api/README.md create mode 100644 Client/src/api/app_alexy/Elements.h create mode 100644 Client/src/api/app_alexy/Makefile create mode 100644 Client/src/api/app_alexy/Solver.h create mode 100644 Client/src/api/app_alexy/Ventilation_2D_compbased.cpp create mode 100644 Client/src/api/app_alexy/setenv.sh create mode 100644 Client/src/api/src/disk_monitor.c create mode 100644 Client/src/api/src/disk_monitor.h create mode 100644 Client/src/api/src/mf_api.c create mode 100644 Client/src/api/src/mf_api.h create mode 100644 Client/src/api/src/power_monitor.c create mode 100644 Client/src/api/src/power_monitor.h create mode 100644 Client/src/api/src/resources_monitor.c create mode 100644 Client/src/api/src/resources_monitor.h create mode 100644 Client/src/api/test/Makefile create mode 100644 Client/src/api/test/setenv.sh create mode 100644 Client/src/api/test/test_mf_api.c create mode 100644 Client/src/core/mf_debug.h create mode 100644 Client/src/mf_config.ini create mode 100644 Client/src/parser/Makefile create mode 100644 Client/src/parser/libs/ini/LICENSE create mode 100644 Client/src/parser/libs/ini/ini.c create mode 100644 Client/src/parser/libs/ini/ini.h create mode 100644 Client/src/parser/src/mf_parser.c create mode 100644 Client/src/parser/src/mf_parser.h create mode 100644 Client/src/plugins/Board_power/Makefile create mode 100755 Client/src/plugins/Board_power/setenv.sh create mode 100644 Client/src/plugins/Board_power/src/mf_Board_power_connector.c create mode 100644 Client/src/plugins/Board_power/src/mf_Board_power_connector.h create mode 100644 Client/src/plugins/Board_power/src/mf_plugin_Board_power.c create mode 100644 Client/src/plugins/Board_power/src/utils/mf_Board_power_client.c create mode 100644 Client/src/plugins/CPU_perf/Makefile create mode 100644 Client/src/plugins/CPU_perf/setenv.sh create mode 100644 Client/src/plugins/CPU_perf/src/mf_CPU_perf_connector.c create mode 100644 Client/src/plugins/CPU_perf/src/mf_CPU_perf_connector.h create mode 100644 Client/src/plugins/CPU_perf/src/mf_plugin_CPU_perf.c create mode 100644 Client/src/plugins/CPU_perf/src/utils/mf_CPU_perf_client.c create mode 100644 Client/src/plugins/CPU_temperature/Makefile create mode 100644 Client/src/plugins/CPU_temperature/setenv.sh create mode 100644 Client/src/plugins/CPU_temperature/src/mf_CPU_temperature_connector.c create mode 100644 Client/src/plugins/CPU_temperature/src/mf_CPU_temperature_connector.h create mode 100644 Client/src/plugins/CPU_temperature/src/mf_plugin_CPU_temperature.c create mode 100644 Client/src/plugins/CPU_temperature/src/utils/mf_CPU_temperature_client.c create mode 100644 Client/src/plugins/Linux_resources/Makefile create mode 100644 Client/src/plugins/Linux_resources/src/mf_Linux_resources_connector.c create mode 100644 Client/src/plugins/Linux_resources/src/mf_Linux_resources_connector.h create mode 100644 Client/src/plugins/Linux_resources/src/mf_plugin_Linux_resources.c create mode 100644 Client/src/plugins/Linux_resources/src/utils/mf_Linux_resources_client.c create mode 100644 Client/src/plugins/Linux_sys_power/Makefile create mode 100644 Client/src/plugins/Linux_sys_power/src/mf_Linux_sys_power_connector.c create mode 100644 Client/src/plugins/Linux_sys_power/src/mf_Linux_sys_power_connector.h create mode 100644 Client/src/plugins/Linux_sys_power/src/mf_plugin_Linux_sys_power.c create mode 100644 Client/src/plugins/Linux_sys_power/src/utils/mf_Linux_sys_power_client.c create mode 100644 Client/src/plugins/NVML/Makefile create mode 100644 Client/src/plugins/NVML/src/mf_NVML_connector.c create mode 100644 Client/src/plugins/NVML/src/mf_NVML_connector.h create mode 100644 Client/src/plugins/NVML/src/mf_plugin_NVML.c create mode 100644 Client/src/plugins/NVML/src/utils/mf_NVML_client.c create mode 100644 Client/src/plugins/RAPL_power/Makefile create mode 100644 Client/src/plugins/RAPL_power/setenv.sh create mode 100644 Client/src/plugins/RAPL_power/src/mf_RAPL_power_connector.c create mode 100644 Client/src/plugins/RAPL_power/src/mf_RAPL_power_connector.h create mode 100644 Client/src/plugins/RAPL_power/src/mf_plugin_RAPL_power.c create mode 100644 Client/src/plugins/RAPL_power/src/utils/mf_RAPL_power_client.c create mode 100644 Client/src/plugins/README.md create mode 100644 Client/src/plugins/utils/plugin_utils.h create mode 100644 Client/src/publisher/Makefile create mode 100644 Client/src/publisher/src/publisher.c create mode 100644 Client/src/publisher/src/publisher.h create mode 100644 Server/.gitignore create mode 100644 Server/CHANGES create mode 100644 Server/LICENSE create mode 100644 Server/README.md create mode 100644 Server/VERSION create mode 100644 Server/app.js create mode 100755 Server/bin/www create mode 100644 Server/elasticsearch.yml create mode 100644 Server/package.json create mode 100644 Server/routes/v1/apidoc.json create mode 100644 Server/routes/v1/configs.js create mode 100644 Server/routes/v1/experiments.js create mode 100644 Server/routes/v1/index.js create mode 100644 Server/routes/v1/metrics.js create mode 100644 Server/routes/v1/profiles.js create mode 100644 Server/routes/v1/resources.js create mode 100644 Server/routes/v1/runtime.js create mode 100644 Server/routes/v1/statistics.js create mode 100644 Server/routes/v1/workflows.js create mode 100755 Server/setup.sh create mode 100755 Server/start.sh create mode 100755 Server/stop.sh create mode 100644 Server/views/error.jade create mode 100644 Server/views/layout.jade diff --git a/Client/.gitignore b/Client/.gitignore new file mode 100644 index 0000000..f4ab48f --- /dev/null +++ b/Client/.gitignore @@ -0,0 +1,14 @@ +bin +build +dist +ext/queue/data-structures-library + +**.so +**.o +**.a +**.tar.gz* +*.pid +*.log +*.swp +**mf_*_client +main \ No newline at end of file diff --git a/Client/Makefile b/Client/Makefile new file mode 100644 index 0000000..c55d4ff --- /dev/null +++ b/Client/Makefile @@ -0,0 +1,164 @@ +## Copyright 2014-2017 University of Stuttgart + +CC = gcc +CXX = g++ + +# +# compile and link flags +# +COPT_SO = ${CFLAGS} -fpic + +CFLAGS = -std=gnu99 -pedantic -Wall -Wwrite-strings -Wpointer-arith \ +-Wcast-align -O0 -ggdb -pthread -D_LARGEFILE64_SOURCE \ +$(CURL_INC) \ +$(PAPI_INC) \ +$(APR_INC) \ +$(PARSER_INC) \ +$(PUBLISHER_INC) \ +$(CORE_INC) \ +$(EXCESS_QUEUE) \ +$(EXCESS_QUEUE_C) + +LFLAGS = -lm $(CURL) $(PAPI) $(APR) $(PARSER) $(PUBLISHER) + +# +# DEBUG SWITCH +# +DEBUG ?= 0 +ifeq ($(DEBUG), 1) + CFLAGS += -DDEBUG -g +else + CFLAGS += -DNDEBUG +endif + +# +# includes and libs +# +PWD = ${CURDIR} + +CURL = -L$(PWD)/bin/curl/lib/ -lcurl +CURL_INC = -I$(PWD)/bin/curl/include + +PAPI = -L$(PWD)/bin/papi/lib/ -lpapi +PAPI_INC = -I$(PWD)/bin/papi/include + +APR_CONFIG = $(PWD)/bin/apr/bin/apr-1-config +APU_CONFIG = $(PWD)/bin/apr/bin/apu-1-config +APR = $(shell $(APR_CONFIG) --link-ld) $(shell $(APU_CONFIG) --link-ld) +APR_INC = $(shell $(APR_CONFIG) --includes) $(shell $(APR_CONFIG) --includes) + +PARSER = -L$(PWD)/src/parser/ -lparser +PARSER_INC = -I$(PWD)/src/parser/src + +PUBLISHER = -L$(PWD)/src/publisher/ -lpublisher +PUBLISHER_INC = -I$(PWD)/src/publisher/src + +CORE_INC = -I$(PWD)/src/core + +EXCESS_QUEUE = -I$(PWD)/ext/queue/data-structures-library/src/include +EXCESS_QUEUE_C = -I$(PWD)/ext/queue + +# +# main source files +# +SRC = $(PWD)/src/agent +FILES = $(shell find $(SRC) -name "*.c") +HEADER = $(shell find $(SRC) -name "*.h") +PLUGIN_DIR = $(PWD)/src/plugins + +# +# build and install paths +# +INSTALL_DIR = $(PWD)/dist +INSTALL_BIN_DIR = $(INSTALL_DIR)/bin +INSTALL_PLUGINS_DIR = $(INSTALL_DIR)/bin/plugins +INSTALL_LIB_DIR = $(INSTALL_DIR)/lib + +# +# compile and build +# +all: prepare mf_api main plugins lib + +${SRC}/%.o: %.c ${HEADER} + $(CC) -c $< $(COPT_SO) + +excess_concurrent_queue.o: + $(CXX) -c $(PWD)/ext/queue/excess_concurrent_queue.cpp -o $@ -I. $(EXCESS_QUEUE) $(EXCESS_QUEUE_C) -fpic + +prepare: + $(MAKE) -C $(PWD)/src/parser DEBUG=$(DEBUG) + $(MAKE) -C $(PWD)/src/publisher DEBUG=$(DEBUG) +mf_api: + $(MAKE) -C $(PWD)/src/api DEBUG=$(DEBUG) + $(MAKE) -C $(PWD)/src/api/test DEBUG=$(DEBUG) + +main: excess_concurrent_queue.o $(SRC)/main.o $(SRC)/thread_handler.o $(SRC)/plugin_discover.o $(SRC)/plugin_manager.o + $(CXX) -o $@ $^ -lrt -ldl -Wl,--export-dynamic $(CFLAGS) $(LFLAGS) + +plugins: + $(MAKE) -C $(PLUGIN_DIR)/Board_power DEBUG=$(DEBUG) + $(MAKE) -C $(PLUGIN_DIR)/CPU_perf DEBUG=$(DEBUG) + $(MAKE) -C $(PLUGIN_DIR)/CPU_temperature DEBUG=$(DEBUG) + $(MAKE) -C $(PLUGIN_DIR)/Linux_resources DEBUG=$(DEBUG) + $(MAKE) -C $(PLUGIN_DIR)/Linux_sys_power DEBUG=$(DEBUG) + $(MAKE) -C $(PLUGIN_DIR)/NVML DEBUG=$(DEBUG) + +lib: + +# +# clean-up +# +clean-all: clean clean-install + +clean: + rm -rf *.o *.a *.so $(SRC)/*.o + rm -rf $(PWD)/ext/queue/*.o + rm -f $(PWD)/main + $(MAKE) -C $(PWD)/src/parser clean + $(MAKE) -C $(PWD)/src/publisher clean + $(MAKE) -C $(PWD)/src/api clean + $(MAKE) -C $(PWD)/src/api/test clean + $(MAKE) -C $(PLUGIN_DIR)/Board_power clean + $(MAKE) -C $(PLUGIN_DIR)/CPU_perf clean + $(MAKE) -C $(PLUGIN_DIR)/CPU_temperature clean + $(MAKE) -C $(PLUGIN_DIR)/Linux_resources clean + $(MAKE) -C $(PLUGIN_DIR)/Linux_sys_power clean + $(MAKE) -C $(PLUGIN_DIR)/NVML clean + +clean-install: + rm -rf $(INSTALL_DIR) + +# +# install +# +install: clean-install prepare-install copy_ini copy_plugins copy_client copy_libs + +prepare-install: + @mkdir -p $(INSTALL_BIN_DIR) + @mkdir -p $(INSTALL_PLUGINS_DIR) + @mkdir -p $(INSTALL_LIB_DIR) + +copy_ini: + cp -f $(PWD)/src/mf_config.ini $(INSTALL_DIR) + +copy_plugins: + cp -f $(PLUGIN_DIR)/Board_power/lib/*.so $(INSTALL_PLUGINS_DIR)/ + cp -f $(PLUGIN_DIR)/CPU_perf/lib/*.so $(INSTALL_PLUGINS_DIR)/ + cp -f $(PLUGIN_DIR)/CPU_temperature/lib/*.so $(INSTALL_PLUGINS_DIR)/ + cp -f $(PLUGIN_DIR)/Linux_resources/lib/*.so $(INSTALL_PLUGINS_DIR)/ + cp -f $(PLUGIN_DIR)/Linux_sys_power/lib/*.so $(INSTALL_PLUGINS_DIR)/ + cp -f $(PLUGIN_DIR)/NVML/lib/*.so $(INSTALL_PLUGINS_DIR)/ 2>/dev/null || : + +copy_client: + cp -f $(PWD)/main $(INSTALL_BIN_DIR)/mf_client + +copy_libs: + cp -f $(PWD)/bin/apr/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/bin/curl/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/bin/hwloc/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/bin/libiio/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/bin/papi/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/bin/sensors/lib/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/src/parser/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/src/publisher/lib*.so* $(INSTALL_LIB_DIR) + cp -f $(PWD)/src/api/lib*.so* $(INSTALL_LIB_DIR) diff --git a/Client/README.md b/Client/README.md new file mode 100644 index 0000000..1971233 --- /dev/null +++ b/Client/README.md @@ -0,0 +1,145 @@ +# PHANTOM monitoring client + +> PHANTOM monitoring client is one part of the PHANTOM monitoring framework, which supports metrics collection based on hardware availabilities and platform configuration. The target platform of the monitoring client includes CPUs, GPUs, Myriad2, ACME power measurement kit and FPGA-based platform. + + +## Introduction +The essential functionality of PHANTOM monitoring client is metrics collection, which is implemented by various plug-ins according to the hardware accessibility. + +Currently 7 plug-ins are supported, whose implementation and design details are collected in the directory `src/plugins`. The monitoring client is designed to be pluggable. Loading a plug-in means starting a thread for the specific plug-in based on the users’ configuration at run-time. The folder `src/agent` plays a role as the main control unit, as managing various plug-ins with the help of pthreads. Folders like `src/core`, `src/parser`, and `src/publisher` are used by the main controller for accessorial support, including parsing input configuration file (`src/mf_config.ini`), publishing metrics via HTTP, and so on. + +For code instrumentation and user-defined metrics collection, we provide a monitoring library and several APIs, which are kept in the directory `src/api`. Descriptions in detail about how to use the monitoring APIs are given also in this directory. + + +## Prerequisites +The monitoring client requires at first a running server and database. In order to install these requirements, please +checkout the associated [PHANTOM monitoring server][server] and follow the setup instructions given in the repository `README.md` file. A successful setup process can be checked by the following command as testing whether the server is running in the specific url: +```bash +curl localhost:3033 +``` + +Please note that the installation and setup steps mentioned below assume that you are running a current Linux as operating system. We have tested the monitoring agent with Ubuntu 14.04 LTS as well as with Scientific Linux 6 (Carbon). + +Before you can proceed, please clone the repository: +```bash +git clone https://github.com/hpcfapix/phantom_monitoring_client.git +``` + + +### Dependencies +This project requires the following dependencies to be installed: + +| Component | Homepage | Version | +|------------------ |------------------------------------------------- |--------- | +| PAPI-C | http://icl.cs.utk.edu/papi/ | 5.4.0 | +| CURL | http://curl.haxx.se/download/ | 7.37.0 | +| Apache APR | https://apr.apache.org/ | 1.5.1 | +| Apache APR Utils | https://apr.apache.org/ | 1.5.3 | +| Nvidia GDK | https://developer.nvidia.com/gpu-deployment-kit/ | 352.55 | +| bison | http://ftp.gnu.org/gnu/bison/ | 2.3 | +| flex | http://prdownloads.sourceforge.net/flex/ | 2.5.33 | +| sensors | https://fossies.org/linux/misc/ | 3.4.0 | +| m4 | https://ftp.gnu.org/gnu/m4 | 1.4.17 | +| libiio | https://github.com/analogdevicesinc/libiio.git | 1.0 | +| hwloc | https://www.open-mpi.org/software/hwloc/v1.11/downloads/ | 1.11.2 | +| EXCESS queue | https://github.com/excess-project/data-structures-library.git | release/0.1.0 | + +To ease the process of setting up a development environment, we provide a basic script that downloads all dependencies, installs them locally in the project directory, and then performs some clean-up operations. Thus, compiling the monitoring client can be performed in a sandbox without affecting your current operating system. + +Executing the following script +```bash +./setup.sh +``` +results in a new directory named `bin`, which holds the required dependencies for compiling the project. + + +## Installation +This section assumes that you've successfully installed all required dependencies as described in the previous paragraphs. + +```bash +make clean-all +make all +make install +``` + +The above commands clean, compile and install the monitoring agent into the directory `dist` within the project's repository. The `dist` folder includes all required binaries, shared libraries, scripts, and configuration files to get you started. The Makefile has been tested with GNU compiler version 4.9.2. + + +## Start monitoring +If you haven't yet followed our guide to set up the associated monitoring server and database, please do so now before continuing. Next, start the monitoring client with a default set of plugins enabled to monitor as follows: +```bash +cd scripts +./start.sh +``` + +You can learn more about various options passed to the monitoring client by calling +```bash +./start.sh -h +``` + +While the monitoring client is started and is collecting metric data, you can use the RESTful APIs provided by the monitoring server to retrieve run-time metrics and corresponding statistics. + + +## Configuring plug-ins and update intervals +The monitoring client as well as plug-ins are configurable at run-time by a global configuration file named `mf_config.ini`. The configuration is implemented by using an INI file; each section name such as `timings` or `plugins` is enclosed by square brackets. For each section, various parameters can be set. These parameters are custom-defined for each plug-in. +```bash +;PHANTOM Monitoring Client Configuration + +[generic] +server = http://localhost:3033/v1 +... + +[plugins] +mf_plugin_Board_power = on +mf_plugin_CPU_perf = off +... + +[timings] +default = 1000000000ns +update_configuration = 360s +mf_plugin_Board_power = 1000000000ns +... + +[mf_plugin_Board_power] +ACME_BOARD_NAME = baylibre-acme.local +device0:current = on +device0:vshunt = off +device0:vbus = off +device0:power = on +... + +``` + +Several parameters such as the `timing` of the plug-ins or the `server` where the server is running can be configured through this configuration file. The file is called `mf_config.ini` and is located at `dist/mf_config.ini`. + + +## Acknowledgment +This project is realized through [EXCESS][excess] and [PHANTOM][phantom]. EXCESS is funded by the EU 7th Framework Programme (FP7/2013-2016) under grant agreement number 611183. The PHANTOM project receives funding under the European Union's Horizon 2020 Research and Innovation Programme under grant agreement number 688146. + + +## Contributing +Find a bug? Have a feature request? +Please [create](https://github.com/excess-project/monitoring-agent/website/issues) an issue. + + +## Main Contributors +**Fangli Pi, HLRS** ++ [github/hpcfapix](https://github.com/hpcfapix) + + +## Release History + +| Date | Version | Comment | +| ----------- | ------- | ---------------- | +| 2017-04-04 | 1.0 | First prototype | + + +## License +Copyright (C) 2014,2015 University of Stuttgart + +[Apache License v2](LICENSE). + + +[server]: https://github.com/hpcfapix/phantom_monitoring_server +[excess]: http://www.excess-project.eu +[phantom]: http://www.phantom-project.org \ No newline at end of file diff --git a/Client/ext/CuTest/AllTests.c b/Client/ext/CuTest/AllTests.c new file mode 100644 index 0000000..d555f01 --- /dev/null +++ b/Client/ext/CuTest/AllTests.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2003 Asim Jalis + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +#include + +#include "CuTest.h" + +CuSuite* CuGetSuite(); + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, CuGetSuite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); +} + +int main(void) +{ + RunAllTests(); +} diff --git a/Client/ext/CuTest/CuTest.c b/Client/ext/CuTest/CuTest.c new file mode 100644 index 0000000..8187552 --- /dev/null +++ b/Client/ext/CuTest/CuTest.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2003 Asim Jalis + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + void* expected, void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + free(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/Client/ext/CuTest/CuTest.h b/Client/ext/CuTest/CuTest.h new file mode 100644 index 0000000..731ccfa --- /dev/null +++ b/Client/ext/CuTest/CuTest.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2003 Asim Jalis + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software in + * a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + void* expected, void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/Client/ext/CuTest/LICENSE b/Client/ext/CuTest/LICENSE new file mode 100644 index 0000000..ecc9065 --- /dev/null +++ b/Client/ext/CuTest/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. \ No newline at end of file diff --git a/Client/ext/queue/excess_concurrent_queue.cpp b/Client/ext/queue/excess_concurrent_queue.cpp new file mode 100644 index 0000000..c35454a --- /dev/null +++ b/Client/ext/queue/excess_concurrent_queue.cpp @@ -0,0 +1,65 @@ +// EXCESS data structure framework concurrent queue C adapter +// Anders Gidenstam + +#include + +#include + +// Prepare the types for a queue storing void* pointers. +typedef excess::concurrent_queue concurrent_queue_t; +typedef excess::concurrent_queue::handle handle_t; + +extern "C" { + +EXCESS_concurrent_queue_t ECQ_create(int queue_implementation) +{ + concurrent_queue_t* queue; + + switch (queue_implementation) { + case 7: +#ifdef USE_TBB + // The concurrent_queue from Intel Threading Building Blocks. + queue = new excess::concurrent_queue_TBBQueue(); +#endif + break; + default: + // An implementation of the Michael and Scott two-lock queue. + queue = new excess::concurrent_queue_MSTLB(); + } + return (EXCESS_concurrent_queue_t)queue; +} + +void ECQ_free(EXCESS_concurrent_queue_t queue) +{ + delete (concurrent_queue_t*)queue; +} + +EXCESS_concurrent_queue_handle_t ECQ_get_handle(EXCESS_concurrent_queue_t queue) +{ + return + (EXCESS_concurrent_queue_handle_t)((concurrent_queue_t*)queue)->get_handle(); +} + +void ECQ_free_handle(EXCESS_concurrent_queue_handle_t handle) +{ + delete (handle_t*)handle; +} + +void ECQ_enqueue(EXCESS_concurrent_queue_handle_t handle, + void* item) +{ + ((handle_t*)handle)->enqueue(item); +} + +int ECQ_try_dequeue(EXCESS_concurrent_queue_handle_t handle, + void** item_ptr) +{ + return ((handle_t*)handle)->try_dequeue(*item_ptr); +} + +int ECQ_is_empty(EXCESS_concurrent_queue_handle_t handle) +{ + return ((handle_t*)handle)->empty(); +} + +} diff --git a/Client/ext/queue/excess_concurrent_queue.h b/Client/ext/queue/excess_concurrent_queue.h new file mode 100644 index 0000000..9e01cb4 --- /dev/null +++ b/Client/ext/queue/excess_concurrent_queue.h @@ -0,0 +1,49 @@ +// EXCESS data structure framework concurrent queue C adapter +// Anders Gidenstam +#ifndef EXCESS_CONCURRENT_QUEUE +#define EXCESS_CONCURRENT_QUEUE + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* EXCESS_concurrent_queue_t; +typedef void* EXCESS_concurrent_queue_handle_t; + +/* + * Creates and initializes a queue instance. + * queue_implementation selects the implementation. Currently ignored. + */ +EXCESS_concurrent_queue_t ECQ_create(int queue_implementation); + +/* + * Frees a queue instance. + */ +void ECQ_free(EXCESS_concurrent_queue_t queue); + +/* + * Get a thread local handle to the queue. + */ +EXCESS_concurrent_queue_handle_t ECQ_get_handle(EXCESS_concurrent_queue_t queue); + +/* + * Free a thread local handle to the queue. + */ +void ECQ_free_handle(EXCESS_concurrent_queue_handle_t handle); + +/* + * Enqueue an item in the queue using a thread local handle. + */ +void ECQ_enqueue(EXCESS_concurrent_queue_handle_t handle, + void* item); + +int ECQ_try_dequeue(EXCESS_concurrent_queue_handle_t handle, + void** item_ptr); + +int ECQ_is_empty(EXCESS_concurrent_queue_handle_t handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Client/scripts/demo_a.sh b/Client/scripts/demo_a.sh new file mode 100755 index 0000000..2ade589 --- /dev/null +++ b/Client/scripts/demo_a.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright (C) 2015 University of Stuttgart +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# input parameters +# +APPLICATION_ID="dummy" +TASK_ID="t1" +MF_SERVER="141.58.0.8:3033" +METRIC_NAME="power_total" + +# +# dummy application path and script +# 5: parallel computing +# 4: number of threads is 4 +# +DUMMY_PATH=/nas_home/hpcfapix/hpcfapix/measure/avx +DUMMY_CONFIG=/nas_home/hpcfapix/hpcfapix/measure/config.ini +DUMMY_PARAMS="${DUMMY_CONFIG} 5 4" + +# +# mf_client path and ld_library_path setup +# +BASE_DIR=`pwd`/.. +DIST_DIR=${BASE_DIR}/dist +DIST_BIN_DIR=${DIST_DIR}/bin +LIB_DIR=${DIST_DIR}/lib +LOG_DIR=${DIST_BIN_DIR}/log + +rm ${LOG_DIR} -rf +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${LIB_DIR} + +# +# mf_client parameters +# -a: application_id +# -t: task_id +# +PARAMS=" -a ${APPLICATION_ID} -t ${TASK_ID}" + +# +# start mf_client +# +DATE_1=$(date +"%FT%T.%3N") +echo "Start mf_client at ${DATE_1}" +${DIST_BIN_DIR}/mf_client ${PARAMS} 2>&1& + +# +# run the dummy application +# +sleep 1 +DATE_2=$(date +"%FT%T.%3N") +echo "Start application at ${DATE_2}" + +${DUMMY_PATH} ${DUMMY_PARAMS} > /dev/null 2>&1 + +DATE_3=$(date +"%FT%T.%3N") +echo "Application ends at ${DATE_3}" +sleep 1 + +# +# stop mf_client +# +DATE_4=$(date +"%FT%T.%3N") +echo "Stop mf_client at ${DATE_4}" +PID=`ps -ef| grep -v grep | grep mf_client | awk '{print $2}'` +kill $PID + +# +# wait for the log file is created +# +sleep 30 + +# +# read from logfile the experiment_id +# +EXPERIMENT_ID=`cat ${LOG_DIR}/* | grep experiment_id | awk '{print $6}'` + +echo "Please try the following query for retrieving monitoring data and statistics:" +echo " " +echo "curl -XGET ${MF_SERVER}/v1/mf/profiles/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}" +echo "curl -XGET ${MF_SERVER}/v1/mf/runtime/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}" +echo "curl -XGET ${MF_SERVER}/v1/mf/statistics/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}?metric=${METRIC_NAME}" +echo "curl -XGET '${MF_SERVER}/v1/mf/statistics/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}?metric=${METRIC_NAME}&from=${DATE_2}&to=${DATE_3}'" + +# end diff --git a/Client/scripts/demo_b.sh b/Client/scripts/demo_b.sh new file mode 100755 index 0000000..9f660f3 --- /dev/null +++ b/Client/scripts/demo_b.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Copyright (C) 2015 University of Stuttgart +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# input parameters +# +APPLICATION_ID="dummy" #should be same as given in the application +TASK_ID="t2" #should be same as given in the application +MF_SERVER="141.58.0.8:3033" #should be same as given in the application +METRIC_NAME="CPU_usage_rate" + +# +# start the application with mf api +# +BASE_DIR=`pwd`/.. +TEST_PATH=${BASE_DIR}/src/api/test +LIB_DIR=${BASE_DIR}/dist/lib +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${LIB_DIR} + +${TEST_PATH}/test_mf_api > demo_b_log.txt + +sleep 10 + +# +# get experiment_id +# +EXPERIMENT_ID=`cat demo_b_log.txt | grep experiment_id | awk '{print $3}'` + +echo "Please try the following query for retrieving monitoring data and statistics:" +echo " " +echo "curl -XGET ${MF_SERVER}/v1/mf/profiles/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}" +echo "curl -XGET ${MF_SERVER}/v1/mf/runtime/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}" +echo "curl -XGET ${MF_SERVER}/v1/mf/statistics/${APPLICATION_ID}/${TASK_ID}/${EXPERIMENT_ID}?metric=${METRIC_NAME}" diff --git a/Client/scripts/start.sh b/Client/scripts/start.sh new file mode 100755 index 0000000..4b795ce --- /dev/null +++ b/Client/scripts/start.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# Copyright (C) 2015 University of Stuttgart +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +usage() { + cat < sets a user-defined application ID [optional] +-t sets a user-defined task (component) ID [optional] + +EOF + +} + +BASE_DIR=`pwd`/.. +DIST_DIR=${BASE_DIR}/dist +DIST_BIN_DIR=${DIST_DIR}/bin +LIB_DIR=${DIST_DIR}/lib + +PARAMS='' + +while getopts "a:t:h" opt; do + case $opt in + a) + PARAMS+=" -a ${OPTARG}" + ;; + t) + PARAMS+=" -t ${OPTARG}" + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + exit 1 + ;; + esac +done + +# set environment variables +libs=${LIB_DIR} +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$libs + +# run agent with given parameters +# nohup makes your process running even after you logout +nohup ${DIST_BIN_DIR}/mf_client ${PARAMS} 2>&1& +echo "mf_client started." + +# end diff --git a/Client/scripts/stop.sh b/Client/scripts/stop.sh new file mode 100755 index 0000000..aced0f0 --- /dev/null +++ b/Client/scripts/stop.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright (C) 2015 University of Stuttgart +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +PID=`ps -ef| grep -v grep | grep mf_client | awk '{print $2}'` +kill $PID +rm -f nohup.out +echo "mf_client stopped." + +#end diff --git a/Client/setup.sh b/Client/setup.sh new file mode 100755 index 0000000..9bade51 --- /dev/null +++ b/Client/setup.sh @@ -0,0 +1,243 @@ +#!/bin/bash +# Copyright (C) 2015, 2016 University of Stuttgart +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# ============================================================================ # +# DEFAULT PATHS # +# ============================================================================ # + +ROOT=`pwd` +BINARY_FOLDER="bin" +INSTALL_PATH_HWLOC=`pwd`/${BINARY_FOLDER}/hwloc +INSTALL_PATH_PAPI=`pwd`/${BINARY_FOLDER}/papi +INSTALL_PATH_APR=`pwd`/${BINARY_FOLDER}/apr +INSTALL_PATH_APU=${INSTALL_PATH_APR} +INSTALL_PATH_CURL=`pwd`/${BINARY_FOLDER}/curl +INSTALL_PATH_NVIDIA=`pwd`/${BINARY_FOLDER}/nvidia +INSTALL_PATH_M4=`pwd`/${BINARY_FOLDER}/m4 +INSTALL_PATH_BISON=`pwd`/${BINARY_FOLDER}/bison +INSTALL_PATH_FLEX=`pwd`/${BINARY_FOLDER}/flex +INSTALL_PATH_SENSORS=`pwd`/${BINARY_FOLDER}/sensors +INSTALL_PATH_EXCESS_QUEUE=`pwd`/ext/queue +INSTALL_PATH_LIBIIO=`pwd`/${BINARY_FOLDER}/libiio + +# ============================================================================ # +# VERSIONS OF REQUIRED LIBRARIES # +# ============================================================================ # + +PAPI="papi" +PAPI_VERSION="5.4.0" +CURL="curl" +CURL_VERSION="7.37.0" +APR="apr" +APR_VERSION="1.5.2" +APR_UTIL="apr-util" +APR_UTIL_VERSION="1.5.4" +EXCESS_QUEUE_VERSION=release/0.1.0 + + +# ============================================================================ # +# DOWNLOAD AND INSTALL HWLOC # +# ============================================================================ # + +cd $ROOT +wget https://www.open-mpi.org/software/hwloc/v1.11/downloads/hwloc-1.11.2.tar.gz +tar xf hwloc-1.11.2.tar.gz +cd hwloc-1.11.2 +./configure --prefix=${INSTALL_PATH_HWLOC} +make +make install + +# ============================================================================ # +# DOWNLOAD AND INSTALL PAPI-C # +# ============================================================================ # + +cd $ROOT +wget http://icl.cs.utk.edu/projects/papi/downloads/${PAPI}-${PAPI_VERSION}.tar.gz +if [ ! -f ${PAPI}-${PAPI_VERSION}.tar.gz ]; then + echo "[ERROR] File not found: " ${PAPI}-${PAPI_VERSION}.tar.gz + exit 1; +fi +tar zxvf ${PAPI}-${PAPI_VERSION}.tar.gz +cd ${PAPI}-${PAPI_VERSION}/src +./configure --prefix=${INSTALL_PATH_PAPI} --with-components="rapl coretemp infiniband" +make +make install all + +# ============================================================================ # +# DOWNLOAD AND INSTALL CURL # +# ============================================================================ # + +cd $ROOT +wget http://curl.haxx.se/download/${CURL}-${CURL_VERSION}.tar.gz +if [ ! -f ${CURL}-${CURL_VERSION}.tar.gz ]; then + echo "[ERROR] File not found: " ${CURL}-${CURL_VERSION}.tar.gz + exit 1; +fi +tar zxvf ${CURL}-${CURL_VERSION}.tar.gz +cd ${CURL}-${CURL_VERSION} +./configure --prefix=${INSTALL_PATH_CURL} +make +make install +make install all + +# ============================================================================ # +# DOWNLOAD AND INSTALL APACHE APR # +# ============================================================================ # + +cd $ROOT +wget http://www.eu.apache.org/dist/apr/${APR}-${APR_VERSION}.tar.gz +if [ ! -f ${APR}-${APR_VERSION}.tar.gz ]; then + echo "[ERROR] File not found: " ${APR}-${APR_VERSION}.tar.gz + exit 1; +fi +tar zxvf ${APR}-${APR_VERSION}.tar.gz +cd ${APR}-${APR_VERSION} +./configure --prefix=${INSTALL_PATH_APR} +make +make install +make install all + +# ============================================================================ # +# DOWNLOAD AND INSTALL APACHE APR UTILITIES # +# ============================================================================ # + +cd $ROOT +wget http://www.eu.apache.org/dist//apr/apr-util-1.5.4.tar.gz +if [ ! -f ${APR_UTIL}-${APR_UTIL_VERSION}.tar.gz ]; then + echo "[ERROR] File not found: " ${APR_UTIL}-${APR_UTIL_VERSION}.tar.gz + exit 1; +fi +tar zxvf ${APR_UTIL}-${APR_UTIL_VERSION}.tar.gz +cd ${APR_UTIL}-${APR_UTIL_VERSION} +./configure --prefix=${INSTALL_PATH_APU} --with-apr=${INSTALL_PATH_APR} +make +make install +make install all + +# ============================================================================ # +# DOWNLOAD AND INSTALL NVIDIA GDK # +# ============================================================================ # + +cd $ROOT +mkdir -f nvidia_gdk_download +cd nvidia_gdk_download +NVIDIA_BASE_URL="http://developer.download.nvidia.com" +NVIDIA_GDK="gdk_linux_amd64_352_55_release.run" +wget ${NVIDIA_BASE_URL}/compute/cuda/7.5/Prod/gdk/${NVIDIA_GDK} +if [ ! -f ${NVIDIA_GDK} ]; then + echo "[ERROR] File not found: " ${NVIDIA_GDK} + exit 1; +fi +chmod +x ${NVIDIA_GDK} +./${NVIDIA_GDK} --silent --installdir=${INSTALL_PATH_NVIDIA} + +# ============================================================================ # +# DOWNLOAD AND INSTALL SENSORS LIB # +# https://fossies.org/linux/misc/lm_sensors-3.4.0.tar.gz/lm_sensors-3.4.0/lib/libsensors.3 +# ============================================================================ # +# +# DEPENDENCIES: bison and flex +# + +cd $ROOT +wget https://ftp.gnu.org/gnu/m4/m4-1.4.17.tar.gz +tar zxvf m4-1.4.17.tar.gz +cd m4-1.4.17 +./configure --prefix=${INSTALL_PATH_M4} +make +make install +export PATH=${PATH}:${INSTALL_PATH_M4}/bin + + +cd $ROOT +wget http://ftp.gnu.org/gnu/bison/bison-3.0.2.tar.gz +tar zxvf bison-3.0.2.tar.gz +cd bison-3.0.2 +./configure --prefix=${INSTALL_PATH_BISON} +make +make install + +cd $ROOT +wget http://prdownloads.sourceforge.net/flex/flex-2.6.0.tar.gz +tar zxvf flex-2.6.0.tar.gz +cd flex-2.6.0 +./configure --prefix=${INSTALL_PATH_FLEX} +make +make install + +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${INSTALL_PATH_FLEX}/lib:${INSTALL_PATH_BISON}/lib +export PATH=${PATH}:${INSTALL_PATH_BISON}/bin:${INSTALL_PATH_FLEX}/bin + +cd $ROOT +wget https://fossies.org/linux/misc/lm_sensors-3.4.0.tar.gz +tar zxvf lm_sensors-3.4.0.tar.gz +cd lm_sensors-3.4.0 +make PREFIX=${INSTALL_PATH_SENSORS} all +make PREFIX=${INSTALL_PATH_SENSORS} install + + +# ============================================================================ # +# DOWNLOAD AND INSTALL LIBIIO # +# https://wiki.analog.com/resources/tools-software/linux-software/libiio +# ============================================================================ # +# +# DEPENDENCIES: libxml2 libxml2-dev bison flex libcdk5-dev libavahi-client-dev cmake +# +cd $ROOT +git clone https://github.com/analogdevicesinc/libiio.git +cd libiio +mkdir -f ${INSTALL_PATH_LIBIIO} +cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PATH_LIBIIO} ./ +make all +make install +find ./ -name "libiio.so*" -exec mv {} ${INSTALL_PATH_LIBIIO}/lib/ \; + +# ============================================================================ # +# DOWNLOAD AND INSTALL EXCESS QUEUE LIBS # +# https://github.com/excess-project/data-structures-library.git +# ============================================================================ # +# +cd $INSTALL_PATH_EXCESS_QUEUE +rm -rf data-structures-library +git clone https://github.com/excess-project/data-structures-library.git +cd data-structures-library +git checkout $EXCESS_QUEUE_VERSION + +# ============================================================================ # +# CLEANING UP # +# ============================================================================ # + +cd $ROOT +rm -f *.tar.gz +rm -rf hwloc-1.11.2 +rm -rf ${PAPI}-${PAPI_VERSION} +rm -rf ${LIKWID}-${LIKWID_VERSION} +rm -rf ${APR}-${APR_VERSION} +rm -rf ${APR_UTIL}-${APR_UTIL_VERSION} +rm -rf ${CURL}-${CURL_VERSION} +rm -rf nvidia_gdk_download +rm -rf m4-1.4.17 +rm -rf bison-3.0.2 +rm -rf flex-2.6.0 +rm -rf lm_sensors-3.4.0 +rm -rf ${NVIDIA_GDK} +rm -rf libiio + +# ============================================================================ # +# DONE +# ============================================================================ # + +echo "ALL DEPENDENCIES WERE INSTALLED SUCCESSFULLY!" diff --git a/Client/src/agent/main.c b/Client/src/agent/main.c new file mode 100644 index 0000000..fd8a72a --- /dev/null +++ b/Client/src/agent/main.c @@ -0,0 +1,286 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "thread_handler.h" //functions like startThreads()... +#include "mf_debug.h" //functions like log_error(), log_info()... +#include "mf_parser.h" //functions like mfp_parse()... +#include "publisher.h" //functions like create_new_experiment()... +#include "main.h" + +#define SUCCESS 1 +#define FAILURE 0 + +/******************************************************************************* + * External Variables Declarations + ******************************************************************************/ +char *pwd; +char *confFile; +char *application_id; +char *experiment_id; +char *task_id; +char *platform_id; +char *metrics_publish_URL; +FILE *logFile; //declared in mf_debug.h +char *logFileName; + +/******************************************************************************* + * Variable Declarations + ******************************************************************************/ +char *name; +int pwd_is_set = 0; + +/******************************************************************************* + * Forward Declarations + ******************************************************************************/ +void set_pwd(void); +void createLogFile(void); +int writeTmpPID(void); +int prepare(void); + +/******************************************************************************* + * Functions implementation + ******************************************************************************/ +/* everything starts here */ +int main(int argc, char* argv[]) { + extern char *optarg; + int c; + int err = 0, help = 0; + + /* init arguments */ + pwd = calloc(256, sizeof(char)); + name = calloc(256, sizeof(char)); //name of the tmp pid file + application_id = calloc(128, sizeof(char)); //should be given as input + experiment_id = calloc(128, sizeof(char)); //should be given as input + task_id = calloc(128, sizeof(char)); //should be generated by mf_server + confFile = calloc(256, sizeof(char)); + + /* assigns the current working directory to the variable "pwd" */ + set_pwd(); + + /* create log file, use log_error(), log_info() and log_warn() afterwards */ + createLogFile(); + + /* write PID to a file ("tmp_pid") in `pwd`; can be used to kill the agent */ + if(writeTmpPID() == FAILURE) { + exit(FAILURE); + } + + /* parse command-line arguments */ + while ((c = getopt(argc, argv, "a:t:h")) != -1) + switch (c) { + case 'a': + strcpy(application_id, optarg); + break; + case 't': + strcpy(task_id, optarg); + break; + case 'h': + help = 1; + break; + case '?': + err = 1; + break; + } + + /* print usage */ + if (err || help) { + char usage[256] = {'\0'}; + sprintf(usage, "usage: %s [-a application_id] [-t task_id] [-h help]\n", argv[0]); + log_error("%s", usage); + exit(FAILURE); + } + + /* set the configuration file */ + sprintf(confFile, "%s/%s", pwd, "../mf_config.ini"); + log_info("Configuration taken from: %s.\n", confFile); + + /* try to parse configuration file */ + if (mfp_parse(confFile) == FAILURE) { + /* could not parse configuration file */ + fprintf(logFile, "[ERROR] Stopping service...could not parse configuration.\n"); + exit(FAILURE); + } + + /* prepare metrics_publish_URL and platform_id, based on mf_config.ini; + send a initialization msg to the server and create a new experiment with unique experiment_id*/ + if (prepare() == FAILURE) { + fprintf(logFile, "[ERROR] Stopping service...could not prepare URLs for sending metrics to server.\n"); + exit(FAILURE); + } + + /* start threads for plugins, implementation in thread_handler.c */ + if(startThreads() == FAILURE) { + fprintf(logFile, "[ERROR] Stopping service...could not start the threads.\n"); + exit(FAILURE); + } + + /* monitoring ends */ + fprintf(logFile, "[INFO] Stopping service ...\n"); + fclose(logFile); + + unlink(name); // delete the file which stores the tmp pid + free(pwd); + free(name); + free(application_id); + free(experiment_id); + free(task_id); + free(metrics_publish_URL); + free(platform_id); + free(logFileName); + free(confFile); + + mfp_parse_clean(); + exit(SUCCESS); +} + +/* assigns the current working directory to the variable "pwd" */ +void set_pwd(void) +{ + if (pwd_is_set) { + return; + } + char buf_1[256] = {'\0'}; + char buf_2[256] = {'\0'}; + + readlink("/proc/self/exe", buf_1, 200); + memcpy(buf_2, buf_1, strlen(buf_1) * sizeof(char)); + + /* extract path folder of executable from it's path */ + char *lastslash = strrchr(buf_2, '/'); + int ptr = lastslash - buf_2; + + memcpy(pwd, buf_2, ptr); + pwd_is_set = 1; +} + +/* Initializing and creating the log file */ +void createLogFile(void) +{ + int errnum; + + if (!pwd_is_set) { + set_pwd(); + } + + logFileName = calloc(300, sizeof(char)); //extern variable + char logFileFolder[300] = { '\0' }; + + time_t curTime; + time(&curTime); + struct tm *time_info = localtime(&curTime); + + char timeForFile[50]; + + strftime(timeForFile, 50, "%F-%T", time_info); + sprintf(logFileFolder, "%s/log", pwd); + sprintf(logFileName, "%s/log/log-%s", pwd, timeForFile); + fprintf(stderr, "using logfile: %s\n", logFileName); + + struct stat st = { 0 }; + if (stat(logFileFolder, &st) == -1) + mkdir(logFileFolder, 0700); + logFile = fopen(logFileName, "a"); + if (logFile == NULL) { + errnum = errno; + fprintf(stderr, "Could not create log file: %s\n", logFileName); + fprintf(stderr, "Error creating log: %s\n", strerror(errnum)); + } else { + log_info("Starting service at %s...\n", timeForFile); + } +} + +/* write PID to a file (named as "tmp_pid") in `pwd` */ +int writeTmpPID(void) +{ + if (!pwd_is_set) { + set_pwd(); + } + + strcpy(name, pwd); + strcat(name, "/tmp_pid"); + + int pid = getpid(); + FILE *tmpFile = fopen(name, "w"); + if (tmpFile == NULL) { + log_error("Failed to create file %s to store the PID.\n", name); + return FAILURE; + } else { + fprintf(tmpFile, "%d", pid); + fclose(tmpFile); + } + + return SUCCESS; +} + +/* prepare metrics_publish_URL and platform_id, based on mf_config.ini; + send a initialization msg to the server and create a new experiment with unique experiment_id*/ +int prepare(void) +{ + char server_name[128] = {'\0'}; + metrics_publish_URL = calloc(256, sizeof(char)); + platform_id = calloc(128, sizeof(char)); + + /* get server */ + mfp_get_value("generic", "server", server_name); + /* get metrics send url */ + sprintf(metrics_publish_URL, "%s/phantom_mf/metrics", server_name); + /* get platform_id */ + mfp_get_value("generic", "platform_id", platform_id); + + /* by default, no application_id and task_id is given, + therefore set application_id to infrastructure; task_id to the platform_id */ + if(application_id[0] == '\0' || task_id[0] == '\0') + { + strcpy(application_id, "infrastructure"); + strcpy(task_id, platform_id); + } + + /* create an new experiment by sending msg to mf_server */ + char *msg = calloc(256, sizeof(char)); + char *experiments_URL = calloc(256, sizeof(char)); + + sprintf(msg, "{\"application\":\"%s\", \"task\": \"%s\", \"host\": \"%s\"}", + application_id, task_id, platform_id); + sprintf(experiments_URL, "%s/phantom_mf/experiments/%s", server_name, application_id); + + create_new_experiment(experiments_URL, msg, experiment_id); + if(experiment_id[0] == '\0') { + log_error("Cannot create new experiment for application %s\n", application_id); + return FAILURE; + } + /* + printf("> application_id : %s\n", application_id); + printf("> task_id : %s\n", task_id); + printf("> experiment_id : %s\n", experiment_id);*/ + + log_info("> application_id : %s\n", application_id); + log_info("> task_id : %s\n", task_id); + log_info("> experiment_id : %s\n", experiment_id); + + /* close and reopen logFile */ + fclose(logFile); + logFile = fopen(logFileName, "a"); + + return SUCCESS; +} diff --git a/Client/src/agent/main.h b/Client/src/agent/main.h new file mode 100644 index 0000000..70bbece --- /dev/null +++ b/Client/src/agent/main.h @@ -0,0 +1,24 @@ +#ifndef MAIN_H +#define MAIN_H + +/* + * Path of current directory + */ +extern char *pwd; + +/* + * Name and location of the configuration file + */ +extern char *confFile; +extern char *logFileName; + +/* IDs for the specific application */ +extern char *application_id; +extern char *task_id; +extern char *experiment_id; +extern char *platform_id; + +/* URL for publishing metrics */ +extern char *metrics_publish_URL; + +#endif /* MAIN_H */ \ No newline at end of file diff --git a/Client/src/agent/plugin_discover.c b/Client/src/agent/plugin_discover.c new file mode 100644 index 0000000..8e7ef80 --- /dev/null +++ b/Client/src/agent/plugin_discover.c @@ -0,0 +1,173 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "plugin_discover.h" +#include "mf_debug.h" //functions like log_error(), log_info()... +#include "mf_parser.h" //mfp_get_value() + +/******************************************************************************* + * Variable Declarations + ******************************************************************************/ +/* List of pointers of plugin handles */ +typedef struct PluginHandleList_t { + void* handle; + struct PluginHandleList_t* next; +} PluginHandleList; + +/* First node of the list*/ +typedef struct PluginDiscoveryState_t { + PluginHandleList* handle_list; +} PluginDiscoveryState; + +/* Plugin init function */ +typedef int (*PluginInitFunc)(PluginManager *pm); + +int pluginCount = 0; + +char* plugins_name[256]; + +/******************************************************************************* + * Forward Declarations + ******************************************************************************/ +/* Load a plugin by calling the init function of a plugin */ +void* load_plugin(char *name, char *fullpath, PluginManager *pm); + +/* parse mf_config.ini + * if one plugin is switched on, call load_plugin function to load the plugin, + * store all the loaded plugin handlers to a list */ +void* discover_plugins(const char *dirname, PluginManager *pm) { + DIR* dir = opendir(dirname); + struct dirent *direntry; + + if (!dir) { + log_error("Unable to open directory %s!\n", dirname); + return NULL ; + } + + PluginDiscoveryState *plugins_state = malloc(sizeof(*plugins_state)); + plugins_state->handle_list = NULL; + + while ((direntry = readdir(dir))) { + /*get the name of the plugin*/ + char *last_slash = strrchr(direntry->d_name, '/'); + char *name_start = last_slash ? last_slash + 1 : direntry->d_name; + char *last_dot = strrchr(direntry->d_name, '.'); + + if (!last_dot || strcmp(last_dot, ".so")) + continue; + char *name = calloc(last_dot - name_start + 1, sizeof(char)); + strncpy(name, name_start, last_dot - name_start); + + if (!name) { + continue; + } + + /* do not consider plug-ins that are switched off */ + char value[20] = {'\0'}; + mfp_get_value("plugins", name, value); + if (strcmp(value, "off") == 0) { + free(name); + continue; + } + + char *fullpath = malloc(200 * sizeof(char)); + + strcpy(fullpath, dirname); + strcat(fullpath, "/"); + strcat(fullpath, direntry->d_name); + plugins_name[pluginCount] = malloc(sizeof(char) * 256); + strcpy(plugins_name[pluginCount], name); + void *handle = load_plugin(name, fullpath, pm); + if (handle) { + PluginHandleList *handle_node = malloc(sizeof(*handle_node)); + handle_node->handle = handle; + handle_node->next = plugins_state->handle_list; + plugins_state->handle_list = handle_node; + pluginCount++; + } + free(name); + free(fullpath); + } + + closedir(dir); + if (plugins_state->handle_list) + return (void*) plugins_state; + else { + free(plugins_state); + return NULL ; + } + return 0; +} + +/* Clean-up plug-ins after execution */ +void cleanup_plugins(void* vpds) { + if(vpds != NULL) { + PluginDiscoveryState *pds = (PluginDiscoveryState*) vpds; + PluginHandleList *node = pds->handle_list; + while (node) { + PluginHandleList *next = node->next; + dlclose(node->handle); + free(node); + node = next; + } + free(pds); + } +} + +/* Load a plugin by calling the init function of a plugin, + when successfully, the plugin hook function is registered by the + PluginManager */ +void* load_plugin(char *name, char *fullpath, PluginManager *pm) { + char* slashed_path = strdup(fullpath); + + void *libhandle = dlopen(slashed_path, RTLD_NOW); + + if (!libhandle) { + log_error("Unable to load library %s\n", dlerror()); + return NULL; + } + + char *init_func_name = malloc((strlen("init_") + strlen(name)) * sizeof(char) + 1); + + strcpy(init_func_name, "init_"); + strcat(init_func_name, name); + + void *ptr = dlsym(libhandle, init_func_name); + free(init_func_name); + if (!ptr) { + log_error("Unable to load init function %s\n", dlerror()); + return NULL; + } + + PluginInitFunc init_func = (PluginInitFunc) (intptr_t) ptr; + + int rc = init_func(pm); + if (rc <= 0) { + log_error("Plugin init function failed for %s\n", strerror(rc)); + dlclose(libhandle); + return NULL ; + } + + free(slashed_path); + return libhandle; +} \ No newline at end of file diff --git a/Client/src/agent/plugin_discover.h b/Client/src/agent/plugin_discover.h new file mode 100644 index 0000000..b8a253b --- /dev/null +++ b/Client/src/agent/plugin_discover.h @@ -0,0 +1,42 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_DISCOVER_H_ +#define PLUGIN_DISCOVER_H_ + +#include "plugin_manager.h" + +/** + * @brief Number of plug-ins found at run-time + */ +extern int pluginCount; + +/** + * @brief Name of a given plug-in + */ +extern char* plugins_name[256]; + +/** + * @brief Discovers available plug-ins, and registers them to the plugin manager + */ +void* discover_plugins(const char *dirname, PluginManager *pm); + +/** + * @brief Clean-up plug-ins after execution + */ +void cleanup_plugins(void*); + +#endif /* PLUGIN_DISCOVER_H_ */ diff --git a/Client/src/agent/plugin_manager.c b/Client/src/agent/plugin_manager.c new file mode 100644 index 0000000..560ecdc --- /dev/null +++ b/Client/src/agent/plugin_manager.c @@ -0,0 +1,66 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "plugin_manager.h" +#include "mf_debug.h" //functions like log_error(), log_info()... + +/* Creat a new plugin manager, which contains a hook queue */ +PluginManager* PluginManager_new() { + PluginManager *pm = malloc(sizeof(PluginManager)); + pm->hook_queue = ECQ_create(0); + return pm; +} + +/* Clean-up a plugin manager */ +void PluginManager_free(PluginManager *pm) { + ECQ_free(pm->hook_queue); + free(pm); +} + +/* Register a plugin hook to the plugin manager + * push the hook to the hook queue */ +void PluginManager_register_hook(PluginManager *pm, const char *name, PluginHook hook) { + PluginHookType *hookType = malloc(sizeof(PluginHookType)); + hookType->hook = hook; + hookType->name = name; + + EXCESS_concurrent_queue_handle_t hook_queue_handle; + hook_queue_handle = ECQ_get_handle(pm->hook_queue); + ECQ_enqueue(hook_queue_handle, (void *)hookType); + ECQ_free_handle(hook_queue_handle); +} + +/* Pop one hook from the hook queue */ +PluginHook PluginManager_get_hook(PluginManager *pm) { + PluginHook funcPtr = NULL; + void *retPtr; + + EXCESS_concurrent_queue_handle_t hook_queue_handle; + hook_queue_handle =ECQ_get_handle(pm->hook_queue); + + if(ECQ_try_dequeue(hook_queue_handle, &retPtr)) { + PluginHookType *typePtr; + typePtr = (struct PluginHookType_t *) retPtr; + funcPtr = *(typePtr->hook); + log_info("Using plugin %s\n", typePtr->name); + } + + ECQ_free_handle(hook_queue_handle); + return funcPtr; +} \ No newline at end of file diff --git a/Client/src/agent/plugin_manager.h b/Client/src/agent/plugin_manager.h new file mode 100644 index 0000000..c6aa5e2 --- /dev/null +++ b/Client/src/agent/plugin_manager.h @@ -0,0 +1,66 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_MANAGER_H_ +#define PLUGIN_MANAGER_H_ + +#include + +/** + * @brief Entry function of a plug-in + */ +typedef char* (*PluginHook)(); + +/** + * @brief definition of plugin manager struct + */ +typedef struct PluginManager_t { + EXCESS_concurrent_queue_t hook_queue; +} PluginManager; + +/** + * @brief definition of plugin hook + */ +typedef struct PluginHookType_t { + PluginHook hook; + const char *name; +} PluginHookType; + +/** + * @brief Initializing the plug-in manager + */ +PluginManager* PluginManager_new(); + +/** + * @brief Functions to deallocate the memory used at run-time + */ +void PluginManager_free(PluginManager *pm); + +/** + * @brief Registers hooks, i.e. entry functions, for each plug-in + */ +void PluginManager_register_hook(PluginManager *pm, const char *name, PluginHook hook); + +/** + * @brief Return the hook function associated with the given plug-in + * + * It should be noted that hooks are stored in a FIFO queue. + * + * @returns a hook function + */ +PluginHook PluginManager_get_hook(PluginManager *pm); + +#endif /* PLUGIN_MANAGER_H_ */ diff --git a/Client/src/agent/thread_handler.c b/Client/src/agent/thread_handler.c new file mode 100644 index 0000000..09a572f --- /dev/null +++ b/Client/src/agent/thread_handler.c @@ -0,0 +1,236 @@ +/* + * Copyright 2014, 2015 High Performance Computing Center, Stuttgart + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "main.h" // variables like confFile +#include "mf_parser.h" // functions like mfp_parse(), ... +#include "publisher.h" // function like publish_json() +#include "mf_debug.h" // functions like log_error(), log_info()... +#include "plugin_manager.h" // functions like PluginManager_new(), PluginManager_free(), PluginManager_get_hook() +#include "plugin_discover.h" // variables like pluginCount, plugins_name; + // functions like discover_plugins(), cleanup_plugins() +#include "thread_handler.h" + +#define JSON_LEN 1024 +#define SUCCESS 1 +#define FAILURE 0 + +/******************************************************************************* + * Variable Declarations + ******************************************************************************/ +int running; +int bulk_size; +static PluginManager *pm; +pthread_t threads[256]; +long timings[256]; +struct timespec sleep_tims[256]; +PluginHook *hooks; + +/******************************************************************************* + * Forward Declarations + ******************************************************************************/ +static void catcher(int signo); +static void init_timings(void); +static void *entryThreads(void *arg); //threads entry for all threads +static int checkConf(void); +static int gatherMetric(int num); + +/******************************************************************************* + * Functions implementation + ******************************************************************************/ +/* All threads starts here */ +int startThreads(void) { + int t; + running = 1; + + /* initialize plugin manager, which is a queue of plugin hooks */ + pm = PluginManager_new(); + const char *dirname = { "/plugins" }; + char *pluginLocation = malloc(256 * sizeof(char)); + strcpy(pluginLocation, pwd); + strcat(pluginLocation, dirname); + + /* discover plugins and register them to the plugin manager */ + void* pdstate = discover_plugins(pluginLocation, pm); + + /* get sampling interval for each plugin */ + init_timings(); + + /*get bulk_size from mf_config.ini */ + char tmp_string[20] = {'\0'}; + mfp_get_value("generic", "bulk_size", tmp_string); + bulk_size = atoi(tmp_string); + + int num_threads = pluginCount + 1; + int iret[num_threads]; + int nums[num_threads]; + + hooks = (PluginHook *)malloc(pluginCount * sizeof(PluginHook)); + for (t = 0; t < pluginCount; t++) { + hooks[t] = PluginManager_get_hook(pm); + } + + /* create threads for monitoring and updating configurations */ + for (t = 0; t < num_threads; t++) { + nums[t] = t; + iret[t] = pthread_create(&threads[t], NULL, entryThreads, &nums[t]); + if (iret[t]) { + log_error("pthread_create() failed for %s.\n", strerror(iret[t])); + exit(FAILURE); + } + } + + struct sigaction sig; + sig.sa_handler = catcher; /* signal handler is "catcher" */ + sig.sa_flags = SA_RESTART; + sigemptyset(&sig.sa_mask); + sigaction(SIGTERM, &sig, NULL ); + sigaction(SIGINT, &sig, NULL ); + + while (running) + sleep(1); + + /* thread join from plugins threads till all the sending threads */ + for (t = 0; t < pluginCount; t++) { + pthread_join(threads[t], NULL); + } + + cleanup_plugins(pdstate); + PluginManager_free(pm); + free(pluginLocation); + return SUCCESS; +} + +/* catch the stop signal */ +static void catcher(int signo) +{ + running = 0; + log_info("Signal %d catched.\n", signo); +} + +/* entry for all threads */ +static void* entryThreads(void *arg) +{ + int *typeT = (int*) arg; + if(*typeT < pluginCount) { + gatherMetric(*typeT); + } + else { + checkConf(); + } + return NULL; +} + +/* timings update if mf_config.ini has been modified */ +static int checkConf(void) +{ + while (running) { + mfp_parse(confFile); + char wait_some_seconds[20] = {'\0'}; + mfp_get_value("timings", "update_configuration", wait_some_seconds); + sleep(atoi(wait_some_seconds)); + + /* update sleep_tims for all plugins */ + init_timings(); + } + return SUCCESS; +} + +/* each plugin gathers its metrics at a specific rate and send the json-formatted metrics to mf_server */ +static int gatherMetric(int num) +{ + int i; + long timings = sleep_tims[num].tv_sec * 10e8 + sleep_tims[num].tv_nsec; + + log_info("Gather metrics of plugin %s (#%d) with update interval of %ld ns\n", plugins_name[num], num, timings); + + char *json_array = calloc(JSON_LEN * bulk_size, sizeof(char)); + json_array[0] = '['; + char msg[JSON_LEN] = {'\0'}; + char static_json[512] = {'\0'}; + + sprintf(static_json, "{\"WorkflowID\":\"%s\",\"ExperimentID\":\"%s\",\"TaskID\":\"%s\",\"host\":\"%s\",", + application_id, experiment_id, task_id, platform_id); + + while (running) { + + for(i=0; i= 10e8) { + sleep_tims[i].tv_sec = timings[i] / 10e8; + sleep_tims[i].tv_nsec = timings[i] % (long) 10e8; + } else { + sleep_tims[i].tv_sec = 0; + sleep_tims[i].tv_nsec = timings[i]; + } + } + } +} \ No newline at end of file diff --git a/Client/src/agent/thread_handler.h b/Client/src/agent/thread_handler.h new file mode 100644 index 0000000..b69c7cd --- /dev/null +++ b/Client/src/agent/thread_handler.h @@ -0,0 +1,9 @@ +#ifndef THREAD_HANDLER_H_ +#define THREAD_HANDLER_H_ + +/** + * @brief Starts all threads registered + */ +int startThreads(void); + +#endif /* THREAD_HANDLER_H_ */ \ No newline at end of file diff --git a/Client/src/api/Makefile b/Client/src/api/Makefile new file mode 100644 index 0000000..2506099 --- /dev/null +++ b/Client/src/api/Makefile @@ -0,0 +1,41 @@ +CC = gcc + +COPT_SO = $(CFLAGS) -fPIC + +CFLAGS = -std=gnu99 -pedantic -Wall -Wwrite-strings -Wpointer-arith \ +-Wcast-align -O0 -ggdb $(CORE_INC) $(CURL_INC) $(PUBLISH_INC) + +LFLAGS = -lm -lpthread $(PUBLISH) $(CURL) + +COMMON = ${CURDIR}/.. + +PUBLISH_INC = -I${COMMON}/publisher/src +CORE_INC = -I$(COMMON)/core +CURL_INC = -I$(COMMON)/../bin/curl/include + +PUBLISH = -L${COMMON}/publisher -lpublisher +CURL = -L$(COMMON)/../bin/curl/lib -lcurl + +SRC = ${CURDIR}/src + +DEBUG ?= 1 +ifeq ($(DEBUG), 1) + CFLAGS += -DDEBUG -g +else + CFLAGS += -DNDEBUG +endif + +all: clean libmf.so libmf.a + +${SRC}/%.o: ${SRC}/%.c + $(CC) -c $< -o $@ $(COPT_SO) + +libmf.so: ${SRC}/mf_api.o ${SRC}/resources_monitor.o ${SRC}/disk_monitor.o ${SRC}/power_monitor.o + $(CC) -shared -o $@ $^ $(CFLAGS) $(LFLAGS) + +libmf.a: ${SRC}/mf_api.o ${SRC}/resources_monitor.o ${SRC}/disk_monitor.o ${SRC}/power_monitor.o + ar rcs $@ $^ + +clean: + rm -rf ${SRC}/*.o + rm -rf *.o *.a *.so diff --git a/Client/src/api/README.md b/Client/src/api/README.md new file mode 100644 index 0000000..b35ce50 --- /dev/null +++ b/Client/src/api/README.md @@ -0,0 +1,87 @@ +# PHANTOM monitoring client APIs + +> PHANTOM monitoring client APIs are used in mainly two domains: application-level monitoring for code instrumentation; and user-defined metrics sampling and sending. Although the APIs are written in C, it can be used also by applications written in other languages as well. In the following, we will clarify how and when to use these APIs in an application. + +## Interfaces introduction +Following interfaces are developed and included in the first release of the monitoring client: + +``` +char *mf_start(char *server, char *platform_id, metrics *m); + +void mf_end(void); + +char *mf_send(char *server, char *application_id, char *component_id, char *platform_id); + +int mf_user_metric(char *metric_name, char *value); +``` + +Function **mf_start** starts monitoring of the predefined metrics for sub-components of an application. Data are stored at first locally. Required input parameters should include the MF server URL, name of the platform (where the application runs), and the metrics’ name and sampling frequency. + +Function **mf_stop** stops monitoring of the predefined metrics when the sub-component is finished. + +Function **mf_send** sends locally-stored predefined metrics to the PHANTOM MF server. The unique generated execution ID will be returned on success. + +Function **mf_user_metric** sends user-defined metrics with given metric’s name, value, and current local timestamps to the PHANTOM MF server. It is noted that the programmers should convert the metrics' value into a string while calling this function. + +## Application example +The above mentioned APIs can be used by a generic application for code instrumentation. Following is a part of an application's source code (written in C++), which is used here to clarify how to use the client APIs. + +As specified by the programmer, if all preconditions are statisfied by the target platform, we can gather power and performance metrics about CPU, memory, disk I/O and network devices, as defined in the variable **m_resources**. In addition to these predefined metrics, users are able to send also user-defined metrics to the MF server. Take the following source code as an example, the user-defined metrics are **duration** and **nrLoops**, which represent the execution duration for each simulation and the number of total simulation loops respectively. + +``` +#include ... +extern "C" { + #include "../src/mf_api.h" +} + +... +int main() { +/* initialization of various application elements, and parameters */ + ... + initNetwork("TestNet", &netparams, 8, 6); + initBranches(&(*branches), netparams); + initVertexes(&(*vertexes), netparams); + float integrationStep = 0.001; // simulation steps + int nrLoops = 5000; // simulation loops + +/* MONITORING START */ + metrics m_resources; + m_resources.num_metrics = 3; + m_resources.local_data_storage = 1; + m_resources.sampling_interval[0] = 1000; // 1000 ms + strcpy(m_resources.metrics_names[0], "resources_usage"); + m_resources.sampling_interval[1] = 1000; // 1000 ms + strcpy(m_resources.metrics_names[1], "disk_io"); + m_resources.sampling_interval[2] = 1000; // 1000 ms + strcpy(m_resources.metrics_names[2], "power"); + char *datapath = mf_start("141.58.0.8:3033", "node01", &m_resources); + +/* simulation process */ + for (int n = 0; n < nrLoops; n++) { + auto begin_time = std::chrono::high_resolution_clock::now(); + simulation_loop(&(*branches), &(*vertexes), netparams, n, + integrationStep); + auto end_time = std::chrono::high_resolution_clock::now(); + std::chrono::duration duration = end_time-begin_time; + + /* MONITORING USER-DEFINED METRICS → duration of each loop */ + char metric_value[8] = {'\0'}; + sprintf(metric_value, "%f", duration); + mf_user_metric("duration", metric_value); + } + +/* MONITORING END */ + mf_end(); + +/* MONITORING USER-DEFINED METRICS →total nr. of completed loops */ + char metric_value[8] = {'\0'}; + sprintf(metric_value, "%d", nrLoops); + mf_user_metric("nrLoops", metric_value); + +/* MONITORING SEND */ + char *experiment_id = mf_send("141.58.0.8:3033", "dummy", "t1", "node01"); + printf("\n> experiment_id is %s\n", experiment_id); + cout << "Simulation finished"; + return 0; +} +``` \ No newline at end of file diff --git a/Client/src/api/app_alexy/Elements.h b/Client/src/api/app_alexy/Elements.h new file mode 100644 index 0000000..d160784 --- /dev/null +++ b/Client/src/api/app_alexy/Elements.h @@ -0,0 +1,277 @@ +/*====================== + Copyright (c) 2016, Alexey CHEPTSOV + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ======================= + */ + +#include "Solver.h" + +class NetworkParams { + +public: + NetworkParams() { + } + ; + NetworkParams(int nrBranches, int nrVertexes, int* A, char* name) { + this->name = name; + this->A = A; + this->nrBranches = nrBranches; + this->nrVertexes = nrVertexes; + } + ; + ~NetworkParams() { + delete[] A; + } + ; + + int* getA() { + return A; + } + ; + int getElementOfA(int vertexNr, int branchNr) { + return A[vertexNr * nrBranches + branchNr]; + } + ; + char* getName() { + return name; + } + ; + int getNrBranches() { + return nrBranches; + } + ; + int getNrVertexes() { + return nrVertexes; + } + ; + +private: + int* A; + char* name; + int nrBranches; + int nrVertexes; +}; + +class BranchParams { +public: + BranchParams() { + } + ; + BranchParams(float A, float B, float C, int nrApproximationElements, + char* name) { + this->A = A; + this->B = B; + this->C = C; + this->nrApproximationElements = nrApproximationElements; + this->name = name; + } + ; + +private: + int nrApproximationElements; + float A; + float B; + float C; + char* name; + +public: + int getNrApproxElements() { + return nrApproximationElements; + } + char* getName() { + return name; + } + float getA() { + return A; + } + float getB() { + return A; + } + float getC() { + return C; + } +}; + +class VertexParams { +public: + VertexParams() { + } + ; + VertexParams(bool isExternal, float H_external, char* name) { + this->isExternal = isExternal; + this->H_external = H_external; + this->name = name; + } + ; +private: + float H_external; + bool isExternal; // true if connected to an external depression source + char* name; + +public: + float getH_external() { + return H_external; + } + bool getIsExternal() { + return isExternal; + } + char* getName() { + return name; + } +}; + +class Branch { +public: + Branch() { + + } + Branch(BranchParams *branchparams, NetworkParams *networkparams) { + this->networkparams = networkparams; + init(branchparams); + } + ; + ~Branch() { + delete[] P; + delete[] Q; + } + ; + + BranchParams* getParams() { + return &branchparams; + } + ; + +private: + // aerodynamical paramemeters + float* P; // pressure + float* Q; // air flow + + // aerodynamical properties of the element + BranchParams branchparams; + + // network parameters + NetworkParams *networkparams; + +public: + void init(BranchParams *branchparams) { + + //TODO: + //check whether Q and P have been allocated + + this->branchparams = *branchparams; + + this->Q = new float[this->branchparams.getNrApproxElements()]; + for (int i = 0; i < this->branchparams.getNrApproxElements(); i++) + this->Q[i] = 0; + + P = new float[this->branchparams.getNrApproxElements() + 1]; + for (int i = 0; i < this->branchparams.getNrApproxElements() + 1; i++) + P[i] = 0; + } + + int simulateBranchFlow(float integrationStep) { + cout << "Simulating branch " << branchparams.getName() << endl; + + Euler *solver = new Euler(); + solver->simulateBranch(integrationStep, P, Q, branchparams.getA(), + branchparams.getB(), branchparams.getC(), + branchparams.getNrApproxElements()); + + /*for (int i = 0; i < branchparams.getNrApproxElements(); i++) + cout << "Q[" << i << "]=" << Q[i] << ","; + cout << endl;*/ + + return 0; + } + + void updateP_Start(float newP) { + P[0] = newP; + } + + void updateP_End(float newP) { + P[this->branchparams.getNrApproxElements()] = newP; + } + + float* getP() { + return P; + } + + float* getQ() { + return Q; + } + +private: + int fetchPressure() { + + return 0; + } +}; + +class Vertex { +public: + Vertex() { + } + ; + Vertex(VertexParams *vertexparams, NetworkParams *networkparams) { + this->networkparams = networkparams; + init(vertexparams); + } + ; + ~Vertex() { + + } + ; + VertexParams* getParams() { + return &vertexparams; + } + ; + +private: + // aerodynamical properties of the element + VertexParams vertexparams; + + // network parameters + NetworkParams* networkparams; + + // aerodynamical paramemeters + float P; // pressure + float QxC_average; + +public: + void init(VertexParams *vertexparams) { + this->vertexparams = *vertexparams; + + P = this->vertexparams.getH_external(); + QxC_average = 0; + } + + float getP() { + return P; + } + + void setP(float P) { + this->P = P; + } + + void setQxC_average(float QxC_average) { + this->QxC_average = QxC_average; + } + + int computeVertexPressure(float integrationStep) { + cout << "Simulating vertex " << vertexparams.getName() << endl; + P = P + (QxC_average) * integrationStep; + + return 0; + } + +}; diff --git a/Client/src/api/app_alexy/Makefile b/Client/src/api/app_alexy/Makefile new file mode 100644 index 0000000..c4314e7 --- /dev/null +++ b/Client/src/api/app_alexy/Makefile @@ -0,0 +1,31 @@ +appname := myapp + +CXX := g++ +CXXFLAGS := -Wall -g -std=c++11 + +srcfiles := $(shell find . -maxdepth 1 -name "*.cpp") +objects := $(patsubst %.cpp, %.o, $(srcfiles)) + +COMMON = ${CURDIR}/../.. +MF_API = -L$(COMMON)/api -lmf +PUBLISH = -L${COMMON}/publisher -lpublisher +CURL = -L$(COMMON)/../bin/curl/lib -lcurl + +all: $(appname) + +$(appname): $(objects) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS) $(MF_API) $(PUBLISH) $(CURL) + +depend: .depend + +.depend: $(srcfiles) + rm -f ./.depend + $(CXX) $(CXXFLAGS) -MM $^>>./.depend; + +clean: + rm -f $(objects) $(appname) .depend + +dist-clean: clean + rm -f *~ .depend + +include .depend \ No newline at end of file diff --git a/Client/src/api/app_alexy/Solver.h b/Client/src/api/app_alexy/Solver.h new file mode 100644 index 0000000..aa0d51a --- /dev/null +++ b/Client/src/api/app_alexy/Solver.h @@ -0,0 +1,93 @@ +/*====================== + Copyright (c) 2016, Alexey CHEPTSOV + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ======================= + */ + +#include + +using namespace std; + +class Solver { +public: + Solver() { + } + ; + ~Solver() { + } + ; + +public: + virtual int simulateBranch(float integrationStep, float *P, float *Q, + float A, float B, float C, int nrApproxElements) { + } + ; + + virtual int simulate() { + } + ; + +}; + +class Euler: public Solver { +public: + + Euler() : + Solver() { + } + ; + /* + Euler(float integrationStep) : + Solver(integrationStep) { + } + ; + */ + +public: + int simulateBranch(float integrationStep, float *P, float *Q, float A, + float B, float C, int nrApproxElements) { + + //cout << "Simulating branch " << (*branch).getParams()->getName() << ": " + // << endl; + + // Q's + for (int i = 0; i < nrApproxElements; i++) + Q[i] = ((P[i] - P[i + 1]) * A - (Q[i] * fabs(Q[i])) * B) + * integrationStep + Q[i]; + + // P's + for (int i = 1; i < nrApproxElements; i++) + P[i] = ((Q[i - 1] - Q[i]) * C) * integrationStep + P[i]; + + for (int i = 0; i < nrApproxElements; i++) + cout << "Q[" << i << "]=" << Q[i] << ","; + cout << endl; + + for (int i = 0; i < nrApproxElements + 1; i++) + cout << "P[" << i << "]=" << P[i] << ","; + cout << endl; + + return 0; + } + ; + int simulateVertex(float integrationStep, float* Pvertex, float Qaverage, + float Caverage) { + + *Pvertex = *Pvertex + (Qaverage * Caverage) * integrationStep; + + return 0; + } + ; +} +; + diff --git a/Client/src/api/app_alexy/Ventilation_2D_compbased.cpp b/Client/src/api/app_alexy/Ventilation_2D_compbased.cpp new file mode 100644 index 0000000..e5addf7 --- /dev/null +++ b/Client/src/api/app_alexy/Ventilation_2D_compbased.cpp @@ -0,0 +1,289 @@ +/*====================== + Copyright (c) 2016, Alexey CHEPTSOV + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ======================= + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Elements.h" + +extern "C" { +#include "../src/mf_api.h" +} + +using namespace std; + +void initNetwork(string name, NetworkParams** netparams, int nrBranches, + int nrVertexes) { + + /* + * B1 B2 B3 B4 B5 B6 B7 B8 + * + * N1 -1, 0, 0, 0, 0, 0, 0, 0, + * N2 1, -1, 0, 0, 0, 0, -1, -1, + * N3 0, 1, 0, 0, -1, -1, 0, 0, + * N4 0, 0, -1, 0, 1, 1, 0, 0, + * N5 0, 0, 1, -1, 0, 0, 1, 1 + * N6 0, 0, 0, 1, 0, 0, 0, 0 + * + */ + + *netparams = new NetworkParams(nrBranches, nrVertexes, new int[6 * 8] { -1, + 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, -1, -1, + 0, 0, 0, 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, -1, 0, 0, 1, 1, 0, 0, 0, 1, + 0, 0, 0, 0 }, &name[0]); + //(*netparams)->getA()[0] + +} + +Branch* initBranch(BranchParams *branchparams, NetworkParams *netparams) { + Branch* branch = new Branch(branchparams, netparams); + + cout << "Branch " << (branch->getParams())->getName() << " with A=" + << (branch->getParams())->getA() << ", B=" + << (branch->getParams())->getB() << ", C=" + << (branch->getParams())->getC() << " has been initialized" << endl; + + //return new Branch(branchparams, netparams); + return branch; +} + +void initBranches(Branch** branches, NetworkParams* netparams) { + BranchParams *branchparams = new BranchParams(0.0655, 0.00252, 259.68, 10, + "Branch1"); + branches[0] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.35, 0.00252, 1385, 10, "Branch2"); + branches[1] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.35, 0.00252, 1385, 10, "Branch3"); + branches[2] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.08, 0.00252, 319.6, 10, "Branch4"); + branches[3] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.02, 0.004, 150.2, 10, "Branch5"); + branches[4] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.034, 0.009, 160.15, 10, "Branch6"); + branches[5] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.021, 0.004, 174.465, 10, "Branch7"); + branches[6] = initBranch(branchparams, netparams); + + branchparams = new BranchParams(0.043, 0.0055, 290.9, 10, "Branch8"); + branches[7] = initBranch(branchparams, netparams); +} + +Vertex* initVertex(VertexParams *vertexparams, NetworkParams *netparams) { + + Vertex* vertex = new Vertex(vertexparams, netparams); + + cout << "Vertex " << (vertex->getParams())->getName() << " external=" + << (vertex->getParams())->getIsExternal() << " with H_external=" + << (vertex->getParams())->getH_external() << " has been initialized" + << endl; + +//return new Vertex(vertexparams, netparams); + return vertex; +} + +void initVertexes(Vertex** vertexes, NetworkParams* netparams) { + VertexParams *vertexparams = new VertexParams(true, 4100, "Node1"); + vertexes[0] = initVertex(vertexparams, netparams); + + vertexparams = new VertexParams(false, 0, "Node2"); + vertexes[1] = initVertex(vertexparams, netparams); + + vertexparams = new VertexParams(false, 0, "Node3"); + vertexes[2] = initVertex(vertexparams, netparams); + + vertexparams = new VertexParams(false, 0, "Node4"); + vertexes[3] = initVertex(vertexparams, netparams); + + vertexparams = new VertexParams(false, 0, "Node5"); + vertexes[4] = initVertex(vertexparams, netparams); + + vertexparams = new VertexParams(true, 0, "Node6"); + vertexes[5] = initVertex(vertexparams, netparams); +} + +void simulation_loop(Branch** branches, Vertex** vertexes, + NetworkParams* netparams, int loopNr, float integrationStep) { + + int nrBranches = netparams->getNrBranches(); + int nrVertexes = netparams->getNrVertexes(); + + /* + * 1. Propagation of boundary conditions + */ + + // 1.1. Pressures from vertexes to branches + for (int i = 0; i < nrBranches; i++) + for (int j = 0; j < nrVertexes; j++) { + if (netparams->getElementOfA(j, i) == 1) //branch enters into the vertex + (*branches[i]).updateP_End((*vertexes[j]).getP()); + else if (netparams->getElementOfA(j, i) == -1) //branch leaves from the vertex + (*branches[i]).updateP_Start((*vertexes[j]).getP()); + } + /* + * 2. Numerical solution step + */ + + // 2.1. Airflow in branches + for (int i = 0; i < nrBranches; i++) + (*branches[i]).simulateBranchFlow(integrationStep); + + // 2.2. Boundary conditions in vertexes + for (int j = 0; j < nrVertexes; j++) { + + bool isExternal = (*vertexes[j]).getParams()->getIsExternal(); + if (!isExternal) { + + float Qaverage = 0; + float Caverage = 0; + + float QxC_average = 0; + + int totNrQ = 0; + + for (int i = 0; i < nrBranches; i++) { + if (netparams->getElementOfA(j, i) == 1) { //branch enters into the vertex + totNrQ++; + + int nrApproxElements = + (*branches[i]).getParams()->getNrApproxElements(); + float* Qtemp = (*branches[i]).getQ(); + QxC_average += (*branches[i]).getParams()->getC() + * Qtemp[nrApproxElements]; + + } else if (netparams->getElementOfA(j, i) == -1) { //branch leaves from the vertex + totNrQ++; + + int nrApproxElements = + (*branches[i]).getParams()->getNrApproxElements(); + float* Qtemp = (*branches[i]).getQ(); + QxC_average -= (*branches[i]).getParams()->getC() + * Qtemp[0]; + + /* old interpretation of the boundary conditions + + Caverage += (*branches[i]).getParams()->getC(); + + float* Qtemp = (*branches[i]).getQ(); + Qaverage -= Qtemp[0]; + */ + } + } + + (*vertexes[j]).setQxC_average(QxC_average); + + } + + /**/cout << "Debug 1: Vertex " << j << " P= " << (*vertexes[j]).getP() + << endl;/**/ + } + + // 2.3. Pressures in vertexes + for (int j = 0; j < nrVertexes; j++) { + (*vertexes[j]).computeVertexPressure(integrationStep); + } +} + +int main() { + +// initialization of the network parameters + NetworkParams *netparams; + + initNetwork("TestNet", &netparams, 8, 6); + cout << "Network " << netparams->getName() << " with " + << netparams->getNrBranches() << " branches and " + << netparams->getNrVertexes() << " vertexes has been initialized" + << endl; + +// initialization of branch elements + Branch *branches[netparams->getNrBranches()]; + initBranches(&(*branches), netparams); + +// initialization of vertex elements + Vertex *vertexes[netparams->getNrVertexes()]; + initVertexes(&(*vertexes), netparams); + +// simulation loops + float integrationStep = 0.001; + int nrLoops = 5000; + +/* MONITORING START */ + metrics m_resources; + m_resources.num_metrics = 2; + m_resources.local_data_storage = 1; + m_resources.sampling_interval[0] = 1000; // 1s + strcpy(m_resources.metrics_names[0], "resources_usage"); + + m_resources.sampling_interval[1] = 1000; // 1s + strcpy(m_resources.metrics_names[1], "disk_io"); + + //m_resources.sampling_interval[2] = 1000; // 1s + //strcpy(m_resources.metrics_names[2], "power"); + + char *datapath = mf_start("localhost:3033", "fangli_laptop", &m_resources); + + for (int n = 0; n < nrLoops; n++) { + cout << "LOOP " << n << endl; + + //clock_t begin_time = clock(); + auto begin_time = std::chrono::high_resolution_clock::now(); + simulation_loop(&(*branches), &(*vertexes), netparams, n, + integrationStep); + auto end_time = std::chrono::high_resolution_clock::now(); + //float duration = float( clock () - begin_time ) / CLOCKS_PER_SEC; + std::chrono::duration duration = end_time-begin_time; + cout << "Loop duration (ms): " << duration.count() << endl; + + /* MONITORING + I'd like to store here the duration of each loop --> duration + */ + char metric_value[8] = {'\0'}; + sprintf(metric_value, "%f", duration); + mf_user_metric("duration", metric_value); + } + +/* MONITORING END */ + mf_end(); + + /* MONITORING + I'd like to store here the total nr. of completed loops --> nrLoops + */ + char metric_value[8] = {'\0'}; + sprintf(metric_value, "%d", nrLoops); + mf_user_metric("nrLoops", metric_value); + +/* MONITORING SEND */ + char *experiment_id = mf_send("localhost:3033", "dummy", "t1", "fangli_laptop"); + printf("\n> experiment_id is %s\n", experiment_id); + + cout << "Simulation finished"; + return 0; +} diff --git a/Client/src/api/app_alexy/setenv.sh b/Client/src/api/app_alexy/setenv.sh new file mode 100644 index 0000000..cc8fa1a --- /dev/null +++ b/Client/src/api/app_alexy/setenv.sh @@ -0,0 +1,3 @@ +#!/bin/bash +PWD=`pwd` +export LD_LIBRARY_PATH=$PWD/../../../bin/curl/lib:$PWD/../../publisher:$PWD/..:$LD_LIBRARY_PATH \ No newline at end of file diff --git a/Client/src/api/src/disk_monitor.c b/Client/src/api/src/disk_monitor.c new file mode 100644 index 0000000..8e598c3 --- /dev/null +++ b/Client/src/api/src/disk_monitor.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include "disk_monitor.h" +#include "mf_api.h" + +/******************************************************************************* + * Implementaion + ******************************************************************************/ +int disk_monitor(int pid, char *DataPath, long sampling_interval) +{ + /*create and open the file*/ + char FileName[256] = {'\0'}; + sprintf(FileName, "%s/%s", DataPath, METRIC_NAME_2); + FILE *fp = fopen(FileName, "a"); //append data to the end of the file + if (fp == NULL) { + printf("ERROR: Could not create file: %s\n", FileName); + return 0; + } + struct timespec timestamp; + double timestamp_ms; + unsigned long long read, write; + float throughput; + disk_stats result; + /*initialize the values in result */ + result.read_bytes_after = 0; + result.write_bytes_after = 0; + disk_stats_read(pid, &result); + + /*in a loop do data sampling and write into the file*/ + while(running) { + usleep(sampling_interval * 1000); + disk_stats_read(pid, &result); + /*get current timestamp in ms*/ + clock_gettime(CLOCK_REALTIME, ×tamp); + timestamp_ms = timestamp.tv_sec * 1000.0 + (double)(timestamp.tv_nsec / 1.0e6); + /*calculate the values for disk stats */ + read = result.read_bytes_after - result.read_bytes_before; + write = result.write_bytes_after - result.write_bytes_before; + throughput = (read + write) * 1000.0 / sampling_interval; //in bytes/s + + fprintf(fp, "\"local_timestamp\":\"%.1f\", \"%s\":%llu, \"%s\":%llu, \"%s\":%.3f\n", timestamp_ms, + "disk_read", read, + "disk_write", write, + "disk_throughput", throughput); + } + + /*close the file*/ + fclose(fp); + return 1; +} + +int disk_stats_read(int pid, disk_stats *disk_info) +{ + FILE *fp; + char filename[128], line[256]; + + /*update the before read/write bytes */ + disk_info->read_bytes_before = disk_info->read_bytes_after; + disk_info->write_bytes_before = disk_info->write_bytes_after; + + sprintf(filename, "/proc/%d/io", pid); + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "ERROR: Could not open file %s.\n", filename); + return 0; + } + + while (fgets(line, 256, fp) != NULL) { + if (!strncmp(line, "read_bytes:", 11)) { + sscanf(line + 12, "%llu", &disk_info->read_bytes_after); + } + if (!strncmp(line, "write_bytes:", 12)) { + sscanf(line + 13, "%llu", &disk_info->write_bytes_after); + } + } + fclose(fp); + return 1; +} \ No newline at end of file diff --git a/Client/src/api/src/disk_monitor.h b/Client/src/api/src/disk_monitor.h new file mode 100644 index 0000000..5834b79 --- /dev/null +++ b/Client/src/api/src/disk_monitor.h @@ -0,0 +1,17 @@ +#ifndef _DISK_MONITOR_H +#define _DISK_MONITOR_H + +#define METRIC_NAME_2 "disk_io" + +typedef struct disk_stats_t { + unsigned long long read_bytes_before; + unsigned long long read_bytes_after; + unsigned long long write_bytes_before; + unsigned long long write_bytes_after; +} disk_stats; + +int disk_monitor(int pid, char *DataPath, long sampling_interval); +int disk_stats_read(int pid, disk_stats *disk_info); + +#endif + diff --git a/Client/src/api/src/mf_api.c b/Client/src/api/src/mf_api.c new file mode 100644 index 0000000..b6fd53e --- /dev/null +++ b/Client/src/api/src/mf_api.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "publisher.h" +#include "resources_monitor.h" +#include "disk_monitor.h" +#include "power_monitor.h" +#include "mf_api.h" + +/******************************************************************************* + * Variable Declarations + ******************************************************************************/ +typedef struct each_metric_t { + long sampling_interval; //in milliseconds + char metric_name[NAME_LENGTH]; //user defined metrics +} each_metric; + +int running; +int keep_local_data_flag = 1; +char parameters_name[9][32] = {"MAX_CPU_POWER", "MIN_CPU_POWER", + "MEMORY_POWER", "L2CACHE_MISS_LATENCY", "L2CACHE_LINE_SIZE", + "E_DISK_R_PER_KB", "E_DISK_W_PER_KB", + "E_NET_SND_PER_KB", "E_NET_RCV_PER_KB"}; +float parameters_value[9]; + +char DataPath[256]; +pthread_t threads[MAX_NUM_METRICS]; +int num_threads; +int pid; + +FILE *logFile; + +/******************************************************************************* + * Forward Declarations + ******************************************************************************/ +static int api_prepare(char *Data_path); +static void *MonitorStart(void *arg); +int get_config_parameters(char *server, char *platform_id); + +int mf_user_metric(char *metric_name, char *value) +{ + if(DataPath[0] == '\0') { + pid = api_prepare(DataPath); + } + /*create and open the file*/ + char FileName[256] = {'\0'}; + sprintf(FileName, "%s/%s", DataPath, "user_defined"); + FILE *fp = fopen(FileName, "a"); //append data to the end of the file + if (fp == NULL) { + printf("ERROR: Could not create file: %s\n", FileName); + return 0; + } + struct timespec timestamp; + /*get current timestamp */ + clock_gettime(CLOCK_REALTIME, ×tamp); + /*convert to milliseconds */ + double timestamp_ms = timestamp.tv_sec * 1000.0 + (double)(timestamp.tv_nsec / 1.0e6); + + fprintf(fp, "\"local_timestamp\":\"%.1f\", \"%s\":%s\n", timestamp_ms, metric_name, value); + /*close the file*/ + fclose(fp); + return 1; +} + +/* +Get the pid, and setup the DataPath for data storage +For each metric, create a thread, open a file for data storage, and start sampling the metrics periodically. +Return the path of data files +*/ +char *mf_start(char *server, char *platform_id, metrics *m) +{ + /* get pid and setup the DataPath according to pid */ + pid = api_prepare(DataPath); + + /* get parameters from server with given platform_id */ + if(get_config_parameters(server, platform_id) <= 0) { + printf("ERROR : get_config_parameters failed.\n"); + return NULL; + } + + num_threads = m->num_metrics; + int t; + int iret[num_threads]; + each_metric *each_m = malloc(num_threads * sizeof(each_metric)); + + running = 1; + keep_local_data_flag = m->local_data_storage; + + for (t = 0; t < num_threads; t++) { + /*prepare the argument for the thread*/ + each_m[t].sampling_interval = m->sampling_interval[t]; + strcpy(each_m[t].metric_name, m->metrics_names[t]); + /*create the thread and pass associated arguments */ + iret[t] = pthread_create(&threads[t], NULL, MonitorStart, &(each_m[t])); + if (iret[t]) { + printf("ERROR: pthread_create failed for %s\n", strerror(iret[t])); + return NULL; + } + } + return DataPath; +} + +/* +Stop threads. +Close all the files for data storage +*/ +void mf_end(void) +{ + int t; + + running = 0; + for (t = 0; t < num_threads; t++) { + pthread_join(threads[t], NULL); + } +} + +/* +Generate the execution_id. +Send the monitoring data in all the files to mf_server. +Return the execution_id +*/ +char *mf_send(char *server, char *application_id, char *component_id, char *platform_id) +{ + /* create an experiment with regards of given application_id, component_id and so on */ + char *msg = calloc(256, sizeof(char)); + char *URL = calloc(256, sizeof(char)); + char *experiment_id = calloc(64, sizeof(char)); + + sprintf(msg, "{\"application\":\"%s\", \"task\": \"%s\", \"host\": \"%s\"}", + application_id, component_id, platform_id); + sprintf(URL, "%s/v1/phantom_mf/experiments/%s", server, application_id); + + create_new_experiment(URL, msg, experiment_id); + if(experiment_id[0] == '\0') { + printf("ERROR: Cannot create new experiment for application %s\n", application_id); + return NULL; + } + //sleep(5); + + /*malloc variables for send metrics */ + char *metric_URL = calloc(256, sizeof(char)); + char *static_string = calloc(256, sizeof(char)); + char *filename = calloc(256, sizeof(char)); + + sprintf(metric_URL, "%s/v1/phantom_mf/metrics", server); + + DIR *dir = opendir(DataPath); + if(dir == NULL) { + printf("Error: Cannot open directory %s\n", DataPath); + return NULL; + } + + struct dirent *drp = readdir(dir); + + while(drp != NULL) { + + sprintf(filename, "%s/%s", DataPath, drp->d_name); + sprintf(static_string, "\"WorkflowID\":\"%s\", \"TaskID\":\"%s\", \"ExperimentID\":\"%s\", \"type\":\"%s\", \"host\":\"%s\"", + application_id, component_id, experiment_id, drp->d_name, platform_id); + + publish_file(metric_URL, static_string, filename); + + /*remove the file if user unset keep_local_data_flag */ + if(keep_local_data_flag == 0) { + unlink(filename); + } + + /*get the next entry */ + drp = readdir(dir); + memset(static_string, '\0', 256); + memset(filename, '\0', 256); + } + + closedir(dir); + fclose(logFile); + + /*remove the data directory if user unset keep_local_data_flag */ + if(keep_local_data_flag == 0) { + rmdir(DataPath); + } + return experiment_id; +} + +/* +Get the pid, and setup the DataPath for data storage +*/ +static int api_prepare(char *Data_path) +{ + /*reset Data_path*/ + size_t size = strlen(Data_path); + memset(Data_path, '\0', size); + + /*get the pid*/ + int pid = getpid(); + + /*get the pwd*/ + char buf_1[256] = {'\0'}; + char buf_2[256] = {'\0'}; + int ret = readlink("/proc/self/exe", buf_1, 200); + if(ret == -1) { + printf("readlink /proc/self/exe failed.\n"); + exit(0); + } + memcpy(buf_2, buf_1, strlen(buf_1) * sizeof(char)); + + /* extract path folder of executable from it's path */ + char *lastslash = strrchr(buf_2, '/'); + int ptr = lastslash - buf_2; + memcpy(Data_path, buf_2, ptr); + + /*create logfile*/ + char logFileName[256] = {'\0'}; + sprintf(logFileName, "%s/log.txt", Data_path); + logFile = fopen(logFileName, "w"); + if (logFile == NULL) { + printf("Could not create log file %s", logFileName); + } + + /*create the folder with regards of the pid*/ + sprintf(Data_path + strlen(Data_path), "/%d", pid); + struct stat st = { 0 }; + if (stat(Data_path, &st) == -1) + mkdir(Data_path, 0700); + + return pid; +} + + +static void *MonitorStart(void *arg) { + each_metric *metric = (each_metric*) arg; + if(strcmp(metric->metric_name, METRIC_NAME_1) == 0) { + resources_monitor(pid, DataPath, metric->sampling_interval); + } + else if(strcmp(metric->metric_name, METRIC_NAME_2) == 0) { + disk_monitor(pid, DataPath, metric->sampling_interval); + } + else if(strcmp(metric->metric_name, METRIC_NAME_3) == 0) { + power_monitor(pid, DataPath, metric->sampling_interval); + } + else { + printf("ERROR: it is not possible to monitor %s\n", metric->metric_name); + return NULL; + } + return NULL; +} + +int get_config_parameters(char *server, char *platform_id) +{ + /* send the query and retrieve the response string */ + char *URL = calloc(256, sizeof(char)); + char *response_str = calloc(256, sizeof(char)); + + sprintf(URL, "%s/v1/phantom_rm/configs/%s", server, platform_id); + if(query_json(URL, response_str) <= 0) { + printf("ERROR: query with %s failed.\n", URL); + return 0; + } + if(strstr(response_str, "parameters") == NULL) { + printf("ERROR: response does not include parameters.\n"); + return 0; + } + + /* parse the send back string to get required parameters */ + char *ptr_begin, *ptr_end; + char value[16] = {'\0'}; + int i, value_length; + for (i = 0; i <= 8; i++) { + ptr_begin = strstr(response_str, parameters_name[i]); + if(ptr_begin != NULL) { + ptr_end = strstr(ptr_begin, ","); + if(ptr_end == NULL) { + ptr_end = strstr(ptr_begin, "}"); + if(ptr_end == NULL) + return 0; + } + value_length = ptr_end - ptr_begin - 4 - strlen(parameters_name[i]); + ptr_begin += 3 + strlen(parameters_name[i]); + memset(value, '\0', 16); + strncpy(value, ptr_begin, value_length); + parameters_value[i] = atof(value); + } + } + /* + printf("parameters are:\n"); + for (i = 0; i <= 8; i++) { + printf("%s:%f\n", parameters_name[i], parameters_value[i]); + } + */ + return 1; +} \ No newline at end of file diff --git a/Client/src/api/src/mf_api.h b/Client/src/api/src/mf_api.h new file mode 100644 index 0000000..43f16af --- /dev/null +++ b/Client/src/api/src/mf_api.h @@ -0,0 +1,41 @@ +#ifndef _MF_API_H +#define _MF_API_H + +#define MAX_NUM_METRICS 3 +#define NAME_LENGTH 32 + + +typedef struct metrics_t { + long sampling_interval[MAX_NUM_METRICS]; //in milliseconds + char metrics_names[MAX_NUM_METRICS][NAME_LENGTH]; //user defined metrics + int num_metrics; + int local_data_storage; +} metrics; + +extern int running; +extern int keep_local_data_flag; +extern char parameters_name[9][32]; +extern float parameters_value[9]; + +int mf_user_metric(char *metric_name, char *value); +/* +Get the pid, and setup the DataPath for data storage +For each metric, create a thread, open a file for data storage, and start sampling the metrics periodically. +Return the path of data files +*/ +char *mf_start(char *server, char *platform_id, metrics *m); + +/* +Stop threads. +Close all the files for data storage +*/ +void mf_end(void); + +/* +Generate the execution_id. +Send the monitoring data in all the files to mf_server. +Return the execution_id +*/ +char *mf_send(char *server, char *application_id, char *component_id, char *platform_id); + +#endif /* _MF_API_H */ \ No newline at end of file diff --git a/Client/src/api/src/power_monitor.c b/Client/src/api/src/power_monitor.c new file mode 100644 index 0000000..840d30b --- /dev/null +++ b/Client/src/api/src/power_monitor.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "power_monitor.h" +#include "mf_api.h" + +int power_monitor(int pid, char *DataPath, long sampling_interval) +{ + /*create and open the file*/ + char FileName[256] = {'\0'}; + sprintf(FileName, "%s/%s", DataPath, METRIC_NAME_3); + FILE *fp = fopen(FileName, "a"); //append data to the end of the file + if (fp == NULL) { + printf("ERROR: Could not create file: %s\n", FileName); + exit(0); + } + struct timespec timestamp_before, timestamp_after; + double timestamp_ms; + float duration, sys_cpu_power, pid_cpu_power, pid_mem_power, pid_disk_power; + + pid_stats_info before, after, delta; + + int fd = create_perf_stat_counter(pid); + if(fd <= 0) + exit(0); + + if(read_and_check(fd, pid, &before) <= 0) + exit(0); + + /*in a loop do data sampling and write into the file*/ + while(running) { + /*get before timestamp in ms*/ + clock_gettime(CLOCK_REALTIME, ×tamp_before); + + usleep(sampling_interval * 1000); + + if(read_and_check(fd, pid, &after) <= 0) + exit(0); + + /*get after timestamp in ms*/ + clock_gettime(CLOCK_REALTIME, ×tamp_after); + + /*calculate the increments of counters; update the values before and after */ + if(calcualte_and_update(&before, &after, &delta) <= 0) + continue; + /* calculate the time interval in seconds */ + duration = timestamp_after.tv_sec - timestamp_before.tv_sec + ((timestamp_after.tv_nsec - timestamp_before.tv_nsec) / 1.0e9); + /* system-wide cpu power in milliwatt */ + sys_cpu_power = delta.sys_cpu_energy * delta.sys_runtime / (delta.sys_itv * duration); + /* pid-based cpu power in milliwatt */ + pid_cpu_power = sys_cpu_power * delta.pid_runtime / delta.sys_runtime; + /* pid-based memory access power in milliwatt */ + pid_mem_power = ((delta.pid_read_bytes + delta.pid_write_bytes - delta.pid_cancelled_writes) / parameters_value[4] + delta.pid_l2_cache_misses) * + parameters_value[3] * parameters_value[2] * 1.0e-6 / duration; + /* pid-based disk access power in milliwatt */ + pid_disk_power = (delta.pid_read_bytes * parameters_value[5] + (delta.pid_write_bytes - delta.pid_cancelled_writes) * parameters_value[6]) / + (1024 * duration); + + timestamp_ms = timestamp_after.tv_sec * 1000.0 + (double)(timestamp_after.tv_nsec / 1.0e6); + + fprintf(fp, "\"local_timestamp\":\"%.1f\", \"%s\":%.3f, \"%s\":%.3f, \"%s\":%.3f, \"%s\":%.3f\n", timestamp_ms, + "total_CPU_power", sys_cpu_power, + "process_CPU_power", pid_cpu_power, + "process_mem_power", pid_mem_power, + "process_disk_power", pid_disk_power); + } + /*close the file*/ + fclose(fp); + return 1; +} + +/* init perf counter for hardware cache misses + return the file descriptor for further read operations */ +int create_perf_stat_counter(int pid) +{ + struct perf_event_attr attr; //cache miss + memset(&attr, 0, sizeof(struct perf_event_attr)); + attr.type = PERF_TYPE_HARDWARE; + attr.config = PERF_COUNT_HW_CACHE_MISSES; + attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; + attr.inherit = 1; + attr.disabled = 0; + attr.enable_on_exec = 1; + attr.size = sizeof(attr); + + /* This measures the specified process/thread on any CPU; + return the file descriptor for the counter */ + + return syscall(__NR_perf_event_open, &attr, pid, -1, -1, 0); +} + +/* read from /proc filesystem all statistics; + get the cpu energy consumption based on cpu freq statistics; + read from perf counter the hardware cache misses */ +int read_and_check(int fd, int pid, pid_stats_info *info) +{ + if(read_pid_time(pid, info) <= 0) + return 0; + + if(read_pid_io(pid, info) <=0 ) + return 0; + + if(read_sys_time(info) <= 0) + return 0; + + if(cpu_freq_stat(info) <= 0) + return 0; + + info->pid_l2_cache_misses = read_perf_counter(fd); + if(info->pid_l2_cache_misses <= 0) + return 0; + + return 1; +} + +/* check if values are increasing; calculate the differences in the time interval; update the before values with after values */ +int calcualte_and_update(pid_stats_info *before, pid_stats_info *after, pid_stats_info *delta) +{ + if (after->sys_itv <= before->sys_itv) + return 0; + if (after->sys_runtime <= before->sys_runtime) + return 0; + + delta->sys_itv = after->sys_itv - before->sys_itv; + delta->sys_runtime = after->sys_runtime - before->sys_runtime; + delta->pid_runtime = after->pid_runtime - before->pid_runtime; + delta->pid_read_bytes = after->pid_read_bytes - before->pid_read_bytes; + delta->pid_write_bytes = after->pid_write_bytes - before->pid_write_bytes; + delta->pid_cancelled_writes = after->pid_cancelled_writes - before->pid_cancelled_writes; + delta->pid_l2_cache_misses = after->pid_l2_cache_misses - before->pid_l2_cache_misses; + delta->sys_cpu_energy = after->sys_cpu_energy - before->sys_cpu_energy; + + memcpy(before, after, sizeof(pid_stats_info)); + return 1; +} + +/* read the process runtime from /proc/[pid]/stat */ +int read_pid_time(int pid, pid_stats_info *info) +{ + FILE *fp; + char line[1024]; + char pid_cpu_file[128] = {'\0'}; + char tmp_str[32]; + char tmp_char; + unsigned long long tmp, pid_utime, pid_stime; + + sprintf(pid_cpu_file, "/proc/%d/stat", pid); + fp = fopen(pid_cpu_file, "r"); + + if(fp == NULL) { + printf("ERROR: Could not open file %s\n", pid_cpu_file); + return 0; + } + if(fgets(line, 1024, fp) != NULL) { + sscanf(line, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu", + (int *)&tmp, tmp_str, &tmp_char, (int *)&tmp, (int *)&tmp, (int *)&tmp, (int *)&tmp, (int *)&tmp, + (unsigned int *)&tmp, (unsigned long *)&tmp, (unsigned long *)&tmp, (unsigned long *)&tmp, + (unsigned long *)&tmp, (unsigned long *)&pid_utime, (unsigned long *)&pid_stime); + } + + info->pid_runtime = pid_utime + pid_stime; + fclose(fp); + return 1; +} + +/* read the process read_bytes, write_bytes, and cancelled_writes from /proc/[pid]/io */ +int read_pid_io(int pid, pid_stats_info *info) +{ + FILE *fp; + char line[128]; + char disk_file[128] = {'\0'}; + + sprintf(disk_file, "/proc/%d/io", pid); + fp = fopen(disk_file, "r"); + + if(fp == NULL) { + printf("ERROR: Could not open file %s\n", disk_file); + return 0; + } + while (fgets(line, 128, fp) != NULL) { + if (!strncmp(line, "read_bytes:", 11)) { + sscanf(line + 12, "%llu", &info->pid_read_bytes); + } + else if (!strncmp(line, "write_bytes:", 12)) { + sscanf(line + 13, "%llu", &info->pid_write_bytes); + } + else if (!strncmp(line, "cancelled_write_bytes:", 22)) { + sscanf(line + 23, "%llu", &info->pid_cancelled_writes); + } + } + fclose(fp); + return 1; +} + +/* read the system itv and runtime from /proc/stat*/ +int read_sys_time(pid_stats_info *info) +{ + FILE *fp; + char line[128]; + char cpu_file[128] = "/proc/stat"; + unsigned long long cpu_user, cpu_nice, cpu_sys, cpu_idle, cpu_iowait, cpu_hardirq, cpu_softirq, cpu_steal; + + fp = fopen(cpu_file, "r"); + + if(fp == NULL) { + printf("ERROR: Could not open file %s\n", cpu_file); + return 0; + } + if(fgets(line, 1024, fp) != NULL) { + sscanf(line+5, "%llu %llu %llu %llu %llu %llu %llu %llu", + &cpu_user, + &cpu_nice, + &cpu_sys, + &cpu_idle, + &cpu_iowait, + &cpu_hardirq, + &cpu_softirq, + &cpu_steal); + } + info->sys_itv = cpu_user + cpu_nice + cpu_sys + cpu_idle + cpu_iowait + cpu_hardirq + cpu_softirq + cpu_steal; + info->sys_runtime = cpu_user + cpu_sys; + fclose(fp); + return 1; +} + +/* get the cpu freq counting and return the cpu energy since the last call of the function */ +int cpu_freq_stat(pid_stats_info *info) +{ + /* + read the system cpu energy based on given max- and min- cpu energy, and frequencies statistics + */ + FILE *fp; + char line[32] = {'\0'}; + DIR *dir; + int i, max_i; + struct dirent *dirent; + char cpu_freq_file[128] = {'\0'}; + + float energy_each, energy_total; + unsigned long long tmp; + unsigned long long freqs[16]; + + /* + check if system support cpu freq counting + */ + fp = fopen("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", "r"); + if(fp == NULL) { + printf("ERROR: CPU frequency statistics are not supported.\n"); + return 0; + } + + energy_total = 0.0; + float power_range = parameters_value[0] - parameters_value[1]; + + dir = opendir("/sys/devices/system/cpu"); + if(!dir) { + printf("ERROR: Could not open directory /sys/devices/system/cpu\n"); + return 0; + } + + while ((dirent = readdir(dir))) { + /* for each entry name starting by cpuxx */ + if (strncmp(dirent->d_name,"cpu", 3) != 0) + continue; + sprintf(cpu_freq_file, "/sys/devices/system/cpu/%s/cpufreq/stats/time_in_state", dirent->d_name); + fp = fopen(cpu_freq_file, "r"); + + if(!fp) + continue; + + for (i = 0; !feof(fp) && (i <= 15); i++) { + if(fgets(line, 32, fp) == NULL) + break; + sscanf(line, "%llu %llu", &tmp, &freqs[i]); + /* each line has a pair like "