├── .clang-format
├── .clang-tidy
├── .dockerignore
├── .github
├── chglog
│ ├── CHANGELOG.tpl.md
│ └── config.yml
├── dependabot.yml
└── workflows
│ ├── build.yml
│ ├── codeql-analysis.yml
│ └── release.yml
├── .gitignore
├── CMakeLists.txt
├── CODEOWNERS
├── Dockerfile
├── LICENSE
├── README.md
├── cmake
└── FindLibPFM.cmake
├── docker
└── entrypoint.sh
└── src
├── config.c
├── config.h
├── config_cli.c
├── config_cli.h
├── config_json.c
├── config_json.h
├── events.c
├── events.h
├── hwinfo.c
├── hwinfo.h
├── payload.c
├── payload.h
├── perf.c
├── perf.h
├── pmu.c
├── pmu.h
├── report.c
├── report.h
├── sensor.c
├── storage.c
├── storage.h
├── storage_csv.c
├── storage_csv.h
├── storage_mongodb.c
├── storage_mongodb.h
├── storage_null.c
├── storage_null.h
├── storage_socket.c
├── storage_socket.h
├── target.c
├── target.h
├── target_docker.c
├── target_docker.h
├── target_kubernetes.c
├── target_kubernetes.h
├── util.c
├── util.h
└── version.h
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Webkit
3 | Language: Cpp
4 | ColumnLimit: 140
5 | SortIncludes: false
6 | AlignAfterOpenBracket: Align
7 | PointerAlignment: Right
8 | BinPackParameters: true
9 | BinPackArguments: true
10 | BreakStringLiterals: false
11 | AlwaysBreakAfterDefinitionReturnType: TopLevel
12 | AlwaysBreakAfterReturnType: TopLevel
13 | AlwaysBreakBeforeMultilineStrings: false
14 | SpaceAfterCStyleCast: true
15 | Cpp11BracedListStyle: true
16 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | Checks: '-*,bugprone-*,cert-*,clang-analyzer-*,misc-*,performance-*,portability-*,-bugprone-easily-swappable-parameters,-bugprone-unused-return-value,-cert-err33-c,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,-misc-include-cleaner'
3 | WarningsAsErrors: '*'
4 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # CMake common build paths:
2 | build/
3 | localbuild/
4 |
--------------------------------------------------------------------------------
/.github/chglog/CHANGELOG.tpl.md:
--------------------------------------------------------------------------------
1 | {{ range .Versions }}
2 |
3 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }})
4 |
5 | {{ range .CommitGroups -}}
6 | ### {{ .Title }}
7 |
8 | {{ range .Commits -}}
9 | * {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ upperFirst .Subject }}
10 | {{ end }}
11 | {{ end -}}
12 |
13 | {{- if .RevertCommits -}}
14 | ### Reverts
15 |
16 | {{ range .RevertCommits -}}
17 | * {{ .Revert.Header }}
18 | {{ end }}
19 | {{ end -}}
20 |
21 | {{- if .NoteGroups -}}
22 | {{ range .NoteGroups -}}
23 | ### {{ .Title }}
24 |
25 | {{ range .Notes }}
26 | {{ upperFirst .Body }}
27 | {{ end }}
28 | {{ end -}}
29 | {{ end -}}
30 | {{ end -}}
31 |
--------------------------------------------------------------------------------
/.github/chglog/config.yml:
--------------------------------------------------------------------------------
1 | style: github
2 | template: CHANGELOG.tpl.md
3 | info:
4 | title: CHANGELOG
5 | repository_url: https://github.com/powerapi-ng/hwpc-sensor
6 | options:
7 | commits:
8 | filters:
9 | Type:
10 | - feat
11 | - fix
12 | - perf
13 | - refactor
14 | - style
15 | - docs
16 | - test
17 | - build
18 | - ci
19 | - chore
20 | commit_groups:
21 | title_maps:
22 | feat: Features
23 | fix: Bug Fixes
24 | perf: Performance Improvements
25 | refactor: Code Refactoring
26 | docs: Documentation
27 | test: Tests
28 | build: Build System
29 | ci: Continuous Integration
30 | chore: Miscellaneous Chores
31 | header:
32 | pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\/\\s]*)\\))?\\:\\s(.*)$"
33 | pattern_maps:
34 | - Type
35 | - Scope
36 | - Subject
37 | notes:
38 | keywords:
39 | - BREAKING CHANGE
40 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 | labels:
9 | - "dependencies"
10 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | env:
10 | BUILD_TYPE: Debug
11 |
12 | jobs:
13 | cmake-build:
14 | runs-on: ubuntu-latest
15 | strategy:
16 | matrix:
17 | compiler: ["gcc", "clang"]
18 |
19 | steps:
20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21 |
22 | - name: Install dependencies
23 | run: |
24 | sudo apt-get update
25 | sudo apt-get install -y libczmq-dev libpfm4-dev libjson-c-dev libmongoc-dev
26 |
27 | - name: Configure CMake
28 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=${{matrix.compiler}} -DCMAKE_C_CLANG_TIDY=clang-tidy
29 |
30 | - name: Build
31 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
32 |
33 | container-build:
34 | runs-on: ubuntu-latest
35 |
36 | steps:
37 | - name: Setup Docker buildx
38 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
39 |
40 | - name: Build image
41 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
42 | with:
43 | push: false
44 | provenance: false
45 | load: true
46 | tags: localbuild/hwpc-sensor:sha-${{ github.sha }}
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | analyze:
11 | name: Analyze
12 | runs-on: ubuntu-latest
13 | permissions:
14 | actions: read
15 | contents: read
16 | security-events: write
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | language: [ 'cpp' ]
21 |
22 | steps:
23 | - name: Checkout repository
24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
25 |
26 | - name: Install dependencies
27 | run: |
28 | sudo apt-get update
29 | sudo apt-get install -y libczmq-dev libpfm4-dev libjson-c-dev libmongoc-dev
30 |
31 | - name: Initialize CodeQL
32 | uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
33 | with:
34 | languages: ${{ matrix.language }}
35 | queries: security-and-quality
36 |
37 | - name: Autobuild
38 | uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
39 |
40 | - name: Perform CodeQL Analysis
41 | uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
42 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags: [ 'v*.*.*' ]
6 |
7 | jobs:
8 |
9 | docker-image:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: read
13 | packages: write
14 |
15 | steps:
16 | - name: Setup Docker buildx
17 | uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
18 |
19 | - name: Log in to Docker Hub registry
20 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
21 | with:
22 | registry: docker.io
23 | username: ${{ vars.DOCKER_HUB_USERNAME }}
24 | password: ${{ secrets.DOCKER_HUB_TOKEN }}
25 |
26 | - name: Log in to GitHub Container Registry
27 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
28 | with:
29 | registry: ghcr.io
30 | username: ${{ github.actor }}
31 | password: ${{ secrets.GITHUB_TOKEN }}
32 |
33 | - name: Extract Docker metadata
34 | id: meta
35 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
36 | with:
37 | images: |
38 | docker.io/powerapi/hwpc-sensor
39 | ghcr.io/powerapi-ng/hwpc-sensor
40 | tags: |
41 | type=semver,pattern={{version}}
42 |
43 | - name: Build and push Docker image
44 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
45 | id: build-and-push
46 | with:
47 | push: true
48 | provenance: false
49 | tags: ${{ steps.meta.outputs.tags }}
50 | labels: ${{ steps.meta.outputs.labels }}
51 | build-args: |
52 | BUILD_TYPE=Release
53 |
54 | github-release:
55 | name: Publish GitHub release
56 | runs-on: ubuntu-latest
57 | needs: docker-image
58 | permissions:
59 | contents: write
60 | env:
61 | CHGLOG_VERSION: "0.15.4"
62 |
63 | steps:
64 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
65 | with:
66 | fetch-depth: 0
67 |
68 | - name: Generate version changelog
69 | run: |
70 | set -euo pipefail
71 | export BASE_URL="https://github.com/git-chglog/git-chglog/releases/download"
72 | export FILENAME="git-chglog_${CHGLOG_VERSION}_linux_amd64.tar.gz"
73 | curl -fsSL "${BASE_URL}/v${CHGLOG_VERSION}/${FILENAME}" |sudo tar xz --no-same-owner -C /usr/local/bin git-chglog
74 | git-chglog --config .github/chglog/config.yml --output CHANGELOG.md "${GITHUB_REF_NAME}"
75 |
76 | - name: Create GitHub release
77 | uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
78 | with:
79 | body_path: CHANGELOG.md
80 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | # Build dirs
55 | build/
56 | localbuild/
57 | dockerbuild/
58 |
59 | # CMake
60 | compile_commands.json
61 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13)
2 | project(hwpc-sensor LANGUAGES CXX)
3 |
4 | option(WITH_MONGODB "Build with support for MongoDB storage module" ON)
5 |
6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
7 |
8 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
9 |
10 | add_compile_options(-Werror -Wall -Wextra -Wformat=2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE)
11 | add_link_options(-pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack -Wl,-z,defs -Wl,--as-needed)
12 |
13 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
14 | # These warnings need to be suppressed temporarily, as the only fix is to rewrite the code in C++
15 | add_compile_options(-Wno-deprecated -Wno-c99-designator -Wno-vla-cxx-extension)
16 | endif()
17 |
18 | if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
19 | add_compile_options(-Og -fsanitize=address,undefined -fno-omit-frame-pointer)
20 | add_link_options(-fsanitize=address,undefined)
21 | endif()
22 |
23 | set(SENSOR_SOURCES
24 | src/config_cli.c
25 | src/config_json.c
26 | src/config.c
27 | src/util.c
28 | src/target.c
29 | src/target_docker.c
30 | src/target_kubernetes.c
31 | src/pmu.c
32 | src/events.c
33 | src/hwinfo.c
34 | src/payload.c
35 | src/report.c
36 | src/perf.c
37 | src/storage.c
38 | src/storage_null.c
39 | src/storage_csv.c
40 | src/storage_socket.c
41 | src/sensor.c
42 | )
43 |
44 | find_package(LibPFM REQUIRED)
45 | find_package(PkgConfig)
46 | pkg_check_modules(CZMQ REQUIRED libczmq)
47 | pkg_check_modules(JSONC REQUIRED json-c)
48 |
49 | if(WITH_MONGODB)
50 | pkg_check_modules(MONGOC REQUIRED libmongoc-1.0)
51 | list(APPEND SENSOR_SOURCES src/storage_mongodb.c)
52 | add_compile_definitions(HAVE_MONGODB)
53 | endif()
54 |
55 | if(DEFINED ENV{GIT_TAG} AND DEFINED ENV{GIT_REV})
56 | add_compile_definitions(VERSION_GIT_TAG="$ENV{GIT_TAG}" VERSION_GIT_REV="$ENV{GIT_REV}")
57 | endif()
58 |
59 | add_executable(hwpc-sensor "${SENSOR_SOURCES}")
60 |
61 | foreach(src ${SENSOR_SOURCES})
62 | set_source_files_properties(${src} PROPERTIES LANGUAGE CXX)
63 | endforeach()
64 |
65 | target_compile_features(hwpc-sensor PUBLIC cxx_std_20)
66 | set_target_properties(hwpc-sensor PROPERTIES CXX_EXTENSIONS OFF LINKER_LANGUAGE CXX)
67 |
68 | target_include_directories(hwpc-sensor SYSTEM PRIVATE "${LIBPFM_INCLUDE_DIRS}" "${CZMQ_INCLUDE_DIRS}" "${JSONC_INCLUDE_DIRS}" "${MONGOC_INCLUDE_DIRS}")
69 | target_link_libraries(hwpc-sensor "${LIBPFM_LIBRARIES}" "${CZMQ_LIBRARIES}" "${JSONC_LIBRARIES}" "${MONGOC_LIBRARIES}")
70 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Default owner for everything in the repo.
2 | * @powerapi-ng/oss-maintainers
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # sensor builder image (build tools + development dependencies):
2 | FROM ubuntu:24.04 as sensor-builder
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ARG BUILD_TYPE=Debug
5 | ARG MONGODB_SUPPORT=ON
6 | RUN apt update && \
7 | apt install -y build-essential git clang-tidy cmake pkg-config libczmq-dev libpfm4-dev libjson-c-dev libsystemd-dev uuid-dev && \
8 | echo "${MONGODB_SUPPORT}" |grep -iq "on" && apt install -y libmongoc-dev || true
9 | COPY . /usr/src/hwpc-sensor
10 | RUN cd /usr/src/hwpc-sensor && \
11 | GIT_TAG=$(git describe --tags --dirty 2>/dev/null || echo "unknown") \
12 | GIT_REV=$(git rev-parse HEAD 2>/dev/null || echo "unknown") \
13 | cmake -B build -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_C_CLANG_TIDY="clang-tidy" -DWITH_MONGODB="${MONGODB_SUPPORT}" && \
14 | cmake --build build --parallel $(getconf _NPROCESSORS_ONLN)
15 |
16 | # sensor runner image (only runtime depedencies):
17 | FROM ubuntu:24.04 as sensor-runner
18 | ENV DEBIAN_FRONTEND=noninteractive
19 | ARG BUILD_TYPE=Debug
20 | ARG MONGODB_SUPPORT=ON
21 | ARG FILE_CAPABILITY=CAP_SYS_ADMIN
22 | RUN useradd -d /opt/powerapi -m powerapi && \
23 | apt update && \
24 | apt install -y libczmq4 libpfm4 libjson-c5 libcap2-bin && \
25 | echo "${MONGODB_SUPPORT}" |grep -iq "on" && apt install -y libmongoc-1.0-0 || true && \
26 | echo "${BUILD_TYPE}" |grep -iq "debug" && apt install -y libasan8 libubsan1 || true && \
27 | rm -rf /var/lib/apt/lists/*
28 | COPY --from=sensor-builder /usr/src/hwpc-sensor/build/hwpc-sensor /usr/bin/hwpc-sensor
29 | RUN setcap "${FILE_CAPABILITY}+ep" /usr/bin/hwpc-sensor && \
30 | setcap -v "${FILE_CAPABILITY}+ep" /usr/bin/hwpc-sensor
31 | COPY docker/entrypoint.sh /entrypoint.sh
32 | ENTRYPOINT ["/entrypoint.sh"]
33 | CMD ["--help"]
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, INRIA
4 | Copyright (c) 2018, University of Lille
5 | All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are met:
9 |
10 | * Redistributions of source code must retain the above copyright notice, this
11 | list of conditions and the following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above copyright notice,
14 | this list of conditions and the following disclaimer in the documentation
15 | and/or other materials provided with the distribution.
16 |
17 | * Neither the name of the copyright holder nor the names of its
18 | contributors may be used to endorse or promote products derived from
19 | this software without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hardware Performance Counters (HwPC) Sensor
2 | This project is a lightweight sensor that monitor the Hardware Performance Counters of the cgroups (i.e. containers, systemd units...) running on a Linux system.
3 |
4 | # About
5 | This open-source project is maintained by the [PowerAPI consortium](https://github.com/powerapi-ng).
6 | To report bugs, submit feature ideas, or post feedback, please use the [Issues section](https://github.com/powerapi-ng/hwpc-sensor/issues) of this repo.
7 |
8 | The documentation is available [on the PowerAPI website](http://powerapi.org).
9 |
10 | # License
11 | This project is licensed under the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
--------------------------------------------------------------------------------
/cmake/FindLibPFM.cmake:
--------------------------------------------------------------------------------
1 | # CMake module for libpfm4
2 | #
3 | # The following variables will be set after configuration:
4 | # LIBPFM_FOUND
5 | # LIBPFM_LIBRARIES
6 | # LIBPFM_INCLUDE_DIRS
7 | # LIBPFM_VERSION
8 |
9 | include(FeatureSummary)
10 | include(FindPackageHandleStandardArgs)
11 |
12 | find_path(LIBPFM_INCLUDE_DIR NAMES perfmon/pfmlib.h)
13 | find_library(LIBPFM_LIBRARY NAMES pfm)
14 |
15 | # Follow symbolic link and try to extract library version from the .so file.
16 | get_filename_component(LIBPFM_LIBRARY_REALPATH "${LIBPFM_LIBRARY}" REALPATH)
17 | string(REGEX MATCH "([0-9]+\\.[0-9]+\\.[0-9]+)$" LIBPFM_VERSION ${LIBPFM_LIBRARY_REALPATH})
18 |
19 | find_package_handle_standard_args(LibPFM REQUIRED_VARS LIBPFM_LIBRARY LIBPFM_INCLUDE_DIR VERSION_VAR LIBPFM_VERSION)
20 |
21 | if (LIBPFM_FOUND)
22 | set(LIBPFM_LIBRARIES "pfm")
23 | set(LIBPFM_INCLUDE_DIRS "${LIBPFM_INCLUDE_DIR}")
24 | mark_as_advanced(LIBPFM_LIBRARIES LIBPFM_INCLUDE_DIRS LIBPFM_VERSION)
25 | endif()
26 |
--------------------------------------------------------------------------------
/docker/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Check if the capabilities associated to the executable are available from the current Bounding set.
4 | # The Bounding set is used because the Permitted/Inheritable/Effective sets are cleared when we switch to an unprivileged user in the image.
5 | #
6 | REQUIRED_CAP=$(/sbin/getcap /usr/bin/hwpc-sensor |sed -e 's/.*\(cap_.*\)[+=].*$/\1/')
7 | REQUIRED_CAP_AVAILABLE=$([ -n "${REQUIRED_CAP}" ] && /sbin/capsh --print |grep "Bounding set =" |grep -iqv "${REQUIRED_CAP}" ; echo $?)
8 | if [ "${REQUIRED_CAP_AVAILABLE}" -eq 0 ]; then
9 | echo >&2 "ERROR: This program requires the '${REQUIRED_CAP^^}' capability to work."
10 | exit 1
11 | fi
12 |
13 | exec /usr/bin/hwpc-sensor "$@"
14 |
--------------------------------------------------------------------------------
/src/config.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include "config.h"
42 | #include "events.h"
43 | #include "storage.h"
44 |
45 |
46 | struct config *
47 | config_create(void)
48 | {
49 | struct config *config = (struct config *) malloc(sizeof(struct config));
50 |
51 | if (!config)
52 | return NULL;
53 |
54 | /* sensor default config */
55 | config->sensor.verbose = 0;
56 | config->sensor.frequency = 1000;
57 | snprintf(config->sensor.cgroup_basepath, PATH_MAX, "%s", "/sys/fs/cgroup");
58 | gethostname(config->sensor.name, HOST_NAME_MAX);
59 |
60 | /* storage default config */
61 | config->storage.type = STORAGE_UNKNOWN;
62 | memset(&config->storage, 0, sizeof(struct config_storage));
63 |
64 | /* events default config */
65 | config->events.system = zhashx_new();
66 | zhashx_set_duplicator(config->events.system, (zhashx_duplicator_fn *) events_group_dup);
67 | zhashx_set_destructor(config->events.system, (zhashx_destructor_fn *) events_group_destroy);
68 |
69 | config->events.containers = zhashx_new();
70 | zhashx_set_duplicator(config->events.containers, (zhashx_duplicator_fn *) events_group_dup);
71 | zhashx_set_destructor(config->events.containers, (zhashx_destructor_fn *) events_group_destroy);
72 |
73 | return config;
74 | }
75 |
76 | static int
77 | check_cgroup_basepath(const char *cgroup_basepath)
78 | {
79 | struct statfs sfs;
80 |
81 | if (statfs(cgroup_basepath, &sfs)) {
82 | zsys_error("config: Failed to get cgroup basepath (%s) information: %s", cgroup_basepath, strerror(errno));
83 | return -1;
84 | }
85 |
86 | if (sfs.f_type == CGROUP_SUPER_MAGIC) {
87 | return 0;
88 | }
89 |
90 | if (sfs.f_type == CGROUP2_SUPER_MAGIC) {
91 | return 0;
92 | }
93 |
94 | if (sfs.f_type == TMPFS_MAGIC) {
95 | zsys_warning("config: You are probably using a unified cgroupv2 basepath on a machine using the legacy cgroupv1 hierarchy!");
96 | }
97 |
98 | zsys_error("config: Invalid cgroup basepath: %s", cgroup_basepath);
99 | return -1;
100 | }
101 |
102 | static int
103 | is_events_group_empty(zhashx_t *events_groups)
104 | {
105 | struct events_group *events_group = NULL;
106 |
107 | for (events_group = (struct events_group *) zhashx_first(events_groups); events_group; events_group = (struct events_group *) zhashx_next(events_groups)) {
108 | if (zlistx_size(events_group->events) == 0) {
109 | zsys_error("config: Events group '%s' is empty", events_group->name);
110 | return -1;
111 | }
112 | }
113 |
114 | return 0;
115 | }
116 |
117 | int
118 | config_validate(struct config *config)
119 | {
120 | const struct config_sensor *sensor = &config->sensor;
121 | const struct config_storage *storage = &config->storage;
122 | const struct config_events *events = &config->events;
123 |
124 | if (!strlen(sensor->name)) {
125 | zsys_error("config: You must provide a sensor name");
126 | return -1;
127 | }
128 |
129 | if (!strlen(sensor->cgroup_basepath)) {
130 | zsys_error("config: You must provide a cgroup basepath");
131 | return -1;
132 | }
133 |
134 | if (check_cgroup_basepath(sensor->cgroup_basepath)) {
135 | return -1;
136 | }
137 |
138 | if (zhashx_size(events->system) == 0 && zhashx_size(events->containers) == 0) {
139 | zsys_error("config: You must provide event(s) to monitor");
140 | return -1;
141 | }
142 |
143 | if (is_events_group_empty(events->system) || is_events_group_empty(events->containers)) {
144 | return -1;
145 | }
146 |
147 | if (storage->type == STORAGE_CSV && !strlen(storage->csv.outdir)) {
148 | zsys_error("config: CSV storage module requires the 'outdir' parameter to be set");
149 | return -1;
150 | }
151 |
152 | if (storage->type == STORAGE_SOCKET && (!strlen(storage->socket.hostname) || !strlen(storage->socket.port))) {
153 | zsys_error("config: Socket storage module requires the 'host' and 'port' parameters to be set");
154 | return -1;
155 | }
156 |
157 | #ifdef HAVE_MONGODB
158 | if (storage->type == STORAGE_MONGODB && (!strlen(storage->mongodb.uri) || !strlen(storage->mongodb.database) || !strlen(storage->mongodb.collection))) {
159 | zsys_error("config: MongoDB storage module requires the 'uri', 'database' and 'collection' parameters to be set");
160 | return -1;
161 | }
162 | #endif
163 |
164 | return 0;
165 | }
166 |
167 | void
168 | config_destroy(struct config *config)
169 | {
170 | if (!config)
171 | return;
172 |
173 | zhashx_destroy(&config->events.containers);
174 | zhashx_destroy(&config->events.system);
175 |
176 | free(config);
177 | }
178 |
--------------------------------------------------------------------------------
/src/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef CONFIG_H
33 | #define CONFIG_H
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | #include "events.h"
40 | #include "storage.h"
41 |
42 | /*
43 | * config_sensor stores sensor specific config.
44 | */
45 | struct config_sensor
46 | {
47 | unsigned int verbose;
48 | unsigned int frequency;
49 | char cgroup_basepath[PATH_MAX];
50 | char name[HOST_NAME_MAX];
51 | };
52 |
53 | /*
54 | * config_storage stores storage specific config.
55 | */
56 | struct config_storage
57 | {
58 | enum storage_type type;
59 | union {
60 | struct {
61 | char outdir[PATH_MAX];
62 | } csv;
63 |
64 | struct {
65 | char hostname[HOST_NAME_MAX];
66 | char port[NI_MAXSERV];
67 | } socket;
68 |
69 | #ifdef HAVE_MONGODB
70 | struct {
71 | char uri[PATH_MAX];
72 | char database[NAME_MAX];
73 | char collection[NAME_MAX];
74 | } mongodb;
75 | #endif
76 | };
77 | };
78 |
79 | /*
80 | * config_events stores events specific config.
81 | */
82 | struct config_events
83 | {
84 | zhashx_t *system; /* char *group_name -> struct events_group *group */
85 | zhashx_t *containers; /* char *group_name -> struct events_group *group */
86 | };
87 |
88 | /*
89 | * config stores the application configuration.
90 | */
91 | struct config
92 | {
93 | struct config_sensor sensor;
94 | struct config_storage storage;
95 | struct config_events events;
96 | };
97 |
98 | /*
99 | * config_create allocate the required resources and setup the default config.
100 | */
101 | struct config *config_create(void);
102 |
103 | /*
104 | * config_validate check the validity of the given config.
105 | */
106 | int config_validate(struct config *config);
107 |
108 | /*
109 | * config_destroy free the allocated memory for the storage of the global config.
110 | */
111 | void config_destroy(struct config *config);
112 |
113 | #endif /* CONFIG_H */
114 |
--------------------------------------------------------------------------------
/src/config_cli.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024, Inria
3 | * Copyright (c) 2024, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include "config_cli.h"
39 | #include "config_json.h"
40 | #include "util.h"
41 |
42 |
43 | const char short_opts[] = "x:vf:p:n:s:c:e:or:U:D:C:P:";
44 | static struct option long_opts[] = {
45 | {"config-file", required_argument, 0, 'x'},
46 | {NULL, 0, NULL, 0}
47 | };
48 |
49 | static int
50 | setup_config_from_file(struct config *config, char *filepath)
51 | {
52 | char *file_extension = NULL;
53 |
54 | errno = 0;
55 | if (access(filepath, R_OK) == -1) {
56 | zsys_error("config: cli: Unable to access configuration file: %s", strerror(errno));
57 | return -1;
58 | }
59 |
60 | file_extension = strrchr(filepath, '.');
61 | if (!file_extension) {
62 | zsys_error("config: cli: Missing extension to configuration file");
63 | return -1;
64 | }
65 |
66 | if (strcasecmp(file_extension, ".json") == 0) {
67 | return config_setup_from_json_file(config, filepath);
68 | }
69 |
70 | zsys_error("config: cli: Unsupported configuration file format: %s", file_extension);
71 | return -1;
72 | }
73 |
74 | static int
75 | setup_cgroup_basepath(struct config *config, const char *cgroup_basepath)
76 | {
77 | if (snprintf(config->sensor.cgroup_basepath, PATH_MAX, "%s", cgroup_basepath) >= PATH_MAX) {
78 | zsys_error("config: cli: Cgroup basepath is too long");
79 | return -1;
80 | }
81 |
82 | return 0;
83 | }
84 |
85 | static int
86 | setup_sensor_name(struct config *config, const char *sensor_name)
87 | {
88 | if (snprintf(config->sensor.name, HOST_NAME_MAX, "%s", sensor_name) >= HOST_NAME_MAX) {
89 | zsys_error("config: cli: Sensor name is too long");
90 | return -1;
91 | }
92 |
93 | return 0;
94 | }
95 |
96 | static int
97 | setup_frequency(struct config *config, const char *value_str)
98 | {
99 | unsigned int frequency;
100 |
101 | if (str_to_uint(value_str, &frequency)) {
102 | zsys_error("config: cli: Frequency value is invalid");
103 | return -1;
104 | }
105 |
106 | config->sensor.frequency = frequency;
107 | return 0;
108 | }
109 |
110 | static int
111 | setup_global_events_group(struct config *config, const char *group_name)
112 | {
113 | struct events_group *events_group = NULL;
114 |
115 | events_group = events_group_create(group_name);
116 | if (!events_group) {
117 | zsys_error("config: cli: Failed to create '%s' global events group");
118 | return -1;
119 | }
120 |
121 | zhashx_insert(config->events.system, group_name, events_group);
122 | events_group_destroy(&events_group); /* The events group are duplicated on insert */
123 | return 0;
124 | }
125 |
126 | static int
127 | setup_cgroups_events_group(struct config *config, const char *group_name)
128 | {
129 | struct events_group *events_group = NULL;
130 |
131 | events_group = events_group_create(group_name);
132 | if (!events_group) {
133 | zsys_error("config: cli: Failed to create '%s' cgroups events group", group_name);
134 | return -1;
135 | }
136 |
137 | zhashx_insert(config->events.containers, group_name, events_group);
138 | events_group_destroy(&events_group); /* The events group are duplicated on insert */
139 | return 0;
140 | }
141 |
142 | static int
143 | setup_cgroups_events_group_type(struct events_group *events_group, enum events_group_monitoring_type type)
144 | {
145 | if (!events_group) {
146 | zsys_error("config: cli: No events group defined before setting type");
147 | return -1;
148 | }
149 |
150 | events_group->type = type;
151 | return 0;
152 | }
153 |
154 | static int
155 | append_event_to_events_group(struct events_group *events_group, const char *event_name)
156 | {
157 | if (!events_group) {
158 | zsys_error("config: cli: No events group defined for event: %s", event_name);
159 | return -1;
160 | }
161 |
162 | if (events_group_append_event(events_group, event_name)) {
163 | zsys_error("config: cli: Failed to add event '%s' to group '%s'", optarg, events_group->name);
164 | return -1;
165 | }
166 | return 0;
167 | }
168 |
169 | static int
170 | setup_storage_module(struct config *config, const char *module_name)
171 | {
172 | enum storage_type type;
173 |
174 | type = storage_module_get_type(module_name);
175 | if (type == STORAGE_UNKNOWN) {
176 | zsys_error("config: cli: Storage module '%s' is invalid or disabled at compile time", module_name);
177 | return -1;
178 | }
179 |
180 | config->storage.type = type;
181 | return 0;
182 | }
183 |
184 | static int
185 | setup_storage_csv_parameters(struct config *config, int opt, const char *value)
186 | {
187 | switch (opt)
188 | {
189 | case 'U': /* Output directory path */
190 | if (snprintf(config->storage.csv.outdir, PATH_MAX, "%s", value) >= PATH_MAX) {
191 | zsys_error("config: cli: CSV output directory path is too long");
192 | return -1;
193 | }
194 | break;
195 |
196 | default:
197 | return -1;
198 | }
199 |
200 | return 0;
201 | }
202 |
203 | static int
204 | setup_storage_socket_parameters(struct config *config, int opt, const char *value)
205 | {
206 | switch (opt)
207 | {
208 | case 'U': /* Destination IP/hostname */
209 | if (snprintf(config->storage.socket.hostname, HOST_NAME_MAX, "%s", value) >= HOST_NAME_MAX) {
210 | zsys_error("config: cli: Socket output host is too long");
211 | return -1;
212 | }
213 | break;
214 |
215 | case 'P': /* Destination port number */
216 | if (snprintf(config->storage.socket.port, NI_MAXSERV, "%s", value) >= NI_MAXSERV) {
217 | zsys_error("config: cli: Socket output port is too long");
218 | return -1;
219 | }
220 | break;
221 |
222 | default:
223 | return -1;
224 | }
225 |
226 | return 0;
227 | }
228 |
229 | #ifdef HAVE_MONGODB
230 | static int
231 | setup_storage_mongodb_parameters(struct config *config, int opt, const char *value)
232 | {
233 | switch (opt)
234 | {
235 | case 'U': /* MongoDB URI (mongodb://x) */
236 | if (snprintf(config->storage.mongodb.uri, PATH_MAX, "%s", value) >= PATH_MAX) {
237 | zsys_error("config: cli: MongoDB URI is too long");
238 | return -1;
239 | }
240 | break;
241 |
242 | case 'D': /* MongoDB Database name */
243 | if (snprintf(config->storage.mongodb.database, NAME_MAX, "%s", value) >= NAME_MAX) {
244 | zsys_error("config: cli: MongoDB database name is too long");
245 | return -1;
246 | }
247 | break;
248 |
249 | case 'C': /* MongoDB Collection name */
250 | if (snprintf(config->storage.mongodb.collection, NAME_MAX, "%s", value) >= NAME_MAX) {
251 | zsys_error("config: cli: MongoDB collection name is too long");
252 | return -1;
253 | }
254 | break;
255 |
256 | default:
257 | return -1;
258 | }
259 |
260 | return 0;
261 | }
262 | #endif
263 |
264 | static int
265 | setup_storage_parameters(struct config *config, int opt, const char *value)
266 | {
267 | switch (config->storage.type)
268 | {
269 | case STORAGE_NULL:
270 | return 0; /* Ignore parameters */
271 |
272 | case STORAGE_CSV:
273 | return setup_storage_csv_parameters(config, opt, value);
274 |
275 | case STORAGE_SOCKET:
276 | return setup_storage_socket_parameters(config, opt, value);
277 |
278 | #ifdef HAVE_MONGODB
279 | case STORAGE_MONGODB:
280 | return setup_storage_mongodb_parameters(config, opt, value);
281 | #endif
282 |
283 | default:
284 | return -1;
285 | }
286 | }
287 |
288 | int
289 | config_setup_from_cli(int argc, char **argv, struct config *config)
290 | {
291 | int option_index = 0;
292 | int opt = -1;
293 | struct events_group *current_events_group = NULL;
294 |
295 | opterr = 0; /* Disable getopt error messages */
296 |
297 | while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) {
298 | switch (opt)
299 | {
300 | case 'x':
301 | if (setup_config_from_file(config, optarg)) {
302 | return -1;
303 | }
304 | break;
305 |
306 | case 'v':
307 | config->sensor.verbose++;
308 | break;
309 |
310 | case 'p':
311 | if (setup_cgroup_basepath(config, optarg)) {
312 | return -1;
313 | }
314 | break;
315 |
316 | case 'n':
317 | if (setup_sensor_name(config, optarg)) {
318 | return -1;
319 | }
320 | break;
321 |
322 | case 'f':
323 | if (setup_frequency(config, optarg)) {
324 | return -1;
325 | }
326 | break;
327 |
328 | case 's':
329 | if (setup_global_events_group(config, optarg)) {
330 | return -1;
331 | }
332 | current_events_group = (struct events_group *) zhashx_lookup(config->events.system, optarg);
333 | break;
334 |
335 | case 'c':
336 | if (setup_cgroups_events_group(config, optarg)) {
337 | return -1;
338 | }
339 | current_events_group = (struct events_group *) zhashx_lookup(config->events.containers, optarg);
340 | break;
341 |
342 | case 'o':
343 | if (setup_cgroups_events_group_type(current_events_group, MONITOR_ONE_CPU_PER_SOCKET)) {
344 | return -1;
345 | }
346 | break;
347 |
348 | case 'e':
349 | if (append_event_to_events_group(current_events_group, optarg)) {
350 | return -1;
351 | }
352 | break;
353 |
354 | case 'r':
355 | if (setup_storage_module(config, optarg)) {
356 | return -1;
357 | }
358 | break;
359 |
360 | case 'U':
361 | case 'D':
362 | case 'C':
363 | case 'P':
364 | if (setup_storage_parameters(config, opt, optarg)) {
365 | return -1;
366 | }
367 | break;
368 |
369 | default:
370 | zsys_error("config: Argument '%c' is unknown", optopt);
371 | return -1;
372 | }
373 | }
374 |
375 | return 0;
376 | }
377 |
--------------------------------------------------------------------------------
/src/config_cli.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024, Inria
3 | * Copyright (c) 2024, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef CONFIG_CLI_H
33 | #define CONFIG_CLI_H
34 |
35 | #include "config.h"
36 |
37 | /*
38 | * config_setup_from_cli setup the given global config from the command line arguments.
39 | */
40 | int config_setup_from_cli(int argc, char **argv, struct config *config);
41 |
42 | #endif /* CONFIG_CLI_H */
43 |
--------------------------------------------------------------------------------
/src/config_json.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024, Inria
3 | * Copyright (c) 2024, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include "config_json.h"
38 | #include "util.h"
39 |
40 | /*
41 | * JSON_FILE_BUFFER_SIZE is the size of the buffer where the content of the json config file will be stored.
42 | */
43 | #define JSON_FILE_BUFFER_SIZE 4096
44 |
45 |
46 | static int
47 | setup_verbose(struct config *config, json_object *verbose_obj)
48 | {
49 | int verbose;
50 |
51 | errno = 0;
52 | verbose = json_object_get_int(verbose_obj);
53 | if (errno != 0 || verbose < 0) {
54 | zsys_error("config: json: Verbose value is invalid (boolean or positive integer expected)");
55 | return -1;
56 | }
57 |
58 | config->sensor.verbose = (unsigned int) verbose;
59 | return 0;
60 | }
61 |
62 | static int
63 | setup_cgroup_basepath(struct config *config, json_object *cgroup_basepath_obj)
64 | {
65 | const char *cgroup_basepath = NULL;
66 |
67 | cgroup_basepath = json_object_get_string(cgroup_basepath_obj);
68 | if (snprintf(config->sensor.cgroup_basepath, PATH_MAX, "%s", cgroup_basepath) >= PATH_MAX) {
69 | zsys_error("config: json: Cgroup basepath is too long");
70 | return -1;
71 | }
72 |
73 | return 0;
74 | }
75 |
76 | static int
77 | setup_sensor_name(struct config *config, json_object *sensor_name_obj)
78 | {
79 | const char *sensor_name = NULL;
80 |
81 | sensor_name = json_object_get_string(sensor_name_obj);
82 | if (snprintf(config->sensor.name, HOST_NAME_MAX, "%s", sensor_name) >= HOST_NAME_MAX) {
83 | zsys_error("config: json: Sensor name is too long");
84 | return -1;
85 | }
86 |
87 | return 0;
88 | }
89 |
90 | static int
91 | setup_frequency(struct config *config, json_object *frequency_obj)
92 | {
93 | int frequency;
94 |
95 | errno = 0;
96 | frequency = json_object_get_int(frequency_obj);
97 | if (errno != 0 || frequency < 0) {
98 | zsys_error("config: json: Frequency value is invalid (positive integer expected)");
99 | return -1;
100 | }
101 |
102 | config->sensor.frequency = (unsigned int) frequency;
103 | return 0;
104 | }
105 |
106 | static int
107 | setup_storage_type(struct config *config, json_object *storage)
108 | {
109 | json_object *storage_type_obj = NULL;
110 | const char *storage_module_name = NULL;
111 | enum storage_type type;
112 |
113 | if (!json_object_object_get_ex(storage, "type", &storage_type_obj)) {
114 | zsys_error("config: json: The storage module 'type' field is required");
115 | return -1;
116 | }
117 |
118 | storage_module_name = json_object_get_string(storage_type_obj);
119 | type = storage_module_get_type(storage_module_name);
120 | if (type == STORAGE_UNKNOWN) {
121 | zsys_error("config: json: Storage module '%s' is invalid or disabled at compile time", storage_module_name);
122 | return -1;
123 | }
124 |
125 | config->storage.type = type;
126 | return 0;
127 | }
128 |
129 | static int
130 | setup_storage_null_parameters(struct config *config __attribute__((unused)), json_object *storage_obj)
131 | {
132 | json_object_object_foreach(storage_obj, key, value) {
133 | if (!strcasecmp(key, "type")) {
134 | continue;
135 | }
136 | else {
137 | zsys_error("config: json: Invalid parameter '%s' for Null storage module", key);
138 | return -1;
139 | }
140 | }
141 |
142 | return 0;
143 | }
144 |
145 | static int
146 | setup_storage_csv_parameters(struct config *config, json_object *storage_obj)
147 | {
148 | const char *output_dir = NULL;
149 |
150 | json_object_object_foreach(storage_obj, key, value) {
151 | if (!strcasecmp(key, "type")) {
152 | continue; /* This field have already been processed */
153 | }
154 | if (!strcasecmp(key, "directory") || !strcasecmp(key, "outdir")) {
155 | output_dir = json_object_get_string(value);
156 | if (snprintf(config->storage.csv.outdir, PATH_MAX, "%s", output_dir) >= PATH_MAX) {
157 | zsys_error("config: json: CSV output directory path is too long");
158 | return -1;
159 | }
160 | }
161 | else {
162 | zsys_error("config: json: Invalid parameter '%s' for CSV storage module", key);
163 | return -1;
164 | }
165 | }
166 |
167 | return 0;
168 | }
169 |
170 | static int
171 | setup_storage_socket_parameters(struct config *config, json_object *storage_obj)
172 | {
173 | const char *host = NULL;
174 | const char *port = NULL;
175 |
176 | json_object_object_foreach(storage_obj, key, value) {
177 | if (!strcasecmp(key, "type")) {
178 | continue; /* This field have already been processed */
179 | }
180 | else if (!strcasecmp(key, "uri") || !strcasecmp(key, "host")) {
181 | host = json_object_get_string(value);
182 | if (snprintf(config->storage.socket.hostname, HOST_NAME_MAX, "%s", host) >= HOST_NAME_MAX) {
183 | zsys_error("config: json: Socket output host is too long");
184 | return -1;
185 | }
186 | }
187 | else if (!strcasecmp(key, "port")) {
188 | port = json_object_get_string(value);
189 | if (snprintf(config->storage.socket.port, NI_MAXSERV, "%s", port) >= NI_MAXSERV) {
190 | zsys_error("config: json: Socket output port is too long");
191 | return -1;
192 | }
193 | }
194 | else {
195 | zsys_error("config: json: Invalid parameter '%s' for Socket storage module", key);
196 | return -1;
197 | }
198 | }
199 |
200 | return 0;
201 | }
202 |
203 | #ifdef HAVE_MONGODB
204 | static int
205 | setup_storage_mongodb_parameters(struct config *config, json_object *storage_obj)
206 | {
207 | const char *uri = NULL;
208 | const char *database = NULL;
209 | const char *collection = NULL;
210 |
211 | json_object_object_foreach(storage_obj, key, value) {
212 | if (!strcasecmp(key, "type")) {
213 | continue; /* This field have already been processed */
214 | }
215 | else if (!strcasecmp(key, "uri")) {
216 | uri = json_object_get_string(value);
217 | if (snprintf(config->storage.mongodb.uri, PATH_MAX, "%s", uri) >= PATH_MAX) {
218 | zsys_error("config: json: MongoDB URI is too long");
219 | return -1;
220 | }
221 | }
222 | else if (!strcasecmp(key, "database")) {
223 | database = json_object_get_string(value);
224 | if (snprintf(config->storage.mongodb.database, NAME_MAX, "%s", database) >= NAME_MAX) {
225 | zsys_error("config: json: MongoDB database name is too long");
226 | return -1;
227 | }
228 | }
229 | else if (!strcasecmp(key, "collection")) {
230 | collection = json_object_get_string(value);
231 | if (snprintf(config->storage.mongodb.collection, NAME_MAX, "%s", collection) >= NAME_MAX) {
232 | zsys_error("config: json: MongoDB collection name is too long");
233 | return -1;
234 | }
235 | }
236 | else {
237 | zsys_error("config: json: Invalid parameter '%s' for MongoDB storage module", key);
238 | return -1;
239 | }
240 | }
241 |
242 | return 0;
243 | }
244 | #endif
245 |
246 | static int
247 | handle_storage_parameters(struct config *config, json_object *storage_obj)
248 | {
249 | /*
250 | * Each storage module is configured with its own set of fields.
251 | * It is therefore required to know the storage type before processing any field.
252 | */
253 | if (setup_storage_type(config, storage_obj)) {
254 | return -1;
255 | }
256 |
257 | switch (config->storage.type)
258 | {
259 | case STORAGE_NULL:
260 | return setup_storage_null_parameters(config, storage_obj);
261 |
262 | case STORAGE_CSV:
263 | return setup_storage_csv_parameters(config, storage_obj);
264 |
265 | case STORAGE_SOCKET:
266 | return setup_storage_socket_parameters(config, storage_obj);
267 |
268 | #ifdef HAVE_MONGODB
269 | case STORAGE_MONGODB:
270 | return setup_storage_mongodb_parameters(config, storage_obj);
271 | #endif
272 |
273 | default:
274 | return -1;
275 | }
276 | }
277 |
278 | static int
279 | setup_perf_events_group_events(struct events_group *events_group, json_object *events_group_obj)
280 | {
281 | const char *event_name = NULL;
282 |
283 | if (!json_object_is_type(events_group_obj, json_type_array)) {
284 | zsys_error("config: json: Invalid 'events' field type for group '%s'", events_group->name);
285 | return -1;
286 | }
287 |
288 | for (size_t i = 0; i < json_object_array_length(events_group_obj); i++) {
289 | event_name = json_object_get_string(json_object_array_get_idx(events_group_obj, i));
290 | if (events_group_append_event(events_group, event_name)) {
291 | zsys_error("config: json: Failed to add event '%s' to group '%s'", event_name, events_group->name);
292 | return -1;
293 | }
294 | }
295 |
296 | return 0;
297 | }
298 |
299 | static int
300 | setup_perf_events_group_mode(struct events_group *events_group, json_object *mode_obj)
301 | {
302 | const char *mode = NULL;
303 |
304 | mode = json_object_get_string(mode_obj);
305 | if (!strcasecmp(mode, "MONITOR_ONE_CPU_PER_SOCKET") || !strcasecmp(mode, "ONE_CPU_PER_SOCKET")) {
306 | events_group->type = MONITOR_ONE_CPU_PER_SOCKET;
307 | return 0;
308 | }
309 | if (!strcasecmp(mode, "MONITOR_ALL_CPU_PER_SOCKET") || !strcasecmp(mode, "ALL_CPU_PER_SOCKET")) {
310 | events_group->type = MONITOR_ALL_CPU_PER_SOCKET;
311 | return 0;
312 | }
313 |
314 | zsys_error("config: json: Invalid monitoring mode '%s' for events group '%s'", mode, events_group->name);
315 | return -1;
316 | }
317 |
318 | static int
319 | handle_perf_events_group_parameters(const char *events_group_name, json_object *events_group_obj, zhashx_t *events_groups)
320 | {
321 | int ret = -1;
322 | struct events_group *events_group = NULL;
323 |
324 | events_group = events_group_create(events_group_name);
325 | if (!events_group) {
326 | zsys_error("config: json: Failed to create '%s' events group", events_group_name);
327 | return -1;
328 | }
329 |
330 | json_object_object_foreach(events_group_obj, key, value) {
331 | if (!strcasecmp(key, "events")) {
332 | if (setup_perf_events_group_events(events_group, value)) {
333 | goto cleanup;
334 | }
335 | }
336 | else if (!strcasecmp(key, "monitoring_type") || !strcasecmp(key, "mode")) {
337 | if (setup_perf_events_group_mode(events_group, value)) {
338 | goto cleanup;
339 | }
340 | }
341 | else {
342 | zsys_error("config: json: Invalid parameter '%s' for '%s' events group", key, events_group);
343 | goto cleanup;
344 | }
345 | }
346 |
347 | ret = 0;
348 | zhashx_insert(events_groups, events_group_name, events_group);
349 |
350 | cleanup:
351 | events_group_destroy(&events_group); /* The events group are duplicated on insert */
352 | return ret;
353 | }
354 |
355 | static int
356 | handle_perf_events_groups(json_object *events_groups_obj, zhashx_t *events_groups)
357 | {
358 | json_object_object_foreach(events_groups_obj, key, value) {
359 | if (handle_perf_events_group_parameters(key, value, events_groups)) {
360 | return -1;
361 | }
362 | }
363 |
364 | return 0;
365 | }
366 |
367 | static int
368 | process_json_fields(struct config *config, json_object *root)
369 | {
370 | json_object_object_foreach(root, key, value) {
371 | if (!strcasecmp(key, "verbose")) {
372 | if (setup_verbose(config, value)) {
373 | return -1;
374 | }
375 | }
376 | else if (!strcasecmp(key, "name") || !strcasecmp(key, "sensor-name")) {
377 | if (setup_sensor_name(config, value)) {
378 | return -1;
379 | }
380 | }
381 | else if (!strcasecmp(key, "cgroup_basepath") || !strcasecmp(key, "cgroup-basepath")) {
382 | if (setup_cgroup_basepath(config, value)) {
383 | return -1;
384 | }
385 | }
386 | else if (!strcasecmp(key, "frequency")) {
387 | if (setup_frequency(config, value)) {
388 | return -1;
389 | }
390 | }
391 | else if (!strcasecmp(key, "output") || !strcasecmp(key, "storage")) {
392 | if (handle_storage_parameters(config, value)) {
393 | return -1;
394 | }
395 | }
396 | else if (!strcasecmp(key, "system") || !strcasecmp(key, "global")) {
397 | if (handle_perf_events_groups(value, config->events.system)) {
398 | return -1;
399 | }
400 | }
401 | else if (!strcasecmp(key, "container") || !strcasecmp(key, "cgroups")) {
402 | if (handle_perf_events_groups(value, config->events.containers)) {
403 | return -1;
404 | }
405 | }
406 | else {
407 | zsys_error("config: json: Unknown parameter: '%s'", key);
408 | return -1;
409 | }
410 | }
411 |
412 | return 0;
413 | }
414 |
415 | static int
416 | read_file_content(int fd, char *buffer, size_t buffer_size)
417 | {
418 | struct stat sb;
419 | ssize_t read_bytes = 0;
420 |
421 | if (fstat(fd, &sb) == -1) {
422 | zsys_error("config: json: Failed to get configuration file information: %s", strerror(errno));
423 | return -1;
424 | }
425 |
426 | if (!S_ISREG(sb.st_mode)) {
427 | zsys_error("config: json: Configuration file is not a regular file");
428 | return -1;
429 | }
430 |
431 | if (sb.st_size == 0) {
432 | zsys_error("config: json: Configuration file is empty");
433 | return -1;
434 | }
435 |
436 | if (sb.st_size >= (off_t) buffer_size) {
437 | zsys_error("config: json: Configuration file size is too big (current: %lu KB, max: %lu KB)", sb.st_size / 1024, buffer_size / 1024);
438 | return -1;
439 | }
440 |
441 | read_bytes = read(fd, buffer, buffer_size - 1);
442 | if (read_bytes == -1) {
443 | zsys_error("config: json: Failed to read the configuration file: %s", strerror(errno));
444 | return -1;
445 | }
446 |
447 | buffer[read_bytes] = '\0';
448 | return 0;
449 | }
450 |
451 | static void
452 | compute_current_position_from_offset(const char *str, size_t target_offset, size_t *line, size_t *column)
453 | {
454 | *line = 1;
455 | *column = 1;
456 | for (size_t current_offset = 0; current_offset < target_offset; current_offset++)
457 | {
458 | if (str[current_offset] == '\n') {
459 | (*line)++;
460 | *column = 1;
461 | }
462 | else {
463 | (*column)++;
464 | }
465 | }
466 | }
467 |
468 | static int
469 | parse_json_configuration_file_from_fd(int fd, json_object **obj)
470 | {
471 | int ret = -1;
472 | char buffer[JSON_FILE_BUFFER_SIZE] = {};
473 | json_tokener *tok = NULL;
474 | enum json_tokener_error jerr;
475 | size_t line, column;
476 |
477 | if (read_file_content(fd, buffer, JSON_FILE_BUFFER_SIZE)) {
478 | goto error_read_content;
479 | }
480 |
481 | tok = json_tokener_new();
482 | if (!tok) {
483 | zsys_error("config: json: Failed to initialize json tokener");
484 | goto error_init_tokener;
485 | }
486 |
487 | *obj = json_tokener_parse_ex(tok, buffer, (int) strlen(buffer) + 1);
488 | jerr = json_tokener_get_error(tok);
489 |
490 | if (jerr != json_tokener_success) {
491 | compute_current_position_from_offset(buffer, json_tokener_get_parse_end(tok), &line, &column);
492 | zsys_error("config: json: Failed to parse json: %s (line: %lu, column: %lu)", json_tokener_error_desc(jerr), line, column);
493 | goto error_tokener_parse;
494 | }
495 |
496 | ret = 0;
497 |
498 | error_tokener_parse:
499 | json_tokener_free(tok);
500 | error_read_content:
501 | error_init_tokener:
502 | return ret;
503 | }
504 |
505 | int
506 | config_setup_from_json_file(struct config *config, const char *filepath)
507 | {
508 | int ret = -1;
509 | int fd = -1;
510 | json_object *root = NULL;
511 |
512 | fd = open(filepath, O_RDONLY);
513 | if (fd < 0) {
514 | zsys_error("config: json: Failed to open configuration file: %s", strerror(errno));
515 | goto error_open_file;
516 | }
517 |
518 | if (parse_json_configuration_file_from_fd(fd, &root)) {
519 | goto error_parse_file;
520 | }
521 |
522 | if (process_json_fields(config, root)) {
523 | zsys_error("config: json: Failed to process the given configuration file");
524 | goto error_process_fields;
525 | }
526 |
527 | ret = 0;
528 |
529 | error_parse_file:
530 | error_process_fields:
531 | close(fd);
532 | json_object_put(root);
533 | error_open_file:
534 | return ret;
535 | }
536 |
--------------------------------------------------------------------------------
/src/config_json.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024, Inria
3 | * Copyright (c) 2024, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef CONFIG_JSON_H
33 | #define CONFIG_JSON_H
34 |
35 | #include "config.h"
36 |
37 | /*
38 | * config_setup_from_json_file setup the given global config from the a json file.
39 | */
40 | int config_setup_from_json_file(struct config *config, const char *filepath);
41 |
42 | #endif /* CONFIG_JSON_H */
43 |
--------------------------------------------------------------------------------
/src/events.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | #include "events.h"
37 | #include "util.h"
38 |
39 |
40 | static int
41 | setup_msr_perf_event_attr_type(struct perf_event_attr *attr)
42 | {
43 | const char pmu_type_path[PATH_MAX] = "/sys/devices/msr/type";
44 | FILE *f = NULL;
45 | char buffer[16] = {0}; /* uint32 expected */
46 | unsigned int pmu_type = 0;
47 | int ret = -1;
48 |
49 | f = fopen(pmu_type_path, "r");
50 | if (f) {
51 | if (fgets(buffer, sizeof(buffer), f)) {
52 | if (!str_to_uint(buffer, &pmu_type)) {
53 | attr->type = pmu_type;
54 | ret = 0;
55 | }
56 | }
57 |
58 | fclose(f);
59 | }
60 |
61 | return ret;
62 | }
63 |
64 | static int
65 | setup_msr_perf_event_attr_config(const char *event_name, struct perf_event_attr *attr)
66 | {
67 | /* events config from: https://github.com/torvalds/linux/blob/master/arch/x86/events/msr.c */
68 | const char *msr_events_name[] = {"tsc", "aperf", "mperf", "pperf", "smi", "ptsc", "irperf", "cpu_thermal_margin"};
69 | const uint64_t msr_events_config[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
70 | const size_t num_msr_events = sizeof(msr_events_name) / sizeof(msr_events_name[0]);
71 | char event_path[PATH_MAX] = {0};
72 |
73 | for (size_t i = 0; i < num_msr_events; i++) {
74 | if (!strcasecmp(event_name, msr_events_name[i])) {
75 | snprintf(event_path, PATH_MAX, "/sys/devices/msr/events/%s", msr_events_name[i]);
76 | if (!access(event_path, F_OK)) {
77 | attr->config = msr_events_config[i];
78 | return 0;
79 | }
80 | }
81 | }
82 |
83 | return -1;
84 | }
85 |
86 | static int
87 | get_msr_pmu_event_encoding(const char *event_name, struct perf_event_attr *attr)
88 | {
89 | attr->size = sizeof(struct perf_event_attr);
90 | attr->disabled = 1;
91 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_GROUP;
92 |
93 | if (setup_msr_perf_event_attr_type(attr)) return -1;
94 | if (setup_msr_perf_event_attr_config(event_name, attr)) return -1;
95 |
96 | return 0;
97 | }
98 |
99 | static int
100 | setup_perf_event_attr(const char *event_name, struct perf_event_attr *attr)
101 | {
102 | pfm_perf_encode_arg_t arg = {};
103 |
104 | attr->size = sizeof(struct perf_event_attr);
105 | attr->disabled = 1;
106 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_GROUP;
107 |
108 | arg.size = sizeof(pfm_perf_encode_arg_t);
109 | arg.attr = attr;
110 | if (pfm_get_os_event_encoding(event_name, PFM_PLM0 | PFM_PLM3, PFM_OS_PERF_EVENT_EXT, &arg) != PFM_SUCCESS) {
111 | /* fallback to MSR PMU event encoding if libpfm fails */
112 | if (get_msr_pmu_event_encoding(event_name, attr)) {
113 | return -1;
114 | }
115 | }
116 |
117 | return 0;
118 | }
119 |
120 | struct event_config *
121 | event_config_create(const char *event_name)
122 | {
123 | struct perf_event_attr attr = {};
124 | struct event_config *config = NULL;
125 |
126 | if (!setup_perf_event_attr(event_name, &attr)) {
127 | config = (struct event_config *) malloc(sizeof(struct event_config));
128 | if (config) {
129 | snprintf(config->name, NAME_MAX, "%s", event_name);
130 | config->attr = attr;
131 | }
132 | }
133 |
134 | return config;
135 | }
136 |
137 | struct event_config *
138 | event_config_dup(struct event_config *config)
139 | {
140 | struct event_config *copy = NULL;
141 |
142 | if (config) {
143 | copy = (struct event_config *) malloc(sizeof(struct event_config));
144 | if (copy) {
145 | snprintf(copy->name, NAME_MAX, "%s", config->name);
146 | copy->attr = config->attr;
147 | }
148 | }
149 |
150 | return copy;
151 | }
152 |
153 | void
154 | event_config_destroy(struct event_config **config)
155 | {
156 | if (!*config)
157 | return;
158 |
159 | free(*config);
160 | }
161 |
162 | struct events_group *
163 | events_group_create(const char *name)
164 | {
165 | struct events_group *group = (struct events_group *) malloc(sizeof(struct events_group));
166 |
167 | if (group) {
168 | snprintf(group->name, NAME_MAX, "%s", name);
169 | group->type = MONITOR_ALL_CPU_PER_SOCKET; /* by default, monitor all cpu of the available socket(s) */
170 |
171 | group->events = zlistx_new();
172 | zlistx_set_duplicator(group->events, (zlistx_duplicator_fn *) event_config_dup);
173 | zlistx_set_destructor(group->events, (zlistx_destructor_fn *) event_config_destroy);
174 | }
175 |
176 | return group;
177 | }
178 |
179 | struct events_group *
180 | events_group_dup(struct events_group *group)
181 | {
182 | struct events_group *copy = NULL;
183 |
184 | if (group) {
185 | copy = (struct events_group *) malloc(sizeof(struct events_group));
186 | if (copy) {
187 | snprintf(copy->name, NAME_MAX, "%s", group->name);
188 | copy->type = group->type;
189 | copy->events = zlistx_dup(group->events);
190 | }
191 | }
192 |
193 | return copy;
194 | }
195 |
196 | int
197 | events_group_append_event(struct events_group *group, const char *event_name)
198 | {
199 | int ret = -1;
200 | struct event_config *event = NULL;
201 |
202 | if (group) {
203 | event = event_config_create(event_name);
204 | if (event) {
205 | zlistx_add_end(group->events, event);
206 | free(event);
207 | ret = 0;
208 | }
209 | }
210 |
211 | return ret;
212 | }
213 |
214 | void
215 | events_group_destroy(struct events_group **group)
216 | {
217 | if (*group) {
218 | zlistx_destroy(&(*group)->events);
219 | free(*group);
220 | }
221 | }
222 |
223 |
--------------------------------------------------------------------------------
/src/events.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef EVENTS_H
33 | #define EVENTS_H
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | /*
40 | * events_group_monitoring_type stores the possible monitoring type of an events group.
41 | */
42 | enum events_group_monitoring_type
43 | {
44 | MONITOR_ALL_CPU_PER_SOCKET,
45 | MONITOR_ONE_CPU_PER_SOCKET
46 | };
47 |
48 | /*
49 | * event_config is the event configuration container.
50 | */
51 | struct event_config
52 | {
53 | char name[NAME_MAX];
54 | struct perf_event_attr attr;
55 | };
56 |
57 | /*
58 | * events_group is the events group container.
59 | */
60 | struct events_group
61 | {
62 | char name[NAME_MAX];
63 | enum events_group_monitoring_type type;
64 | zlistx_t *events; /* struct event_config *event */
65 | };
66 |
67 | /*
68 | * event_config_create allocate the required resources for the event config container.
69 | */
70 | struct event_config *event_config_create(const char *event_name);
71 |
72 | /*
73 | * event_config_dup duplicate the given event config container.
74 | */
75 | struct event_config *event_config_dup(struct event_config *config);
76 |
77 | /*
78 | * event_config_destroy free the allocated resources of the event config container.
79 | */
80 | void event_config_destroy(struct event_config **config);
81 |
82 | /*
83 | * events_group_create allocate the required resources for the events group container.
84 | */
85 | struct events_group *events_group_create(const char *name);
86 |
87 | /*
88 | * events_group_dup duplicate the given events group container.
89 | */
90 | struct events_group *events_group_dup(struct events_group *group);
91 |
92 | /*
93 | * events_group_append_event get the event attributes from its name (if available) and store it into the events group container.
94 | */
95 | int events_group_append_event(struct events_group *group, const char *event_name);
96 |
97 | /*
98 | * events_group_destroy free the allocated resources of the events group container.
99 | */
100 | void events_group_destroy(struct events_group **group);
101 |
102 | #endif /* EVENTS_H */
103 |
104 |
--------------------------------------------------------------------------------
/src/hwinfo.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | #include "hwinfo.h"
37 | #include "util.h"
38 |
39 | /*
40 | * SYSFS_CPU_PATH stores the path leading to the available CPUs for the system.
41 | */
42 | #define SYSFS_CPU_PATH "/sys/bus/cpu/devices"
43 |
44 | /*
45 | * CPU_ID_REGEX is the regex used to extract the CPU id from its name.
46 | * CPU_ID_REGEX_EXPECTED_MATCHES is the number of expected matches from the regex. (num groups + 1)
47 | */
48 | #define CPU_ID_REGEX "^cpu([0-9]+)$"
49 | #define CPU_ID_REGEX_EXPECTED_MATCHES 2
50 |
51 |
52 | static struct hwinfo_pkg *
53 | hwinfo_pkg_create(void)
54 | {
55 | struct hwinfo_pkg *pkg = (struct hwinfo_pkg *) malloc(sizeof(struct hwinfo_pkg));
56 |
57 | if (!pkg)
58 | return NULL;
59 |
60 | pkg->cpus_id = zlistx_new();
61 | zlistx_set_duplicator(pkg->cpus_id, (zlistx_duplicator_fn *) strdup);
62 | zlistx_set_destructor(pkg->cpus_id, (zlistx_destructor_fn *) ptrfree);
63 |
64 | return pkg;
65 | }
66 |
67 | static struct hwinfo_pkg *
68 | hwinfo_pkg_dup(struct hwinfo_pkg *pkg)
69 | {
70 | struct hwinfo_pkg *pkgcpy = (struct hwinfo_pkg *) malloc(sizeof(struct hwinfo_pkg));
71 |
72 | if (!pkgcpy)
73 | return NULL;
74 |
75 | pkgcpy->cpus_id = zlistx_dup(pkg->cpus_id);
76 |
77 | return pkgcpy;
78 | }
79 |
80 | static void
81 | hwinfo_pkg_destroy(struct hwinfo_pkg **pkg_ptr)
82 | {
83 | if (!*pkg_ptr)
84 | return;
85 |
86 | zlistx_destroy(&(*pkg_ptr)->cpus_id);
87 | free(*pkg_ptr);
88 | *pkg_ptr = NULL;
89 | }
90 |
91 | static int
92 | get_cpu_online_status(const char *cpu_dir)
93 | {
94 | int status = 1;
95 | char path[PATH_MAX] = {};
96 | FILE *f = NULL;
97 | char buffer[2]; /* boolean expected */
98 |
99 | snprintf(path, PATH_MAX, "%s/%s/online", SYSFS_CPU_PATH, cpu_dir);
100 |
101 | f = fopen(path, "r");
102 | if (f) {
103 | if (fgets(buffer, sizeof(buffer), f)) {
104 | if (buffer[0] == '0')
105 | status = 0;
106 | }
107 | fclose(f);
108 | }
109 |
110 | /*
111 | * Certain systems cannot disable some CPUs and the "online" file will not be available.
112 | * In this case, we report the cpu as online.
113 | */
114 | return status;
115 | }
116 |
117 | static char *
118 | get_package_id(const char *cpu_dir)
119 | {
120 | FILE *f = NULL;
121 | char path[PATH_MAX] = {};
122 | char buffer[24]; /* log10(ULLONG_MAX) */
123 | char *id = NULL;
124 |
125 | snprintf(path, PATH_MAX, "%s/%s/topology/physical_package_id", SYSFS_CPU_PATH, cpu_dir);
126 |
127 | f = fopen(path, "r");
128 | if (f) {
129 | if (fgets(buffer, sizeof(buffer), f)) {
130 | id = strndup(buffer, strlen(buffer) - 1);
131 | }
132 | fclose(f);
133 | }
134 |
135 | return id;
136 | }
137 |
138 | static char *
139 | parse_cpu_id_from_name(const char *str)
140 | {
141 | regex_t re = {};
142 | regmatch_t matches[CPU_ID_REGEX_EXPECTED_MATCHES];
143 | char *id = NULL;
144 |
145 | if (!regcomp(&re, CPU_ID_REGEX, REG_EXTENDED)) {
146 | if (!regexec(&re, str, CPU_ID_REGEX_EXPECTED_MATCHES, matches, 0)) {
147 | id = strndup(str + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
148 | }
149 | regfree(&re);
150 | }
151 |
152 | return id;
153 | }
154 |
155 | static int
156 | do_packages_detection(struct hwinfo *hwinfo)
157 | {
158 | int ret = -1;
159 | DIR *dir = NULL;
160 | struct dirent *entry = NULL;
161 | int cpu_online;
162 | char *cpu_id = NULL;
163 | char *pkg_id = NULL;
164 | struct hwinfo_pkg *pkg = NULL;
165 |
166 | dir = opendir(SYSFS_CPU_PATH);
167 | if (!dir) {
168 | zsys_error("hwinfo: failed to open sysfs cpu directory");
169 | return ret;
170 | }
171 |
172 | /* extract information from online cpus */
173 | for (entry = readdir(dir); entry; entry = readdir(dir)) {
174 | if ((entry->d_type & DT_LNK) && (entry->d_name[0] != '.')) {
175 | cpu_online = get_cpu_online_status(entry->d_name);
176 | if (!cpu_online) {
177 | zsys_info("hwinfo: %s is offline and will be ignored", entry->d_name);
178 | continue;
179 | }
180 |
181 | cpu_id = parse_cpu_id_from_name(entry->d_name);
182 | if (!cpu_id) {
183 | zsys_error("hwinfo: failed to parse cpu id for %s", entry->d_name);
184 | goto cleanup;
185 | }
186 |
187 | pkg_id = get_package_id(entry->d_name);
188 | if (!pkg_id) {
189 | zsys_error("hwinfo: failed to parse package id for %s", entry->d_name);
190 | goto cleanup;
191 | }
192 |
193 | /* get cpu pkg or create it if never encountered */
194 | pkg = (struct hwinfo_pkg *) zhashx_lookup(hwinfo->pkgs, pkg_id);
195 | if (!pkg) {
196 | pkg = hwinfo_pkg_create();
197 | if (!pkg) {
198 | zsys_error("hwinfo: failed to allocate package info struct");
199 | goto cleanup;
200 | }
201 |
202 | zhashx_insert(hwinfo->pkgs, pkg_id, pkg);
203 | hwinfo_pkg_destroy(&pkg);
204 | pkg = (struct hwinfo_pkg *) zhashx_lookup(hwinfo->pkgs, pkg_id); /* get the copy the pkg done by zhashx_insert */
205 | }
206 |
207 | zlistx_add_end(pkg->cpus_id, cpu_id);
208 |
209 | free(cpu_id);
210 | cpu_id = NULL;
211 | free(pkg_id);
212 | pkg_id = NULL;
213 | }
214 | }
215 |
216 | ret = 0;
217 |
218 | cleanup:
219 | free(cpu_id);
220 | free(pkg_id);
221 | closedir(dir);
222 | return ret;
223 | }
224 |
225 | int
226 | hwinfo_detect(struct hwinfo *hwinfo)
227 | {
228 | if (do_packages_detection(hwinfo)) {
229 | return -1;
230 | }
231 |
232 | return 0;
233 | }
234 |
235 | struct hwinfo *
236 | hwinfo_create(void)
237 | {
238 | struct hwinfo *hw = (struct hwinfo *) malloc(sizeof(struct hwinfo));
239 |
240 | if (!hw)
241 | return NULL;
242 |
243 | hw->pkgs = zhashx_new();
244 | zhashx_set_duplicator(hw->pkgs, (zhashx_duplicator_fn *) hwinfo_pkg_dup);
245 | zhashx_set_destructor(hw->pkgs, (zlistx_destructor_fn *) hwinfo_pkg_destroy);
246 |
247 | return hw;
248 | }
249 |
250 | struct hwinfo *
251 | hwinfo_dup(struct hwinfo *hwinfo)
252 | {
253 | struct hwinfo *hwinfocpy = (struct hwinfo *) malloc(sizeof(struct hwinfo));
254 |
255 | if (!hwinfocpy)
256 | return NULL;
257 |
258 | hwinfocpy->pkgs = zhashx_dup(hwinfo->pkgs);
259 |
260 | return hwinfocpy;
261 | }
262 |
263 | void
264 | hwinfo_destroy(struct hwinfo *hwinfo)
265 | {
266 | if (!hwinfo)
267 | return;
268 |
269 | zhashx_destroy(&hwinfo->pkgs);
270 | free(hwinfo);
271 | }
272 |
273 |
--------------------------------------------------------------------------------
/src/hwinfo.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef HWINFO_H
33 | #define HWINFO_H
34 |
35 | #include
36 | #include
37 |
38 |
39 | /*
40 | * hwinfo_pkg stores information about the package.
41 | */
42 | struct hwinfo_pkg
43 | {
44 | zlistx_t *cpus_id; /* char *cpu_id */
45 | };
46 |
47 | /*
48 | * hwinfo stores information about the machine hardware.
49 | */
50 | struct hwinfo
51 | {
52 | zhashx_t *pkgs; /* char *pkg_id -> struct hwinfo_pkg *pkg */
53 | };
54 |
55 | /*
56 | * hwinfo_create allocate the needed ressources.
57 | */
58 | struct hwinfo *hwinfo_create(void);
59 |
60 | /*
61 | * hwinfo_detect discover and store the machine hardware topology.
62 | */
63 | int hwinfo_detect(struct hwinfo *hwinfo);
64 |
65 | /*
66 | * hwinfo_dup duplicate the hwinfo struct and its members.
67 | */
68 | struct hwinfo *hwinfo_dup(struct hwinfo *hwinfo);
69 |
70 | /*
71 | * hwinfo_destroy free the allocated memory to store the machine topology.
72 | */
73 | void hwinfo_destroy(struct hwinfo *hwinfo);
74 |
75 | #endif /* HWINFO_H */
76 |
77 |
--------------------------------------------------------------------------------
/src/payload.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "util.h"
36 | #include "payload.h"
37 |
38 | struct payload_cpu_data *
39 | payload_cpu_data_create(void)
40 | {
41 | struct payload_cpu_data *data = (struct payload_cpu_data *) malloc(sizeof(struct payload_cpu_data));
42 |
43 | if (!data)
44 | return NULL;
45 |
46 | data->events = zhashx_new();
47 | zhashx_set_duplicator(data->events, (zhashx_duplicator_fn *) uint64ptrdup);
48 | zhashx_set_destructor(data->events, (zhashx_destructor_fn *) ptrfree);
49 |
50 | return data;
51 | }
52 |
53 | void
54 | payload_cpu_data_destroy(struct payload_cpu_data **data_ptr)
55 | {
56 | if (!*data_ptr)
57 | return;
58 |
59 | zhashx_destroy(&(*data_ptr)->events);
60 | free(*data_ptr);
61 | *data_ptr = NULL;
62 | }
63 |
64 | struct payload_pkg_data *
65 | payload_pkg_data_create(void)
66 | {
67 | struct payload_pkg_data *data = (struct payload_pkg_data *) malloc(sizeof(struct payload_pkg_data));
68 |
69 | if (!data)
70 | return NULL;
71 |
72 | data->cpus = zhashx_new();
73 | zhashx_set_destructor(data->cpus, (zhashx_destructor_fn *) payload_cpu_data_destroy);
74 |
75 | return data;
76 | }
77 |
78 | void
79 | payload_pkg_data_destroy(struct payload_pkg_data **data_ptr)
80 | {
81 | if (!*data_ptr)
82 | return;
83 |
84 | zhashx_destroy(&(*data_ptr)->cpus);
85 | free(*data_ptr);
86 | *data_ptr = NULL;
87 | }
88 |
89 | struct payload_group_data *
90 | payload_group_data_create(void)
91 | {
92 | struct payload_group_data *data = (struct payload_group_data *) malloc(sizeof(struct payload_group_data));
93 |
94 | if (!data)
95 | return NULL;
96 |
97 | data->pkgs = zhashx_new();
98 | zhashx_set_destructor(data->pkgs, (zhashx_destructor_fn *) payload_pkg_data_destroy);
99 |
100 | return data;
101 | }
102 |
103 | void
104 | payload_group_data_destroy(struct payload_group_data **data_ptr)
105 | {
106 | if (!*data_ptr)
107 | return;
108 |
109 | zhashx_destroy(&(*data_ptr)->pkgs);
110 | free(*data_ptr);
111 | *data_ptr = NULL;
112 | }
113 |
114 | struct payload *
115 | payload_create(uint64_t timestamp, const char *target_name)
116 | {
117 | struct payload *payload = (struct payload *) malloc(sizeof(struct payload));
118 |
119 | if (!payload)
120 | return NULL;
121 |
122 | payload->timestamp = timestamp;
123 | payload->target_name = strdup(target_name);
124 | payload->groups = zhashx_new();
125 | zhashx_set_destructor(payload->groups, (zhashx_destructor_fn *) payload_group_data_destroy);
126 |
127 | return payload;
128 | }
129 |
130 | void
131 | payload_destroy(struct payload *payload)
132 | {
133 | if (!payload)
134 | return;
135 |
136 | free(payload->target_name);
137 | zhashx_destroy(&payload->groups);
138 | free(payload);
139 | }
140 |
141 |
--------------------------------------------------------------------------------
/src/payload.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef PAYLOAD_H
33 | #define PAYLOAD_H
34 |
35 | #include
36 |
37 | /*
38 | * payload_cpu_data stores the events values of a cpu.
39 | */
40 | struct payload_cpu_data
41 | {
42 | zhashx_t *events; /* char *event_name -> uint64_t *event_value */
43 | };
44 |
45 | /*
46 | * payload_pkg_data stores the payloads for a cpu package.
47 | */
48 | struct payload_pkg_data
49 | {
50 | zhashx_t *cpus; /* char *cpu_id -> struct payload_cpu_data *cpu_data */
51 | };
52 |
53 | /*
54 | * payload_group_data stores the payloads for an events group.
55 | */
56 | struct payload_group_data
57 | {
58 | zhashx_t *pkgs; /* char *pkg_id -> struct payload_pkg_data *pkg_data */
59 | };
60 |
61 | /*
62 | * payload stores the data collected by the monitoring module for the reporting module.
63 | */
64 | struct payload
65 | {
66 | uint64_t timestamp;
67 | char *target_name;
68 | zhashx_t *groups; /* char *group_name -> struct payload_group_data *group_data */
69 | };
70 |
71 | /*
72 | * payload_create allocate the required resources of a monitoring payload.
73 | */
74 | struct payload *payload_create(uint64_t timestamp, const char *target_name);
75 |
76 | /*
77 | * payload_destroy free the allocated resources of the monitoring payload.
78 | */
79 | void payload_destroy(struct payload *payload);
80 |
81 | /*
82 | * payload_group_data_create allocate the resources of an events group data container.
83 | */
84 | struct payload_group_data *payload_group_data_create(void);
85 |
86 | /*
87 | * payload_group_data_destroy free the allocated resources of the events group data container.
88 | */
89 | void payload_group_data_destroy(struct payload_group_data **data_ptr);
90 |
91 | /*
92 | * payload_pkg_data_create allocate the resources of a package data container.
93 | */
94 | struct payload_pkg_data *payload_pkg_data_create(void);
95 |
96 | /*
97 | * payload_pkg_data_destroy free the allocated resources of the package data container.
98 | */
99 | void payload_pkg_data_destroy(struct payload_pkg_data **data_ptr);
100 |
101 | /*
102 | * payload_cpu_data_create allocate the resources of a cpu data container.
103 | */
104 | struct payload_cpu_data *payload_cpu_data_create(void);
105 |
106 | /*
107 | * payload_cpu_data_destroy free the allocated resources of the cpu data container.
108 | */
109 | void payload_cpu_data_destroy(struct payload_cpu_data **data_ptr);
110 |
111 | #endif /* PAYLOAD_H */
112 |
113 |
--------------------------------------------------------------------------------
/src/perf.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef PERF_H
33 | #define PERF_H
34 |
35 | #include
36 | #include "hwinfo.h"
37 | #include "events.h"
38 |
39 | /*
40 | * perf_config stores the configuration of a perf actor.
41 | */
42 | struct perf_config
43 | {
44 | struct hwinfo *hwinfo;
45 | zhashx_t *events_groups; /* char *group_name -> struct events_group *group_config */
46 | struct target *target;
47 | };
48 |
49 | /*
50 | * perf_group_cpu_context stores the context of an events group for a specific cpu.
51 | */
52 | struct perf_group_cpu_context
53 | {
54 | zlistx_t *perf_fds; /* int *fd */
55 | };
56 |
57 | /*
58 | * perf_group_pkg_context stores the context of an events group for a specific package.
59 | */
60 | struct perf_group_pkg_context
61 | {
62 | zhashx_t *cpus_ctx; /* char *cpu_id -> struct perf_group_cpu_context *cpu_ctx */
63 | };
64 |
65 | /*
66 | * perf_group_context stores the context of an events group.
67 | */
68 | struct perf_group_context
69 | {
70 | struct events_group *config;
71 | zhashx_t *pkgs_ctx; /* char *pkg_id -> struct perf_group_pkg_context *pkg_ctx */
72 | };
73 |
74 | /*
75 | * perf_context stores the context of a perf actor.
76 | */
77 | struct perf_context
78 | {
79 | struct perf_config *config;
80 | const char *target_name;
81 | bool terminated;
82 | zsock_t *pipe;
83 | zsock_t *ticker;
84 | zpoller_t *poller;
85 | zsock_t *reporting;
86 | int cgroup_fd;
87 | zhashx_t *groups_ctx; /* char *group_name -> struct perf_group_context *group_ctx */
88 | };
89 |
90 | /*
91 | * perf_counter_value stores the counter value.
92 | */
93 | struct perf_counter_value {
94 | uint64_t value;
95 | };
96 |
97 | /*
98 | * perf_cpu_report stores the events counter value.
99 | */
100 | struct perf_read_format {
101 | uint64_t nr;
102 | uint64_t time_enabled; /* PERF_FORMAT_TOTAL_TIME_ENABLED flag */
103 | uint64_t time_running; /* PERF_FORMAT_TOTAL_TIME_RUNNING flag */
104 | struct perf_counter_value values[];
105 | };
106 |
107 | /*
108 | * perf_config_create allocate and configure a perf configuration structure.
109 | */
110 | struct perf_config *perf_config_create(struct hwinfo *hwinfo, zhashx_t *events_groups, struct target *target);
111 |
112 | /*
113 | * perf_config_destroy free the resources allocated for the perf configuration structure.
114 | */
115 | void perf_config_destroy(struct perf_config *config);
116 |
117 | /*
118 | * perf_monitoring_actor handle the monitoring of a cgroup using perf_event.
119 | */
120 | void perf_monitoring_actor(zsock_t *pipe, void *args);
121 |
122 | /*
123 | * perf_try_event_open try to open a global counting event using the perf_event_open syscall.
124 | * This is used to check if the perf_event_open syscall is working and the current process is allowed to use it.
125 | */
126 | int perf_try_global_counting_event_open(void);
127 |
128 | #endif /* PERF_H */
129 |
130 |
--------------------------------------------------------------------------------
/src/pmu.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "pmu.h"
36 | #include "util.h"
37 |
38 | int
39 | pmu_initialize(void)
40 | {
41 | if (pfm_initialize() != PFM_SUCCESS) {
42 | return -1;
43 | }
44 |
45 | return 0;
46 | }
47 |
48 | void
49 | pmu_deinitialize(void)
50 | {
51 | pfm_terminate();
52 | }
53 |
54 | struct pmu_info *
55 | pmu_info_create(void)
56 | {
57 | struct pmu_info *pmu = (struct pmu_info *) malloc(sizeof(struct pmu_info));
58 | return pmu;
59 | }
60 |
61 | struct pmu_info *
62 | pmu_info_dup(struct pmu_info *pmu)
63 | {
64 | struct pmu_info *copy = NULL;
65 |
66 | if (pmu) {
67 | copy = (struct pmu_info *) malloc(sizeof(struct pmu_info));
68 | if (copy) {
69 | *copy = *pmu;
70 | }
71 | }
72 |
73 | return copy;
74 | }
75 |
76 | void
77 | pmu_info_destroy(struct pmu_info **pmu)
78 | {
79 | if (!*pmu)
80 | return;
81 |
82 | free(*pmu);
83 | }
84 |
85 | struct pmu_topology *
86 | pmu_topology_create(void)
87 | {
88 | struct pmu_topology *topology = (struct pmu_topology *) malloc(sizeof(struct pmu_topology));
89 |
90 | if (!topology)
91 | return NULL;
92 |
93 | topology->pmus = zlistx_new();
94 | zlistx_set_duplicator(topology->pmus, (zlistx_duplicator_fn *) pmu_info_dup);
95 | zlistx_set_destructor(topology->pmus, (zlistx_destructor_fn *) pmu_info_destroy);
96 |
97 | return topology;
98 | }
99 |
100 | void
101 | pmu_topology_destroy(struct pmu_topology *topology)
102 | {
103 | if (!topology)
104 | return;
105 |
106 | zlistx_destroy(&topology->pmus);
107 | free(topology);
108 | }
109 |
110 | int
111 | pmu_topology_detect(struct pmu_topology *topology)
112 | {
113 | pfm_pmu_t pmu = {};
114 | pfm_pmu_info_t pmu_info = {};
115 |
116 | for (pmu = PFM_PMU_NONE; pmu < PFM_PMU_MAX; pmu = static_cast(pmu + 1)) {
117 | if (pfm_get_pmu_info(pmu, &pmu_info) != PFM_SUCCESS)
118 | continue;
119 |
120 | /* filter to only present pmu */
121 | if (pmu_info.is_present) {
122 | /* rewrite type for unknown PMU */
123 | if (pmu_info.type >= PFM_PMU_TYPE_MAX)
124 | pmu_info.type = PFM_PMU_TYPE_UNKNOWN;
125 |
126 | zlistx_add_end(topology->pmus, &pmu_info);
127 | }
128 | }
129 |
130 | return 0;
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/src/pmu.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef PMU_H
33 | #define PMU_H
34 |
35 | #include
36 | #include
37 |
38 | /*
39 | * pmu_info is the container for the pmu information.
40 | */
41 | struct pmu_info
42 | {
43 | pfm_pmu_info_t info;
44 | };
45 |
46 | /*
47 | * pmu_topology is the container of the supported pmu by the machine.
48 | */
49 | struct pmu_topology
50 | {
51 | zlistx_t *pmus; /* struct pmu_info *info */
52 | };
53 |
54 | /*
55 | * pmu_initialize allocate the resources needed to use the PMUs.
56 | */
57 | int pmu_initialize(void);
58 |
59 | /*
60 | * pmu_deinitialize free the allocated resources needed to use the PMUs.
61 | */
62 | void pmu_deinitialize(void);
63 |
64 | /*
65 | * pmu_info_create allocate the resources needed for a pmu info container.
66 | */
67 | struct pmu_info *pmu_info_create(void);
68 |
69 | /*
70 | * pmu_info_dup duplicate the given pmu info.
71 | */
72 | struct pmu_info *pmu_info_dup(struct pmu_info *pmu);
73 |
74 | /*
75 | * pmu_info_destroy free the allocated resources for the pmu info container.
76 | */
77 | void pmu_info_destroy(struct pmu_info **pmu);
78 |
79 | /*
80 | * pmu_topology_create allocate the resource needed for a pmu topology container.
81 | */
82 | struct pmu_topology *pmu_topology_create(void);
83 |
84 | /*
85 | * pmu_topology_destroy free the allocated resource of the pmu topology container.
86 | */
87 | void pmu_topology_destroy(struct pmu_topology *topology);
88 |
89 | /*
90 | * pmu_topology_detect populate the topology container with the available PMUs.
91 | */
92 | int pmu_topology_detect(struct pmu_topology *topology);
93 |
94 | #endif /* PMU_H */
95 |
96 |
--------------------------------------------------------------------------------
/src/report.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "report.h"
36 | #include "util.h"
37 | #include "hwinfo.h"
38 | #include "events.h"
39 | #include "payload.h"
40 | #include "perf.h"
41 | #include "storage.h"
42 |
43 | struct report_config *
44 | report_config_create(struct storage_module *storage_module)
45 | {
46 | struct report_config *config = (struct report_config *) malloc(sizeof(struct report_config));
47 |
48 | if (!config)
49 | return NULL;
50 |
51 | config->storage = storage_module;
52 |
53 | return config;
54 | }
55 |
56 | void
57 | report_config_destroy(struct report_config *config)
58 | {
59 | if (!config)
60 | return;
61 |
62 | free(config);
63 | }
64 |
65 | static struct report_context *
66 | report_context_create(struct report_config *config, zsock_t *pipe)
67 | {
68 | struct report_context *ctx = (struct report_context *) malloc(sizeof(struct report_context));
69 |
70 | if (!ctx)
71 | return NULL;
72 |
73 | ctx->terminated = false;
74 | ctx->pipe = pipe;
75 | ctx->reporting = zsock_new_pull("inproc://reporting");
76 | ctx->poller = zpoller_new(ctx->pipe, ctx->reporting, NULL);
77 | ctx->config = config;
78 |
79 | return ctx;
80 | }
81 |
82 | static void
83 | report_context_destroy(struct report_context *ctx)
84 | {
85 | if (!ctx)
86 | return;
87 |
88 | zpoller_destroy(&ctx->poller);
89 | zsock_destroy(&ctx->reporting);
90 | free(ctx);
91 | }
92 |
93 | static void
94 | handle_pipe(struct report_context *ctx)
95 | {
96 | char *command = zstr_recv(ctx->pipe);
97 |
98 | if (streq(command, "$TERM")) {
99 | ctx->terminated = true;
100 | zsys_info("reporting: bye!");
101 | }
102 | else {
103 | zsys_error("reporting: invalid pipe command: %s", command);
104 | }
105 |
106 | zstr_free(&command);
107 | }
108 |
109 | static void
110 | handle_reporting(struct report_context *ctx)
111 | {
112 | struct payload *payload = NULL;
113 |
114 | zsock_recv(ctx->reporting, "p", &payload);
115 |
116 | if (!payload)
117 | return;
118 |
119 | if (storage_module_store_report(ctx->config->storage, payload)) {
120 | zsys_error("report: failed to store the report for timestamp=%lu", payload->timestamp);
121 | }
122 |
123 | payload_destroy(payload);
124 | }
125 |
126 | void
127 | reporting_actor(zsock_t *pipe, void *args)
128 | {
129 | struct report_context *ctx = report_context_create((struct report_config *) args, pipe);
130 | zsock_t *which = NULL;
131 |
132 | if (!ctx) {
133 | zsys_error("reporting: cannot create context");
134 | return;
135 | }
136 |
137 | zsock_signal(pipe, 0);
138 |
139 | while (!ctx->terminated) {
140 | which = (zsock_t *) zpoller_wait(ctx->poller, -1);
141 |
142 | if (zpoller_terminated(ctx->poller)) {
143 | break;
144 | }
145 |
146 | if (which == ctx->pipe) {
147 | handle_pipe(ctx);
148 | }
149 | else if (which == ctx->reporting) {
150 | handle_reporting(ctx);
151 | }
152 | }
153 |
154 | report_context_destroy(ctx);
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/src/report.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef REPORT_H
33 | #define REPORT_H
34 |
35 | #include
36 | #include
37 |
38 | /*
39 | * report_config stores the reporting module configuration.
40 | */
41 | struct report_config
42 | {
43 | struct storage_module *storage;
44 | };
45 |
46 | /*
47 | * report_context stores the reporting module execution context.
48 | */
49 | struct report_context
50 | {
51 | struct report_config *config;
52 | bool terminated;
53 | zsock_t *pipe;
54 | zsock_t *reporting;
55 | zpoller_t *poller;
56 | };
57 |
58 | /*
59 | * report_config_create allocate the resource of a report configuration structure.
60 | */
61 | struct report_config *report_config_create(struct storage_module *storage_module);
62 |
63 | /*
64 | * report_config_destroy free the allocated resource of the report configuration structure.
65 | */
66 | void report_config_destroy(struct report_config *config);
67 |
68 | /*
69 | * reporting_actor is the reporting actor entrypoint.
70 | */
71 | void reporting_actor(zsock_t *pipe, void *args);
72 |
73 | #endif /* REPORT_H */
74 |
75 |
--------------------------------------------------------------------------------
/src/sensor.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include "version.h"
42 | #include "config.h"
43 | #include "config_cli.h"
44 | #include "pmu.h"
45 | #include "events.h"
46 | #include "hwinfo.h"
47 | #include "perf.h"
48 | #include "report.h"
49 | #include "target.h"
50 | #include "storage.h"
51 | #include "storage_null.h"
52 | #include "storage_csv.h"
53 | #include "storage_socket.h"
54 |
55 | #ifdef HAVE_MONGODB
56 | #include "storage_mongodb.h"
57 | #endif
58 |
59 | static struct storage_module *
60 | setup_storage_module(struct config *config)
61 | {
62 | switch (config->storage.type)
63 | {
64 | case STORAGE_NULL:
65 | return storage_null_create(config);
66 | case STORAGE_CSV:
67 | return storage_csv_create(config);
68 | case STORAGE_SOCKET:
69 | return storage_socket_create(config);
70 | #ifdef HAVE_MONGODB
71 | case STORAGE_MONGODB:
72 | return storage_mongodb_create(config);
73 | #endif
74 | default:
75 | return NULL;
76 | }
77 | }
78 |
79 | static void
80 | sync_cgroups_running_monitored(struct hwinfo *hwinfo, zhashx_t *container_events_groups, const char *cgroup_basepath, zhashx_t *container_monitoring_actors)
81 | {
82 | zhashx_t *running_targets = NULL; /* char *cgroup_path -> struct target *target */
83 | zactor_t *perf_monitor = NULL;
84 | const char *cgroup_path = NULL;
85 | struct target *target = NULL;
86 | struct perf_config *monitor_config = NULL;
87 |
88 | /* to store running cgroups name and absolute path */
89 | running_targets = zhashx_new();
90 |
91 | /* get running (and identifiable) container(s) */
92 | if (target_discover_running(cgroup_basepath, TARGET_TYPE_EVERYTHING, running_targets)) {
93 | zsys_error("sensor: error when retrieving the running targets.");
94 | goto out;
95 | }
96 |
97 | /* stop monitoring dead container(s) */
98 | for (perf_monitor = (zactor_t *) zhashx_first(container_monitoring_actors); perf_monitor; perf_monitor = (zactor_t *) zhashx_next(container_monitoring_actors)) {
99 | cgroup_path = (const char *) zhashx_cursor(container_monitoring_actors);
100 | target = (struct target *) zhashx_lookup(running_targets, cgroup_path);
101 | if (!target) {
102 | zhashx_freefn(running_targets, cgroup_path, (zhashx_free_fn *) target_destroy);
103 | zhashx_delete(container_monitoring_actors, cgroup_path);
104 | }
105 | }
106 |
107 | /* start monitoring new container(s) */
108 | for (target = (struct target *) zhashx_first(running_targets); target; target = (struct target *) zhashx_next(running_targets)) {
109 | cgroup_path = (const char *) zhashx_cursor(running_targets);
110 | if (!zhashx_lookup(container_monitoring_actors, cgroup_path)) {
111 | monitor_config = perf_config_create(hwinfo, container_events_groups, target);
112 | perf_monitor = zactor_new(perf_monitoring_actor, monitor_config);
113 | zhashx_insert(container_monitoring_actors, cgroup_path, perf_monitor);
114 | } else {
115 | zhashx_freefn(running_targets, cgroup_path, (zhashx_free_fn *) target_destroy);
116 | }
117 | }
118 |
119 | out:
120 | zhashx_destroy(&running_targets);
121 | }
122 |
123 | int
124 | main(int argc, char **argv)
125 | {
126 | int ret = 1;
127 | struct config *config = NULL;
128 | struct utsname kernel_info;
129 | struct pmu_topology *sys_pmu_topology = NULL;
130 | struct pmu_info *pmu = NULL;
131 | struct hwinfo *hwinfo = NULL;
132 | struct storage_module *storage = NULL;
133 | struct report_config reporting_conf = {};
134 | zactor_t *reporting = NULL;
135 | zhashx_t *cgroups_running = NULL; /* char *cgroup_name -> char *cgroup_absolute_path */
136 | zhashx_t *container_monitoring_actors = NULL; /* char *actor_name -> zactor_t *actor */
137 | zsock_t *ticker = NULL;
138 | struct target *system_target = NULL;
139 | struct perf_config *system_monitor_config = NULL;
140 | zactor_t *system_perf_monitor = NULL;
141 |
142 | signal(SIGPIPE, SIG_IGN);
143 |
144 | if (!zsys_init()) {
145 | fprintf(stderr, "czmq: failed to initialize zsys context\n");
146 | return ret;
147 | }
148 |
149 | /* disable limit of maximum czmq sockets */
150 | zsys_set_max_sockets(0);
151 |
152 | /* show build information */
153 | zsys_info("build: version %s (rev: %s)", VERSION_GIT_TAG, VERSION_GIT_REV);
154 |
155 | /* show Kernel information */
156 | if (uname(&kernel_info)) {
157 | zsys_error("uname: failed to get Kernel information");
158 | goto cleanup;
159 | }
160 | zsys_info("uname: %s %s %s %s", kernel_info.sysname, kernel_info.release, kernel_info.version, kernel_info.machine);
161 |
162 | /* check if perf_event is working */
163 | if (perf_try_global_counting_event_open()) {
164 | zsys_error("perf: error while testing the perf_event support");
165 | goto cleanup;
166 | }
167 |
168 | /* initialize the PMU module */
169 | if (pmu_initialize()) {
170 | zsys_error("pmu: cannot initialize the pmu module");
171 | goto cleanup;
172 | }
173 |
174 | /* detect pmu topology */
175 | sys_pmu_topology = pmu_topology_create();
176 | if (!sys_pmu_topology) {
177 | zsys_error("pmu: cannot allocate pmu topology memory");
178 | goto cleanup;
179 | }
180 | if (pmu_topology_detect(sys_pmu_topology)) {
181 | zsys_error("pmu: cannot detect system PMU topology");
182 | goto cleanup;
183 | }
184 | for (pmu = (struct pmu_info *) zlistx_first(sys_pmu_topology->pmus); pmu; pmu = (struct pmu_info *) zlistx_next(sys_pmu_topology->pmus)) {
185 | zsys_info("pmu: found %s '%s' having %d events, %d counters (%d general, %d fixed)",
186 | pmu->info.name,
187 | pmu->info.desc,
188 | pmu->info.nevents,
189 | pmu->info.num_cntrs + pmu->info.num_fixed_cntrs,
190 | pmu->info.num_cntrs,
191 | pmu->info.num_fixed_cntrs);
192 | }
193 |
194 | /* detect machine hardware */
195 | hwinfo = hwinfo_create();
196 | if (!hwinfo) {
197 | zsys_error("hwinfo: error while creating hardware information container");
198 | goto cleanup;
199 | }
200 | if (hwinfo_detect(hwinfo)) {
201 | zsys_error("hwinfo: error while detecting hardware information");
202 | goto cleanup;
203 | }
204 |
205 | /* get application config */
206 | config = config_create();
207 | if (!config) {
208 | zsys_error("config: failed to create config container");
209 | goto cleanup;
210 | }
211 | if (config_setup_from_cli(argc, argv, config)) {
212 | zsys_error("config: failed to parse the provided command-line arguments");
213 | goto cleanup;
214 | }
215 | if (config_validate(config)) {
216 | zsys_error("config: failed to validate config");
217 | goto cleanup;
218 | }
219 |
220 | /* setup storage module */
221 | storage = setup_storage_module(config);
222 | if (!storage) {
223 | zsys_error("sensor: failed to create '%s' storage module", storage_types_name[config->storage.type]);
224 | goto cleanup;
225 | }
226 | if (storage_module_initialize(storage)) {
227 | zsys_error("sensor: failed to initialize storage module");
228 | goto cleanup;
229 | }
230 | if (storage_module_ping(storage)) {
231 | zsys_error("sensor: failed to ping storage module");
232 | storage_module_deinitialize(storage);
233 | goto cleanup;
234 | }
235 |
236 | zsys_info("sensor: configuration is valid, starting monitoring...");
237 |
238 | /* start reporting actor */
239 | reporting_conf = (struct report_config){
240 | .storage = storage
241 | };
242 | reporting = zactor_new(reporting_actor, &reporting_conf);
243 |
244 | /* create ticker publisher socket */
245 | ticker = zsock_new_pub("inproc://ticker");
246 |
247 | /* start system monitoring actor only when needed */
248 | if (zhashx_size(config->events.system)) {
249 | system_target = target_create(TARGET_TYPE_ALL, NULL, NULL);
250 | system_monitor_config = perf_config_create(hwinfo, config->events.system, system_target);
251 | system_perf_monitor = zactor_new(perf_monitoring_actor, system_monitor_config);
252 | }
253 |
254 | /* monitor running containers */
255 | container_monitoring_actors = zhashx_new();
256 | zhashx_set_destructor(container_monitoring_actors, (zhashx_destructor_fn *) zactor_destroy);
257 | while (!zsys_interrupted) {
258 | /* monitor containers only when needed */
259 | if (zhashx_size(config->events.containers)) {
260 | sync_cgroups_running_monitored(hwinfo, config->events.containers, config->sensor.cgroup_basepath, container_monitoring_actors);
261 | }
262 |
263 | /* send clock tick to monitoring actors */
264 | zsock_send(ticker, "s8", "CLOCK_TICK", zclock_time());
265 |
266 | zclock_sleep((int)config->sensor.frequency);
267 | }
268 |
269 | /* clean storage module ressources */
270 | storage_module_deinitialize(storage);
271 |
272 | ret = 0;
273 |
274 | cleanup:
275 | zhashx_destroy(&cgroups_running);
276 | zhashx_destroy(&container_monitoring_actors);
277 | zactor_destroy(&system_perf_monitor);
278 | zactor_destroy(&reporting);
279 | storage_module_destroy(storage);
280 | zsock_destroy(&ticker);
281 | config_destroy(config);
282 | pmu_topology_destroy(sys_pmu_topology);
283 | pmu_deinitialize();
284 | hwinfo_destroy(hwinfo);
285 | zsys_shutdown();
286 | return ret;
287 | }
288 |
--------------------------------------------------------------------------------
/src/storage.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "storage.h"
36 |
37 | const char *storage_types_name[] = {
38 | [STORAGE_UNKNOWN] = "unknown",
39 | [STORAGE_NULL] = "null",
40 | [STORAGE_CSV] = "csv",
41 | [STORAGE_SOCKET] = "socket",
42 | #ifdef HAVE_MONGODB
43 | [STORAGE_MONGODB] = "mongodb",
44 | #endif
45 | };
46 |
47 | enum storage_type
48 | storage_module_get_type(const char *type_name)
49 | {
50 | if (strcasecmp(type_name, storage_types_name[STORAGE_NULL]) == 0) {
51 | return STORAGE_NULL;
52 | }
53 |
54 | if (strcasecmp(type_name, storage_types_name[STORAGE_CSV]) == 0) {
55 | return STORAGE_CSV;
56 | }
57 |
58 | if (strcasecmp(type_name, storage_types_name[STORAGE_SOCKET]) == 0) {
59 | return STORAGE_SOCKET;
60 | }
61 |
62 | #ifdef HAVE_MONGODB
63 | if (strcasecmp(type_name, storage_types_name[STORAGE_MONGODB]) == 0) {
64 | return STORAGE_MONGODB;
65 | }
66 | #endif
67 |
68 | return STORAGE_UNKNOWN;
69 | }
70 |
71 | int
72 | storage_module_initialize(struct storage_module *module)
73 | {
74 | return (*module->initialize)(module);
75 | }
76 |
77 | int
78 | storage_module_ping(struct storage_module *module)
79 | {
80 | return (*module->ping)(module);
81 | }
82 |
83 | int
84 | storage_module_store_report(struct storage_module *module, struct payload *payload)
85 | {
86 | return (*module->store_report)(module, payload);
87 | }
88 |
89 | int
90 | storage_module_deinitialize(struct storage_module *module)
91 | {
92 | return (*module->deinitialize)(module);
93 | }
94 |
95 | void
96 | storage_module_destroy(struct storage_module *module)
97 | {
98 | if (!module)
99 | return;
100 |
101 | (*module->destroy)(module);
102 | free(module);
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/src/storage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef STORAGE_H
33 | #define STORAGE_H
34 |
35 | #include "payload.h"
36 | #include "report.h"
37 |
38 | /*
39 | * storage_type enumeration allows to select a storage type to generate.
40 | */
41 | enum storage_type
42 | {
43 | STORAGE_UNKNOWN,
44 | STORAGE_NULL,
45 | STORAGE_CSV,
46 | STORAGE_SOCKET,
47 | #ifdef HAVE_MONGODB
48 | STORAGE_MONGODB,
49 | #endif
50 | };
51 |
52 | /*
53 | * storage_types_name stores the name (as string) of the supported storage types.
54 | */
55 | extern const char *storage_types_name[];
56 |
57 | /*
58 | * storage_module is a generic interface for storage modules.
59 | */
60 | struct storage_module
61 | {
62 | enum storage_type type;
63 | void *context;
64 | bool is_initialized;
65 | int (*initialize)(struct storage_module *self);
66 | int (*ping)(struct storage_module *self);
67 | int (*store_report)(struct storage_module *self, struct payload *payload);
68 | int (*deinitialize)(struct storage_module *self);
69 | void (*destroy)(struct storage_module *self);
70 | };
71 |
72 | /*
73 | * storage_module_get_type returns the type of the given storage module name.
74 | */
75 | enum storage_type storage_module_get_type(const char *type_name);
76 |
77 | /*
78 | * storage_module_initialize initialize the storage module.
79 | */
80 | int storage_module_initialize(struct storage_module *module);
81 |
82 | /*
83 | * storage_module_ping test if the storage module is working.
84 | */
85 | int storage_module_ping(struct storage_module *module);
86 |
87 | /*
88 | * storage_module_store_report store a report using the storage module.
89 | */
90 | int storage_module_store_report(struct storage_module *module, struct payload *payload);
91 |
92 | /*
93 | * storage_module_deinitialize deinitialize the storage module.
94 | */
95 | int storage_module_deinitialize(struct storage_module *module);
96 |
97 | /*
98 | * storage_module_destroy free the allocated ressources for the storage module.
99 | */
100 | void storage_module_destroy(struct storage_module *module);
101 |
102 | #endif /* STORAGE_H */
103 |
104 |
--------------------------------------------------------------------------------
/src/storage_csv.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include "storage.h"
38 | #include "storage_csv.h"
39 | #include "config.h"
40 |
41 | static void
42 | group_fd_destroy(FILE **fd_ptr)
43 | {
44 | if (!*fd_ptr)
45 | return;
46 |
47 | fflush(*fd_ptr);
48 | fsync(fileno(*fd_ptr));
49 | fclose(*fd_ptr);
50 | *fd_ptr = NULL;
51 | }
52 |
53 | static struct csv_context *
54 | csv_context_create(const char *sensor_name, const char *output_dir)
55 | {
56 | struct csv_context *ctx = (struct csv_context *) malloc(sizeof(struct csv_context));
57 |
58 | if (!ctx)
59 | return NULL;
60 |
61 | ctx->config.output_dir = output_dir;
62 | ctx->config.sensor_name = sensor_name;
63 |
64 | ctx->groups_fd = zhashx_new();
65 | zhashx_set_destructor(ctx->groups_fd, (zhashx_destructor_fn *) group_fd_destroy);
66 |
67 | ctx->groups_events = zhashx_new();
68 | zhashx_set_destructor(ctx->groups_events, (zhashx_destructor_fn *) zlistx_destroy);
69 |
70 | return ctx;
71 | }
72 |
73 | static void
74 | csv_context_destroy(struct csv_context *ctx)
75 | {
76 | if (!ctx)
77 | return;
78 |
79 | zhashx_destroy(&ctx->groups_fd);
80 | zhashx_destroy(&ctx->groups_events);
81 | free(ctx);
82 | }
83 |
84 | static int
85 | csv_initialize(struct storage_module *module)
86 | {
87 | struct csv_context *ctx = (struct csv_context *) module->context;
88 | struct stat outdir_stat = {};
89 |
90 | /* create output directory */
91 | errno = 0;
92 | if (mkdir(ctx->config.output_dir, 0755) == -1) {
93 | /* ignore if directory already exists */
94 | if (errno != EEXIST) {
95 | zsys_error("csv: failed to create output directory: %s", strerror(errno));
96 | return -1;
97 | }
98 | }
99 |
100 | /* check if directory exists, above EEXIST check DO NOT guarantee that path is a directory */
101 | errno = 0;
102 | if (stat(ctx->config.output_dir, &outdir_stat) == -1) {
103 | zsys_error("csv: failed to check output dir: %s", strerror(errno));
104 | return -1;
105 | }
106 | if (!S_ISDIR(outdir_stat.st_mode)) {
107 | zsys_error("csv: output path already exists and is not a directory");
108 | return -1;
109 | }
110 |
111 | /* check if we can write into the output directory */
112 | errno = 0;
113 | if (access(ctx->config.output_dir, W_OK)) {
114 | zsys_error("csv: output path is not writable: %s", strerror(errno));
115 | return -1;
116 | }
117 |
118 | module->is_initialized = true;
119 | return 0;
120 | }
121 |
122 | static int
123 | csv_ping(struct storage_module *module __attribute__ ((unused)))
124 | {
125 | /* ping is not needed because the relevant checks are done when initializing the module */
126 | return 0;
127 | }
128 |
129 | static int
130 | write_group_header(struct csv_context *ctx, const char *group, FILE *fd, zhashx_t *events)
131 | {
132 | char buffer[CSV_LINE_BUFFER_SIZE] = {};
133 | int pos = 0;
134 | zlistx_t *events_name = NULL;
135 | const char *event_name = NULL;
136 |
137 | events_name = zhashx_keys(events);
138 | if (!events_name)
139 | return -1;
140 |
141 | /* sort events by name */
142 | zlistx_set_comparator(events_name, (zlistx_comparator_fn *) strcmp);
143 | zlistx_sort(events_name);
144 |
145 | /* write static elements to buffer */
146 | pos += snprintf(buffer, CSV_LINE_BUFFER_SIZE, "timestamp,sensor,target,socket,cpu");
147 |
148 | /* append dynamic elements (events) to buffer */
149 | for (event_name = (const char * ) zlistx_first(events_name); event_name; event_name = (const char * ) zlistx_next(events_name)) {
150 | pos += snprintf(buffer + pos, CSV_LINE_BUFFER_SIZE - pos, ",%s", event_name);
151 | if (pos >= CSV_LINE_BUFFER_SIZE)
152 | goto error_buffer_too_small;
153 | }
154 |
155 | if (fprintf(fd, "%s\n", buffer) < 0)
156 | goto error_failed_write;
157 |
158 | /* force writing to the disk */
159 | fflush(fd);
160 |
161 | /* store events name in the order written in header */
162 | zhashx_insert(ctx->groups_events, group, events_name);
163 |
164 | return 0;
165 |
166 | error_failed_write:
167 | error_buffer_too_small:
168 | zlistx_destroy(&events_name);
169 | return -1;
170 | }
171 |
172 | static int
173 | open_group_outfile(struct csv_context *ctx, const char *group_name)
174 | {
175 | char path[PATH_MAX] = {};
176 | int fd = -1;
177 | FILE *file = NULL;
178 |
179 | if (snprintf(path, PATH_MAX, "%s/%s.csv", ctx->config.output_dir, group_name) >= PATH_MAX) {
180 | zsys_error("csv: the destination path for output file of group %s is too long", group_name);
181 | return -1;
182 | }
183 |
184 | errno = 0;
185 | fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
186 | if (fd == -1) {
187 | zsys_error("csv: failed to open output file for group %s: %s", group_name, strerror(errno));
188 | return -1;
189 | }
190 |
191 | errno = 0;
192 | file = fdopen(fd, "w");
193 | if (!file) {
194 | zsys_error("csv: failed to associate a stream to output file of group %s: %s", group_name, strerror(errno));
195 | close(fd);
196 | return -1;
197 | }
198 |
199 | zhashx_insert(ctx->groups_fd, group_name, file);
200 | return 0;
201 | }
202 |
203 | static int
204 | write_events_value(struct csv_context *ctx, const char *group, FILE *fd, uint64_t timestamp, const char *target, const char *socket, const char *cpu, zhashx_t *events)
205 | {
206 | zlistx_t *events_name = NULL;
207 | char buffer[CSV_LINE_BUFFER_SIZE] = {};
208 | int pos = 0;
209 | const char *event_name = NULL;
210 | const uint64_t *event_value = NULL;
211 |
212 | /* get events name in the order of csv header */
213 | events_name = (zlistx_t *) zhashx_lookup(ctx->groups_events, group);
214 | if (!events_name)
215 | return -1;
216 |
217 | /* write static elements to buffer */
218 | pos += snprintf(buffer, CSV_LINE_BUFFER_SIZE, "%" PRIu64 ",%s,%s,%s,%s", timestamp, ctx->config.sensor_name, target, socket, cpu);
219 |
220 | /* write dynamic elements (events) to buffer */
221 | for (event_name = (const char *) zlistx_first(events_name); event_name; event_name = (const char * ) zlistx_next(events_name)) {
222 | event_value = (uint64_t *) zhashx_lookup(events, event_name);
223 | if (!event_value)
224 | return -1;
225 |
226 | pos += snprintf(buffer + pos, CSV_LINE_BUFFER_SIZE - pos, ",%" PRIu64, *event_value);
227 | if (pos >= CSV_LINE_BUFFER_SIZE)
228 | return -1;
229 | }
230 |
231 | if (fprintf(fd, "%s\n", buffer) < 0)
232 | return -1;
233 |
234 | return 0;
235 | }
236 |
237 | static int
238 | csv_store_report(struct storage_module *module, struct payload *payload)
239 | {
240 | struct csv_context *ctx = (struct csv_context *) module->context;
241 | struct payload_group_data *group_data = NULL;
242 | const char *group_name = NULL;
243 | FILE *group_fd = NULL;
244 | bool write_header = false;
245 | struct payload_pkg_data *pkg_data = NULL;
246 | const char *pkg_id = NULL;
247 | struct payload_cpu_data *cpu_data = NULL;
248 | const char *cpu_id = NULL;
249 |
250 | /*
251 | * write report into csv file as following:
252 | * timestamp,sensor,target,socket,cpu,INSTRUCTIONS_RETIRED,LLC_MISSES
253 | * 1538327257673,grvingt-64,system,0,56,5996,108
254 | */
255 | for (group_data = (struct payload_group_data *) zhashx_first(payload->groups); group_data; group_data = (struct payload_group_data *) zhashx_next(payload->groups)) {
256 | group_name = (const char *) zhashx_cursor(payload->groups);
257 | group_fd = (FILE *) zhashx_lookup(ctx->groups_fd, group_name);
258 | if (!group_fd) {
259 | if (open_group_outfile(ctx, group_name))
260 | return -1;
261 |
262 | group_fd = (FILE *) zhashx_lookup(ctx->groups_fd, group_name);
263 | write_header = true;
264 | }
265 |
266 | for (pkg_data = (struct payload_pkg_data *) zhashx_first(group_data->pkgs); pkg_data; pkg_data = (struct payload_pkg_data *) zhashx_next(group_data->pkgs)) {
267 | pkg_id = (const char *) zhashx_cursor(group_data->pkgs);
268 |
269 | for (cpu_data = (struct payload_cpu_data *) zhashx_first(pkg_data->cpus); cpu_data; cpu_data = (struct payload_cpu_data *) zhashx_next(pkg_data->cpus)) {
270 | cpu_id = (const char *) zhashx_cursor(pkg_data->cpus);
271 |
272 | if (write_header) {
273 | if (write_group_header(ctx, group_name, group_fd, cpu_data->events)) {
274 | zsys_error("csv: failed to write header to file for group=%s", group_name);
275 | return -1;
276 | }
277 | write_header = false;
278 | }
279 | if (write_events_value(ctx, group_name, group_fd, payload->timestamp, payload->target_name, pkg_id, cpu_id, cpu_data->events)) {
280 | zsys_error("csv: failed to write report to file for group=%s timestamp=%" PRIu64, group_name, payload->timestamp);
281 | return -1;
282 | }
283 | }
284 | }
285 | }
286 |
287 | return 0;
288 | }
289 |
290 | static int
291 | csv_deinitialize(struct storage_module *module)
292 | {
293 | module->is_initialized = false;
294 | return 0;
295 | }
296 |
297 | static void
298 | csv_destroy(struct storage_module *module)
299 | {
300 | if (!module)
301 | return;
302 |
303 | csv_context_destroy((csv_context *) module->context);
304 | }
305 |
306 | struct storage_module *
307 | storage_csv_create(struct config *config)
308 | {
309 | struct storage_module *module = NULL;
310 | struct csv_context *ctx = NULL;
311 |
312 | module = (struct storage_module *) malloc(sizeof(struct storage_module));
313 | if (!module)
314 | goto error;
315 |
316 | ctx = csv_context_create(config->sensor.name, config->storage.csv.outdir);
317 | if (!ctx)
318 | goto error;
319 |
320 | module->type = STORAGE_CSV;
321 | module->context = ctx;
322 | module->is_initialized = false;
323 | module->initialize = csv_initialize;
324 | module->ping = csv_ping;
325 | module->store_report = csv_store_report;
326 | module->deinitialize = csv_deinitialize;
327 | module->destroy = csv_destroy;
328 |
329 | return module;
330 |
331 | error:
332 | csv_context_destroy(ctx);
333 | free(module);
334 | return NULL;
335 | }
336 |
337 |
--------------------------------------------------------------------------------
/src/storage_csv.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef STORAGE_CSV_H
33 | #define STORAGE_CSV_H
34 |
35 | #include
36 |
37 | #include "config.h"
38 |
39 | /*
40 | * CSV_LINE_BUFFER_SIZE stores the maximum length of a line in a group csv output file.
41 | */
42 | #define CSV_LINE_BUFFER_SIZE 1024
43 |
44 | /*
45 | * csv_config stores the required information for the module.
46 | */
47 | struct csv_config
48 | {
49 | const char *sensor_name;
50 | const char *output_dir;
51 | };
52 |
53 | /*
54 | * csv_context stores the context of the module.
55 | */
56 | struct csv_context
57 | {
58 | struct csv_config config;
59 | zhashx_t *groups_fd; /* char *group_name -> FILE *fd */
60 | zhashx_t *groups_events; /* char *group_name -> zlistx_t *group_events */
61 | };
62 |
63 | /*
64 | * storage_csv_create creates and configure a csv storage module..
65 | */
66 | struct storage_module *storage_csv_create(struct config *config);
67 |
68 | #endif /* CSV_H */
69 |
70 |
--------------------------------------------------------------------------------
/src/storage_mongodb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 |
34 | #include "report.h"
35 | #include "storage_mongodb.h"
36 | #include "perf.h"
37 |
38 | static struct mongodb_context *
39 | mongodb_context_create(const char *sensor_name, const char *uri, const char *database, const char *collection)
40 | {
41 | struct mongodb_context *ctx = (struct mongodb_context *) malloc(sizeof(struct mongodb_context));
42 |
43 | if (!ctx)
44 | return NULL;
45 |
46 | ctx->config.sensor_name = sensor_name;
47 | ctx->config.uri = uri;
48 | ctx->config.database_name = database;
49 | ctx->config.collection_name = collection;
50 |
51 | ctx->client = NULL;
52 | ctx->collection = NULL;
53 |
54 | return ctx;
55 | }
56 |
57 | static void
58 | mongodb_context_destroy(struct mongodb_context *ctx)
59 | {
60 | if (!ctx)
61 | return;
62 |
63 | free(ctx);
64 | }
65 |
66 | static int
67 | mongodb_initialize(struct storage_module *module)
68 | {
69 | struct mongodb_context *ctx = (struct mongodb_context *) module->context;
70 | bson_error_t error;
71 |
72 | if (module->is_initialized)
73 | return -1;
74 |
75 | mongoc_init();
76 |
77 | ctx->uri = mongoc_uri_new_with_error(ctx->config.uri, &error);
78 | if (!ctx->uri) {
79 | zsys_error("mongodb: failed to parse uri: %s", error.message);
80 | goto error;
81 | }
82 |
83 | ctx->client = mongoc_client_new_from_uri(ctx->uri);
84 | if (!ctx->client) {
85 | zsys_error("mongodb: failed to create client");
86 | goto error;
87 | }
88 |
89 | ctx->collection = mongoc_client_get_collection(ctx->client, ctx->config.database_name, ctx->config.collection_name);
90 | /* collection is automatically created if non-existent */
91 |
92 | module->is_initialized = true;
93 | return 0;
94 |
95 | error:
96 | mongoc_uri_destroy(ctx->uri);
97 | mongoc_client_destroy(ctx->client);
98 | return -1;
99 | }
100 |
101 | static int
102 | mongodb_ping(struct storage_module *module)
103 | {
104 | struct mongodb_context *ctx = (struct mongodb_context *) module->context;
105 | int ret = 0;
106 | bson_t *ping_cmd = BCON_NEW("ping", BCON_INT32(1));
107 | bson_error_t error;
108 |
109 | if (!mongoc_client_command_simple(ctx->client, "admin", ping_cmd, NULL, NULL, &error)) {
110 | zsys_error("mongodb: failed to ping mongodb server: %s", error.message);
111 | ret = -1;
112 | }
113 |
114 | bson_destroy(ping_cmd);
115 | return ret;
116 | }
117 |
118 | static int
119 | mongodb_store_report(struct storage_module *module, struct payload *payload)
120 | {
121 | struct mongodb_context *ctx = (struct mongodb_context *) module->context;
122 | bson_t document = BSON_INITIALIZER;
123 | bson_t doc_groups;
124 | struct payload_group_data *group_data = NULL;
125 | const char *group_name = NULL;
126 | bson_t doc_group;
127 | struct payload_pkg_data *pkg_data = NULL;
128 | const char *pkg_id = NULL;
129 | bson_t doc_pkg;
130 | struct payload_cpu_data *cpu_data = NULL;
131 | const char *cpu_id = NULL;
132 | bson_t doc_cpu;
133 | const char *event_name = NULL;
134 | uint64_t *event_value = NULL;
135 | bson_error_t error;
136 | int ret = 0;
137 |
138 | /*
139 | * construct mongodb document as following:
140 | * {
141 | * "timestamp": 1529868713854,
142 | * "sensor": "test.cluster.lan",
143 | * "target": "example",
144 | * "groups": {
145 | * "group_name": {
146 | * "pkg_id": {
147 | * "cpu_id": {
148 | * "time_enabled": 12345,
149 | * "time_running": 12345,
150 | * "event_name": 123456789.0,
151 | * more events...
152 | * },
153 | * more cpus...
154 | * },
155 | * more pkgs...
156 | * },
157 | * more groups...
158 | * }
159 | * }
160 | */
161 | BSON_APPEND_DATE_TIME(&document, "timestamp", payload->timestamp);
162 | BSON_APPEND_UTF8(&document, "sensor", ctx->config.sensor_name);
163 | BSON_APPEND_UTF8(&document, "target", payload->target_name);
164 |
165 | BSON_APPEND_DOCUMENT_BEGIN(&document, "groups", &doc_groups);
166 | for (group_data = (struct payload_group_data *) zhashx_first(payload->groups); group_data; group_data = (struct payload_group_data *) zhashx_next(payload->groups)) {
167 | group_name = (const char *) zhashx_cursor(payload->groups);
168 | BSON_APPEND_DOCUMENT_BEGIN(&doc_groups, group_name, &doc_group);
169 |
170 | for (pkg_data = (struct payload_pkg_data *) zhashx_first(group_data->pkgs); pkg_data; pkg_data = (struct payload_pkg_data *) zhashx_next(group_data->pkgs)) {
171 | pkg_id = (const char * ) zhashx_cursor(group_data->pkgs);
172 | BSON_APPEND_DOCUMENT_BEGIN(&doc_group, pkg_id, &doc_pkg);
173 |
174 | for (cpu_data = (struct payload_cpu_data *) zhashx_first(pkg_data->cpus); cpu_data; cpu_data = (struct payload_cpu_data *) zhashx_next(pkg_data->cpus)) {
175 | cpu_id = (const char *) zhashx_cursor(pkg_data->cpus);
176 | BSON_APPEND_DOCUMENT_BEGIN(&doc_pkg, cpu_id, &doc_cpu);
177 |
178 | for (event_value = (uint64_t *) zhashx_first(cpu_data->events); event_value; event_value = (uint64_t *) zhashx_next(cpu_data->events)) {
179 | event_name = (const char *) zhashx_cursor(cpu_data->events);
180 | BSON_APPEND_DOUBLE(&doc_cpu, event_name, *event_value);
181 | }
182 |
183 | bson_append_document_end(&doc_pkg, &doc_cpu);
184 | }
185 |
186 | bson_append_document_end(&doc_group, &doc_pkg);
187 | }
188 |
189 | bson_append_document_end(&doc_groups, &doc_group);
190 | }
191 | bson_append_document_end(&document, &doc_groups);
192 |
193 | /* insert document into collection */
194 | if (!mongoc_collection_insert_one(ctx->collection, &document, NULL, NULL, &error)) {
195 | zsys_error("mongodb: failed insert timestamp=%lu target=%s: %s", payload->timestamp, payload->target_name, error.message);
196 | ret = -1;
197 | }
198 |
199 | bson_destroy(&document);
200 | return ret;
201 | }
202 |
203 | static int
204 | mongodb_deinitialize(struct storage_module *module __attribute__ ((unused)))
205 | {
206 | struct mongodb_context *ctx = (struct mongodb_context *) module->context;
207 |
208 | if (!module->is_initialized)
209 | return -1;
210 |
211 | mongoc_collection_destroy(ctx->collection);
212 | mongoc_client_destroy(ctx->client);
213 | mongoc_uri_destroy(ctx->uri);
214 | mongoc_cleanup();
215 | module->is_initialized = false;
216 | return 0;
217 | }
218 |
219 | static void
220 | mongodb_destroy(struct storage_module *module)
221 | {
222 | if (!module)
223 | return;
224 |
225 | mongodb_context_destroy((struct mongodb_context *) module->context);
226 | }
227 |
228 | struct storage_module *
229 | storage_mongodb_create(struct config *config)
230 | {
231 | struct storage_module *module = NULL;
232 | struct mongodb_context *ctx = NULL;
233 |
234 | module = (struct storage_module *) malloc(sizeof(struct storage_module));
235 | if (!module)
236 | goto error;
237 |
238 | ctx = mongodb_context_create(config->sensor.name, config->storage.mongodb.uri, config->storage.mongodb.database, config->storage.mongodb.collection);
239 | if (!ctx)
240 | goto error;
241 |
242 | module->type = STORAGE_MONGODB;
243 | module->context = ctx;
244 | module->is_initialized = false;
245 | module->initialize = mongodb_initialize;
246 | module->ping = mongodb_ping;
247 | module->store_report = mongodb_store_report;
248 | module->deinitialize = mongodb_deinitialize;
249 | module->destroy = mongodb_destroy;
250 |
251 | return module;
252 |
253 | error:
254 | mongodb_context_destroy(ctx);
255 | free(module);
256 | return NULL;
257 | }
258 |
259 |
--------------------------------------------------------------------------------
/src/storage_mongodb.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef STORAGE_MONGODB_H
33 | #define STORAGE_MONGODB_H
34 |
35 | #include
36 |
37 | #include "storage.h"
38 | #include "config.h"
39 |
40 |
41 | /*
42 | * mongodb_config stores the required information for the module.
43 | */
44 | struct mongodb_config
45 | {
46 | const char *sensor_name;
47 | const char *uri;
48 | const char *database_name;
49 | const char *collection_name;
50 | };
51 |
52 | /*
53 | * mongodb_context stores the context of the module.
54 | */
55 | struct mongodb_context
56 | {
57 | struct mongodb_config config;
58 | mongoc_uri_t *uri;
59 | mongoc_client_t *client;
60 | mongoc_collection_t *collection;
61 | };
62 |
63 | /*
64 | * storage_mongodb_create creates and configure a mongodb storage module.
65 | */
66 | struct storage_module *storage_mongodb_create(struct config *config);
67 |
68 | #endif /* STORAGE_MONGODB_H */
69 |
70 |
--------------------------------------------------------------------------------
/src/storage_null.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include "storage.h"
33 | #include "storage_null.h"
34 | #include "config.h"
35 |
36 | static int
37 | null_initialize(struct storage_module *module)
38 | {
39 | zsys_warning("null: this output module should be used for debug only, no data will be stored");
40 |
41 | module->is_initialized = true;
42 | return 0;
43 | }
44 |
45 | static int
46 | null_ping(struct storage_module *module __attribute__ ((unused)))
47 | {
48 | return 0;
49 | }
50 |
51 | static int
52 | null_store_report(struct storage_module *module __attribute__ ((unused)), struct payload *payload __attribute__ ((unused)))
53 | {
54 | return 0;
55 | }
56 |
57 | static int
58 | null_deinitialize(struct storage_module *module)
59 | {
60 | module->is_initialized = false;
61 | return 0;
62 | }
63 |
64 | static void
65 | null_destroy(struct storage_module *module __attribute__ ((unused)))
66 | {
67 | return;
68 | }
69 |
70 | struct storage_module *
71 | storage_null_create(struct config *config __attribute__ ((unused)))
72 | {
73 | struct storage_module *module = (struct storage_module *) malloc(sizeof(struct storage_module));
74 |
75 | if (!module)
76 | return NULL;
77 |
78 | module->type = STORAGE_NULL;
79 | module->context = NULL;
80 | module->is_initialized = false;
81 | module->initialize = null_initialize;
82 | module->ping = null_ping;
83 | module->store_report = null_store_report;
84 | module->deinitialize = null_deinitialize;
85 | module->destroy = null_destroy;
86 |
87 | return module;
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/src/storage_null.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef STORAGE_NULL_H
33 | #define STORAGE_NULL_H
34 |
35 | #include "config.h"
36 |
37 | /*
38 | * storage_null_create creates and configure a null storage module.
39 | */
40 | struct storage_module *storage_null_create(struct config *config);
41 |
42 | #endif /* STORAGE_NULL_H */
43 |
--------------------------------------------------------------------------------
/src/storage_socket.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, INRIA
3 | * Copyright (c) 2021, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include "perf.h"
42 | #include "report.h"
43 | #include "storage_socket.h"
44 |
45 | static struct socket_context *
46 | socket_context_create(const char *sensor_name, const char *address, const char *port)
47 | {
48 | struct socket_context *ctx = (struct socket_context *) malloc(sizeof(struct socket_context));
49 |
50 | if (!ctx)
51 | return NULL;
52 |
53 | ctx->config.sensor_name = sensor_name;
54 | ctx->config.address = address;
55 | ctx->config.port = port;
56 |
57 | ctx->socket_fd = -1;
58 | ctx->last_retry_time = 0;
59 | ctx->retry_backoff_time = 1;
60 |
61 | return ctx;
62 | }
63 |
64 | static void
65 | socket_context_destroy(struct socket_context *ctx)
66 | {
67 | if (!ctx)
68 | return;
69 |
70 | free(ctx);
71 | }
72 |
73 | static int
74 | socket_resolve_and_connect(struct socket_context *ctx)
75 | {
76 | struct addrinfo hints = {};
77 | struct addrinfo *result = NULL, *rp = NULL;
78 | int sfd = -1;
79 | int ret = -1;
80 |
81 | /* setup hints for address resolution */
82 | hints.ai_family = AF_UNSPEC;
83 | hints.ai_socktype = SOCK_STREAM;
84 |
85 | if (getaddrinfo(ctx->config.address, ctx->config.port, &hints, &result)) {
86 | zsys_error("socket: Unable to resolve address: %s", ctx->config.address);
87 | goto error_no_getaddrinfo;
88 | }
89 |
90 | /* attemps to connect to any of the resolved address(es) */
91 | for (rp = result; rp; rp = rp->ai_next) {
92 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
93 | if (sfd == -1)
94 | continue;
95 |
96 | ret = connect(sfd, rp->ai_addr, rp->ai_addrlen);
97 | if (!ret) {
98 | zsys_info("socket: Successfully connected to %s:%s", ctx->config.address, ctx->config.port);
99 | break;
100 | }
101 |
102 | close(sfd);
103 | }
104 |
105 | /* no connection have been established */
106 | if (ret == -1) {
107 | zsys_error("socket: Failed to connect to %s:%s", ctx->config.address, ctx->config.port);
108 | goto error_not_connected;
109 | }
110 |
111 | ctx->socket_fd = sfd;
112 |
113 | error_not_connected:
114 | freeaddrinfo(result);
115 | error_no_getaddrinfo:
116 | return ret;
117 | }
118 |
119 | static int
120 | socket_initialize(struct storage_module *module)
121 | {
122 | struct socket_context *ctx = (struct socket_context *) module->context;
123 |
124 | if (module->is_initialized)
125 | return -1;
126 |
127 | if (socket_resolve_and_connect(ctx))
128 | return -1;
129 |
130 | module->is_initialized = 1;
131 | return 0;
132 | }
133 |
134 | static int
135 | socket_ping(struct storage_module *module __attribute__ ((unused)))
136 | {
137 | /* ping is not supported by this module */
138 | return 0;
139 | }
140 |
141 | static int
142 | socket_try_reconnect(struct socket_context *ctx)
143 | {
144 | time_t current_time = time(NULL);
145 | ssize_t nbrand;
146 | uint8_t rand_jitter;
147 |
148 | /* close the current socket */
149 | if (ctx->socket_fd != -1) {
150 | close(ctx->socket_fd);
151 | ctx->socket_fd = -1;
152 | }
153 |
154 | /* retry socket connection with an exponential backoff */
155 | if (difftime(current_time, ctx->last_retry_time) >= (double) ctx->retry_backoff_time) {
156 | if (socket_resolve_and_connect(ctx)) {
157 | ctx->last_retry_time = current_time;
158 | if (ctx->retry_backoff_time < MAX_DURATION_CONNECTION_RETRY) {
159 | nbrand = getrandom(&rand_jitter, sizeof(uint8_t), 0);
160 | ctx->retry_backoff_time = ctx->retry_backoff_time * 2 + (nbrand != -1 ? rand_jitter % 10 : 0);
161 | }
162 |
163 | zsys_error("socket: Failed to reconnect, next try will be in %d seconds", ctx->retry_backoff_time);
164 | return -1;
165 | } else {
166 | ctx->last_retry_time = 0;
167 | ctx->retry_backoff_time = 1;
168 |
169 | zsys_info("socket: Connection recovered, resuming operation");
170 | return 0;
171 | }
172 | }
173 |
174 | return -1;
175 | }
176 |
177 | static int
178 | socket_store_report(struct storage_module *module, struct payload *payload)
179 | {
180 | struct socket_context *ctx = (struct socket_context *) module->context;
181 | struct json_object *jobj = NULL;
182 | struct json_object *jobj_groups = NULL;
183 | struct payload_group_data *group_data = NULL;
184 | const char *group_name = NULL;
185 | struct json_object *jobj_group = NULL;
186 | struct payload_pkg_data *pkg_data = NULL;
187 | const char *pkg_id = NULL;
188 | struct json_object *jobj_pkg = NULL;
189 | struct payload_cpu_data *cpu_data = NULL;
190 | const char *cpu_id = NULL;
191 | struct json_object *jobj_cpu = NULL;
192 | const char *event_name = NULL;
193 | uint64_t *event_value = NULL;
194 | const char *json_report = NULL;
195 | size_t json_report_length = 0;
196 | struct iovec socket_iov[2] = {};
197 | ssize_t nbsend;
198 | int retry_once = 1;
199 | int ret = -1;
200 |
201 | /* try to reconnect the socket before building the document */
202 | if (ctx->socket_fd == -1) {
203 | if (socket_try_reconnect(ctx))
204 | return -1;
205 | }
206 |
207 | /*
208 | * {
209 | * "timestamp": 1529868713854,
210 | * "sensor": "test.cluster.lan",
211 | * "target": "example",
212 | * "groups": {
213 | * "group_name": {
214 | * "pkg_id": {
215 | * "cpu_id": {
216 | * "time_enabled": 12345,
217 | * "time_running": 12345,
218 | * "event_name": 1234567890,
219 | * more events...
220 | * },
221 | * more cpus...
222 | * },
223 | * more pkgs...
224 | * },
225 | * more groups...
226 | * }
227 | * }
228 | */
229 | jobj = json_object_new_object();
230 |
231 | json_object_object_add(jobj, "timestamp", json_object_new_uint64(payload->timestamp));
232 | json_object_object_add(jobj, "sensor", json_object_new_string(ctx->config.sensor_name));
233 | json_object_object_add(jobj, "target", json_object_new_string(payload->target_name));
234 |
235 | jobj_groups = json_object_new_object();
236 | json_object_object_add(jobj, "groups", jobj_groups);
237 | for (group_data = (struct payload_group_data *) zhashx_first(payload->groups); group_data; group_data = (struct payload_group_data *) zhashx_next(payload->groups)) {
238 |
239 | jobj_group = json_object_new_object();
240 | group_name = (const char *) zhashx_cursor(payload->groups);
241 | json_object_object_add(jobj_groups, group_name, jobj_group);
242 | for (pkg_data = (struct payload_pkg_data *) zhashx_first(group_data->pkgs); pkg_data; pkg_data = (struct payload_pkg_data *) zhashx_next(group_data->pkgs)) {
243 |
244 | jobj_pkg = json_object_new_object();
245 | pkg_id = (const char *) zhashx_cursor(group_data->pkgs);
246 | json_object_object_add(jobj_group, pkg_id, jobj_pkg);
247 | for (cpu_data = (struct payload_cpu_data *) zhashx_first(pkg_data->cpus); cpu_data; cpu_data = (struct payload_cpu_data *) zhashx_next(pkg_data->cpus)) {
248 | jobj_cpu = json_object_new_object();
249 | cpu_id = (const char *) zhashx_cursor(pkg_data->cpus);
250 | json_object_object_add(jobj_pkg, cpu_id, jobj_cpu);
251 |
252 | for (event_value = (uint64_t *) zhashx_first(cpu_data->events); event_value; event_value = (uint64_t *) zhashx_next(cpu_data->events)) {
253 | event_name = (const char *) zhashx_cursor(cpu_data->events);
254 | json_object_object_add(jobj_cpu, event_name, json_object_new_uint64(*event_value));
255 | }
256 | }
257 | }
258 | }
259 |
260 | json_report = json_object_to_json_string_length(jobj, JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE, &json_report_length);
261 | if (json_report == NULL) {
262 | zsys_error("socket: Failed to convert report to json string");
263 | goto error_json_to_string;
264 | }
265 |
266 | /*
267 | * PowerAPI socketdb requires a newline character at the end of the json document.
268 | * Using POSIX IOV allows to efficiently append it at the end of the json string.
269 | */
270 | socket_iov[0].iov_base = (void *) json_report;
271 | socket_iov[0].iov_len = json_report_length;
272 | socket_iov[1].iov_base = (void *) "\n";
273 | socket_iov[1].iov_len = 1;
274 |
275 | do {
276 | /*
277 | * Try to send the serialized report to the endpoint.
278 | * If the connection have been lost, try to reconnect and send the report again.
279 | * The exponential backoff on socket reconnect prevents consecutive attempts.
280 | */
281 | errno = 0;
282 | nbsend = writev(ctx->socket_fd, socket_iov, 2);
283 | if (nbsend == -1) {
284 | zsys_error("socket: Sending the report failed with error: %s", strerror(errno));
285 |
286 | if (retry_once) {
287 | zsys_info("socket: Connection has been lost, attempting to reconnect...");
288 | if (!socket_try_reconnect(ctx))
289 | continue;
290 | }
291 |
292 | goto error_socket_disconnected;
293 | }
294 | } while (nbsend == -1 && retry_once--);
295 |
296 | ret = 0;
297 |
298 | error_json_to_string:
299 | error_socket_disconnected:
300 | json_object_put(jobj);
301 | return ret;
302 | }
303 |
304 | static int
305 | socket_deinitialize(struct storage_module *module)
306 | {
307 | struct socket_context *ctx = (struct socket_context *) module->context;
308 |
309 | if (!module->is_initialized)
310 | return -1;
311 |
312 | if (ctx->socket_fd != -1)
313 | close(ctx->socket_fd);
314 |
315 | return 0;
316 | }
317 |
318 | static void
319 | socket_destroy(struct storage_module *module)
320 | {
321 | if (!module)
322 | return;
323 |
324 | socket_context_destroy((struct socket_context *) module->context);
325 | }
326 |
327 | struct storage_module *
328 | storage_socket_create(struct config *config)
329 | {
330 | struct storage_module *module = NULL;
331 | struct socket_context *ctx = NULL;
332 |
333 | module = (struct storage_module *) malloc(sizeof(struct storage_module));
334 | if (!module)
335 | goto error;
336 |
337 | ctx = socket_context_create(config->sensor.name, config->storage.socket.hostname, config->storage.socket.port);
338 | if (!ctx)
339 | goto error;
340 |
341 | module->type = STORAGE_SOCKET;
342 | module->context = ctx;
343 | module->is_initialized = false;
344 | module->initialize = socket_initialize;
345 | module->ping = socket_ping;
346 | module->store_report = socket_store_report;
347 | module->deinitialize = socket_deinitialize;
348 | module->destroy = socket_destroy;
349 |
350 | return module;
351 |
352 | error:
353 | socket_context_destroy(ctx);
354 | free(module);
355 | return NULL;
356 | }
357 |
--------------------------------------------------------------------------------
/src/storage_socket.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2021, INRIA
3 | * Copyright (c) 2021, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef STORAGE_SOCKET_H
33 | #define STORAGE_SOCKET_H
34 |
35 | #include "storage.h"
36 | #include "config.h"
37 |
38 | /*
39 | * MAX_DURATION_CONNECTION_RETRY stores the maximal value of a connection retry. (in seconds)
40 | */
41 | #define MAX_DURATION_CONNECTION_RETRY 1800
42 |
43 | /*
44 | * socket_config stores the required information for the module.
45 | */
46 | struct socket_config
47 | {
48 | const char *sensor_name;
49 | const char *address;
50 | const char *port;
51 | };
52 |
53 | /*
54 | * socket_context stores the context of the module.
55 | */
56 | struct socket_context
57 | {
58 | struct socket_config config;
59 | int socket_fd;
60 | time_t last_retry_time;
61 | time_t retry_backoff_time;
62 | };
63 |
64 | /*
65 | * storage_socket_create creates and configure a socket storage module.
66 | */
67 | struct storage_module *storage_socket_create(struct config *config);
68 |
69 | #endif /* STORAGE_SOCKET_H */
70 |
--------------------------------------------------------------------------------
/src/target.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 | #include "target.h"
41 | #include "target_docker.h"
42 | #include "target_kubernetes.h"
43 |
44 |
45 | enum target_type
46 | target_detect_type(const char *cgroup_path)
47 | {
48 | /* All running processes/threads (not a cgroup) */
49 | if (!cgroup_path)
50 | return TARGET_TYPE_ALL;
51 |
52 | /* System (running processes/threads in system cgroup) */
53 | if (strstr(cgroup_path, "perf_event/system"))
54 | return TARGET_TYPE_SYSTEM;
55 |
56 | /* Kernel (running processes/threads in kernel cgroup) */
57 | if (strstr(cgroup_path, "perf_event/kernel"))
58 | return TARGET_TYPE_KERNEL;
59 |
60 | /* Docker (running containers) */
61 | if (strstr(cgroup_path, "perf_event/docker"))
62 | return TARGET_TYPE_DOCKER;
63 |
64 | /* Kubernetes (running containers) */
65 | if (strstr(cgroup_path, "perf_event/kubepods"))
66 | return TARGET_TYPE_KUBERNETES;
67 |
68 | /* LibVirt (running virtual machine) */
69 | if (strstr(cgroup_path, "perf_event/machine.slice"))
70 | return TARGET_TYPE_LIBVIRT;
71 |
72 | /* LXC (running containers) */
73 | if (strstr(cgroup_path, "perf_event/lxc"))
74 | return TARGET_TYPE_LXC;
75 |
76 | return TARGET_TYPE_UNKNOWN;
77 | }
78 |
79 | int
80 | target_validate_type(enum target_type type, const char *cgroup_path)
81 | {
82 | switch (type) {
83 | case TARGET_TYPE_DOCKER:
84 | return target_docker_validate(cgroup_path);
85 |
86 | case TARGET_TYPE_KUBERNETES:
87 | return target_kubernetes_validate(cgroup_path);
88 |
89 | default:
90 | /* other types does not need a validation */
91 | return true;
92 | }
93 | }
94 |
95 | struct target *
96 | target_create(enum target_type type, const char *cgroup_basedir, const char *cgroup_path)
97 | {
98 | struct target *target = (struct target *) malloc(sizeof(struct target));
99 |
100 | if (!target)
101 | return NULL;
102 |
103 | target->cgroup_basedir = cgroup_basedir;
104 | target->cgroup_path = (cgroup_path) ? strdup(cgroup_path) : NULL;
105 | target->type = type;
106 |
107 | return target;
108 | }
109 |
110 | char *
111 | target_resolve_real_name(struct target *target)
112 | {
113 | char *target_real_name = NULL;
114 |
115 | switch (target->type) {
116 | case TARGET_TYPE_DOCKER:
117 | target_real_name = target_docker_resolve_name(target);
118 | break;
119 |
120 | case TARGET_TYPE_KUBERNETES:
121 | target_real_name = target_kubernetes_resolve_name(target);
122 | break;
123 |
124 | case TARGET_TYPE_ALL:
125 | target_real_name = strdup("all");
126 | break;
127 |
128 | case TARGET_TYPE_KERNEL:
129 | target_real_name = strdup("kernel");
130 | break;
131 |
132 | case TARGET_TYPE_SYSTEM:
133 | target_real_name = strdup("system");
134 | break;
135 |
136 | default:
137 | break;
138 | }
139 |
140 | /* if name cannot be resolved, use the cgroup path relative to cgroup base dir */
141 | if (!target_real_name && target->cgroup_path && target->cgroup_basedir) {
142 | target_real_name = strdup(target->cgroup_path + strlen(target->cgroup_basedir));
143 | }
144 |
145 | return target_real_name;
146 | }
147 |
148 | void
149 | target_destroy(struct target *target)
150 | {
151 | if (!target)
152 | return;
153 |
154 | free(target->cgroup_path);
155 | free(target);
156 | }
157 |
158 | int
159 | target_discover_running(const char *base_path, enum target_type type_mask, zhashx_t *targets)
160 | {
161 | const char *path[] = { base_path, NULL };
162 | FTS *file_system = NULL;
163 | FTSENT *node = NULL;
164 | enum target_type type;
165 | struct target *target = NULL;
166 |
167 | file_system = fts_open((char * const *)path, FTS_LOGICAL | FTS_NOCHDIR, NULL);
168 | if (!file_system)
169 | return -1;
170 |
171 | for (node = fts_read(file_system); node; node = fts_read(file_system)) {
172 | /*
173 | * Filtering the directories having 2 hard links leading to them to only get leaves directories.
174 | * The cgroup subsystems does not support hard links, so this will always work.
175 | */
176 | if (node->fts_info == FTS_D && node->fts_statp->st_nlink == 2) {
177 | type = target_detect_type(node->fts_path);
178 | if ((type & type_mask) && target_validate_type(type, node->fts_path)) {
179 | target = target_create(type, base_path, node->fts_path);
180 | if (target)
181 | zhashx_insert(targets, node->fts_path, target);
182 | }
183 | }
184 | }
185 |
186 | fts_close(file_system);
187 | return 0;
188 | }
189 |
190 |
--------------------------------------------------------------------------------
/src/target.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef TARGET_H
33 | #define TARGET_H
34 |
35 | #include
36 |
37 | /*
38 | * target_type stores the supported target types.
39 | */
40 | enum target_type
41 | {
42 | TARGET_TYPE_UNKNOWN = 1,
43 | TARGET_TYPE_ALL = 2,
44 | TARGET_TYPE_SYSTEM = 4,
45 | TARGET_TYPE_KERNEL = 8,
46 | TARGET_TYPE_DOCKER = 16,
47 | TARGET_TYPE_KUBERNETES = 32,
48 | TARGET_TYPE_LIBVIRT = 64,
49 | TARGET_TYPE_LXC = 128,
50 | TARGET_TYPE_EVERYTHING = 255
51 | };
52 |
53 | /*
54 | * target stores various information about the target.
55 | */
56 | struct target
57 | {
58 | enum target_type type;
59 | const char *cgroup_basedir;
60 | char *cgroup_path;
61 | };
62 |
63 | /*
64 | * target_detect_type returns the target type of the given cgroup path.
65 | */
66 | enum target_type target_detect_type(const char *cgroup_path);
67 |
68 | /*
69 | * target_validate_type validate the target type of the given cgroup path.
70 | */
71 | int target_validate_type(enum target_type type, const char *cgroup_path);
72 |
73 | /*
74 | * target_create allocate the resources and configure the target.
75 | */
76 | struct target *target_create(enum target_type type, const char *cgroup_basedir, const char *cgroup_path);
77 |
78 | /*
79 | * target_resolve_real_name resolve and return the real name of the given target.
80 | */
81 | char *target_resolve_real_name(struct target *target);
82 |
83 | /*
84 | * target_destroy free the allocated resources for the target.
85 | */
86 | void target_destroy(struct target *target);
87 |
88 | /*
89 | * target_discover_running returns a list of running targets.
90 | */
91 | int target_discover_running(const char *base_path, enum target_type type_mask, zhashx_t *targets);
92 |
93 | #endif /* TARGET_H */
94 |
95 |
--------------------------------------------------------------------------------
/src/target_docker.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include "target.h"
39 | #include "target_docker.h"
40 |
41 | /*
42 | * CONTAINER_ID_REGEX is the regex used to extract the Docker container id from the cgroup path.
43 | * CONTAINER_ID_REGEX_EXPECTED_MATCHES is the number of expected matches from the regex. (num groups + 1)
44 | */
45 | #define CONTAINER_ID_REGEX "perf_event/docker/([a-f0-9]{64})$"
46 | #define CONTAINER_ID_REGEX_EXPECTED_MATCHES 2
47 |
48 | /*
49 | * CONTAINER_NAME_REGEX is the regex used to extract the Docker container name from its json configuration file.
50 | * CONTAINER_NAME_REGEX_EXPECTED_MATCHES is the number of expected matches from the regex. (num groups + 1)
51 | */
52 | #define CONTAINER_NAME_REGEX "\"Name\":\"/([a-zA-Z0-9][a-zA-Z0-9_.-]+)\""
53 | #define CONTAINER_NAME_REGEX_EXPECTED_MATCHES 2
54 |
55 |
56 | int
57 | target_docker_validate(const char *cgroup_path)
58 | {
59 | regex_t re;
60 | int is_docker_target = false;
61 |
62 | if (!cgroup_path)
63 | return false;
64 |
65 | if (!regcomp(&re, CONTAINER_ID_REGEX, REG_EXTENDED | REG_NEWLINE | REG_NOSUB)) {
66 | if (!regexec(&re, cgroup_path, 0, NULL, 0))
67 | is_docker_target = true;
68 |
69 | regfree(&re);
70 | }
71 |
72 | return is_docker_target;
73 | }
74 |
75 | static char *
76 | build_container_config_path(const char *cgroup_path)
77 | {
78 | regex_t re;
79 | regmatch_t matches[CONTAINER_ID_REGEX_EXPECTED_MATCHES];
80 | regoff_t length;
81 | const char *id = NULL;
82 | char buffer[PATH_MAX] = {};
83 | char *config_path = NULL;
84 |
85 | if (!regcomp(&re, CONTAINER_ID_REGEX, REG_EXTENDED | REG_NEWLINE)) {
86 | if (!regexec(&re, cgroup_path, CONTAINER_ID_REGEX_EXPECTED_MATCHES, matches, 0)) {
87 | id = cgroup_path + matches[1].rm_so;
88 | length = matches[1].rm_eo - matches[1].rm_so;
89 | snprintf(buffer, PATH_MAX, "/var/lib/docker/containers/%.*s/config.v2.json", length, id);
90 | config_path = strdup(buffer);
91 | }
92 | regfree(&re);
93 | }
94 |
95 | return config_path;
96 | }
97 |
98 | char *
99 | target_docker_resolve_name(struct target *target)
100 | {
101 | char *config_path = NULL;
102 | FILE *json_file = NULL;
103 | char *json = NULL;
104 | size_t json_len;
105 | regex_t re;
106 | regmatch_t matches[CONTAINER_NAME_REGEX_EXPECTED_MATCHES];
107 | char *target_name = NULL;
108 |
109 | config_path = build_container_config_path(target->cgroup_path);
110 | if (!config_path)
111 | return NULL;
112 |
113 | json_file = fopen(config_path, "r");
114 | if (json_file) {
115 | if (getline(&json, &json_len, json_file) != -1) {
116 | if (!regcomp(&re, CONTAINER_NAME_REGEX, REG_EXTENDED | REG_NEWLINE)) {
117 | if (!regexec(&re, json, CONTAINER_NAME_REGEX_EXPECTED_MATCHES, matches, 0))
118 | target_name = strndup(json + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
119 |
120 | regfree(&re);
121 | }
122 | free(json);
123 | }
124 | fclose(json_file);
125 | }
126 |
127 | free(config_path);
128 | return target_name;
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/src/target_docker.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef TARGET_DOCKER_H
33 | #define TARGET_DOCKER_H
34 |
35 | #include "target.h"
36 |
37 | /*
38 | * target_docker_validate check if the cgroup path lead to a valid Docker target.
39 | */
40 | int target_docker_validate(const char *cgroup_path);
41 |
42 | /*
43 | * target_docker_resolve_name resolve and return the real name of the given target.
44 | */
45 | char *target_docker_resolve_name(struct target *target);
46 |
47 | #endif /* TARGET_DOCKER_H */
48 |
49 |
--------------------------------------------------------------------------------
/src/target_kubernetes.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "target.h"
36 | #include "target_kubernetes.h"
37 |
38 | /*
39 | * CONTAINER_ID_REGEX is the regex used to extract the Docker container id from a cgroup path.
40 | * CONTAINER_ID_REGEX_EXPECTED_MATCHES is the number of matches expected from the regex. (num groups + 1)
41 | */
42 | #define CONTAINER_ID_REGEX \
43 | "perf_event/kubepods/" \
44 | "(besteffort/|burstable/|)" \
45 | "(pod[a-zA-Z0-9][a-zA-Z0-9.-]+)/" /* Pod ID */ \
46 | "([a-f0-9]{64})" /* Container ID */ \
47 | "(/[a-zA-Z0-9][a-zA-Z0-9.-]+|)" /* Resource group */
48 | #define CONTAINER_ID_REGEX_EXPECTED_MATCHES 5
49 |
50 | /*
51 | * CONTAINER_NAME_REGEX is the regex used to extract the name of the Docker container from its json configuration file.
52 | * CONTAINER_NAME_REGEX_EXPECTED_MATCHES is the number of matches expected from the regex. (num groups + 1)
53 | */
54 | #define CONTAINER_NAME_REGEX "\"Name\":\"/([a-zA-Z0-9][a-zA-Z0-9_.-]+)\""
55 | #define CONTAINER_NAME_REGEX_EXPECTED_MATCHES 2
56 |
57 |
58 | int
59 | target_kubernetes_validate(const char *cgroup_path)
60 | {
61 | regex_t re;
62 | bool is_kubernetes_target = false;
63 |
64 | if (!cgroup_path)
65 | return false;
66 |
67 | if (!regcomp(&re, CONTAINER_ID_REGEX, REG_EXTENDED | REG_NEWLINE | REG_NOSUB)) {
68 | if (!regexec(&re, cgroup_path, 0, NULL, 0))
69 | is_kubernetes_target = true;
70 |
71 | regfree(&re);
72 | }
73 |
74 | return is_kubernetes_target;
75 | }
76 |
77 | static char *
78 | build_container_config_path(const char *cgroup_path)
79 | {
80 | regex_t re;
81 | regmatch_t matches[CONTAINER_ID_REGEX_EXPECTED_MATCHES];
82 | regoff_t length;
83 | const char *id = NULL;
84 | char buffer[PATH_MAX] = {};
85 | char *config_path = NULL;
86 |
87 | if (!regcomp(&re, CONTAINER_ID_REGEX, REG_EXTENDED | REG_NEWLINE)) {
88 | if (!regexec(&re, cgroup_path, CONTAINER_ID_REGEX_EXPECTED_MATCHES, matches, 0)) {
89 | id = cgroup_path + matches[3].rm_so;
90 | length = matches[3].rm_eo - matches[3].rm_so;
91 | snprintf(buffer, PATH_MAX, "/var/lib/docker/containers/%.*s/config.v2.json", length, id);
92 | config_path = strdup(buffer);
93 | }
94 | regfree(&re);
95 | }
96 |
97 | return config_path;
98 | }
99 |
100 | char *
101 | target_kubernetes_resolve_name(struct target *target)
102 | {
103 | char *config_path = NULL;
104 | FILE *json_file = NULL;
105 | char *json = NULL;
106 | size_t json_len;
107 | regex_t re;
108 | regmatch_t matches[CONTAINER_NAME_REGEX_EXPECTED_MATCHES];
109 | char *target_name = NULL;
110 |
111 | config_path = build_container_config_path(target->cgroup_path);
112 | if (!config_path)
113 | return NULL;
114 |
115 | json_file = fopen(config_path, "r");
116 | if (json_file) {
117 | if (getline(&json, &json_len, json_file) != -1) {
118 | if (!regcomp(&re, CONTAINER_NAME_REGEX, REG_EXTENDED | REG_NEWLINE)) {
119 | if (!regexec(&re, json, CONTAINER_NAME_REGEX_EXPECTED_MATCHES, matches, 0))
120 | target_name = strndup(json + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
121 |
122 | regfree(&re);
123 | }
124 | free(json);
125 | }
126 | fclose(json_file);
127 | }
128 |
129 | free(config_path);
130 | return target_name;
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/src/target_kubernetes.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef TARGET_KUBERNETES_H
33 | #define TARGET_KUBERNETES_H
34 |
35 | #include "target.h"
36 |
37 | /*
38 | * target_kubernetes_validate check if the cgroup path lead to a valid Kubernetes target.
39 | */
40 | int target_kubernetes_validate(const char *cgroup_path);
41 |
42 | /*
43 | * target_kubernetes_resolve_name resolve and return the real name of the given target.
44 | */
45 | char *target_kubernetes_resolve_name(struct target *target);
46 |
47 | #endif /* TARGET_KUBERNETES_H */
48 |
49 |
--------------------------------------------------------------------------------
/src/util.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | #include "util.h"
38 |
39 | int *
40 | intdup(int val)
41 | {
42 | int *res = (int *) malloc(sizeof(int));
43 |
44 | if (!res)
45 | return NULL;
46 |
47 | *res = val;
48 |
49 | return res;
50 | }
51 |
52 | int *
53 | intptrdup(const int *ptr)
54 | {
55 | if (!ptr)
56 | return NULL;
57 |
58 | return intdup(*ptr);
59 | }
60 |
61 | int
62 | intcmp(int a, int b)
63 | {
64 | return (a < b) ? -1 : (a > b);
65 | }
66 |
67 | int
68 | intptrcmp(const int *a, const int *b)
69 | {
70 | return intcmp((a) ? *a : 0, (b) ? *b : 0);
71 | }
72 |
73 | uint64_t *
74 | uint64dup(uint64_t val)
75 | {
76 | uint64_t *res = (uint64_t *) malloc(sizeof(uint64_t));
77 |
78 | if (!res)
79 | return NULL;
80 |
81 | *res = val;
82 |
83 | return res;
84 | }
85 |
86 | uint64_t *
87 | uint64ptrdup(const uint64_t *ptr)
88 | {
89 | if (!ptr)
90 | return NULL;
91 |
92 | return uint64dup(*ptr);
93 | }
94 |
95 | int
96 | uint64cmp(uint64_t a, uint64_t b)
97 | {
98 | return (a < b) ? -1 : (a > b);
99 | }
100 |
101 | int
102 | uint64ptrcmp(const uint64_t *a, const uint64_t *b)
103 | {
104 | return uint64cmp((a) ? *a : 0, (b) ? *b : 0);
105 | }
106 |
107 | void
108 | ptrfree(void **ptr)
109 | {
110 | free(*ptr);
111 | *ptr = NULL;
112 | }
113 |
114 | int
115 | str_to_uint(const char *str, unsigned int *out)
116 | {
117 | unsigned long value;
118 | char *str_endp = NULL;
119 |
120 | errno = 0;
121 | value = strtoul(str, &str_endp, 0);
122 |
123 | if (errno != 0 || str == str_endp || (*str_endp != '\0' && *str_endp != '\n')) {
124 | return EINVAL;
125 | }
126 |
127 | if (value > UINT_MAX) {
128 | return ERANGE;
129 | }
130 |
131 | *out = (unsigned int) value;
132 | return 0;
133 | }
134 |
135 | int
136 | str_to_int(const char *str, int *out)
137 | {
138 | long value;
139 | char *str_endp = NULL;
140 |
141 | errno = 0;
142 | value = strtol(str, &str_endp, 0);
143 |
144 | if (errno != 0 || str == str_endp || (*str_endp != '\0' && *str_endp != '\n')) {
145 | return EINVAL;
146 | }
147 |
148 | if (value > INT_MAX) {
149 | return ERANGE;
150 | }
151 |
152 | *out = (int) value;
153 | return 0;
154 | }
155 |
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef UTIL_H
33 | #define UTIL_H
34 |
35 | #include
36 |
37 | /*
38 | * intdup returns a pointer to a new integer having the same value as val.
39 | */
40 | int *intdup(int val);
41 |
42 | /*
43 | * intptrdup returns a pointer to a new integer having the same value as the one pointed by ptr.
44 | */
45 | int *intptrdup(const int *ptr);
46 |
47 | /*
48 | * intcmp compare two integers. (same behaviour as strcmp)
49 | */
50 | int intcmp(int a, int b);
51 |
52 | /*
53 | * intptrcmp compare the value of two pointers to integer. (same behavious as strcmp)
54 | * Value having a NULL pointer is considered as 0.
55 | */
56 | int intptrcmp(const int *a, const int *b);
57 |
58 | /*
59 | * uint64dup returns a pointer to a new uint64_t having the same value as val.
60 | */
61 | uint64_t *uint64dup(uint64_t val);
62 |
63 | /*
64 | * uint64ptrdup returns a pointer to a new uint64_t having the same value as the one pointed by ptr.
65 | */
66 | uint64_t *uint64ptrdup(const uint64_t *ptr);
67 |
68 | /*
69 | * uint64cmp compare two uint64_t. (same behaviour as strcmp)
70 | */
71 | int uint64cmp(uint64_t a, uint64_t b);
72 |
73 | /*
74 | * uint64ptrcmp compare the value of two pointers to uint64_t. (same behaviour as strcmp)
75 | * Value having a NULL pointer is considered as 0.
76 | */
77 | int uint64ptrcmp(const uint64_t *a, const uint64_t *b);
78 |
79 | /*
80 | * ptrfree free the memory pointed by ptr and set ptr to NULL.
81 | */
82 | void ptrfree(void **ptr);
83 |
84 | /*
85 | * str_to_uint safely converts a string to an unsigned int.
86 | */
87 | int str_to_uint(const char *str, unsigned int *out);
88 |
89 | /*
90 | * str_to_int safely converts a string to an integer.
91 | */
92 | int str_to_int(const char *str, int *out);
93 |
94 | #endif /* UTIL_H */
95 |
--------------------------------------------------------------------------------
/src/version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018, INRIA
3 | * Copyright (c) 2018, University of Lille
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice, this
10 | * list of conditions and the following disclaimer.
11 | *
12 | * * Redistributions in binary form must reproduce the above copyright notice,
13 | * this list of conditions and the following disclaimer in the documentation
14 | * and/or other materials provided with the distribution.
15 | *
16 | * * Neither the name of the copyright holder nor the names of its
17 | * contributors may be used to endorse or promote products derived from
18 | * this software without specific prior written permission.
19 | *
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #ifndef VERSION_H
33 | #define VERSION_H
34 |
35 | /*
36 | * VERSION_GIT_TAG store the name of the current git tag.
37 | */
38 | #ifndef VERSION_GIT_TAG
39 | #define VERSION_GIT_TAG "undefined"
40 | #endif
41 |
42 | /*
43 | * VERSION_GIT_REV store the sha1 hash of the last git commit.
44 | */
45 | #ifndef VERSION_GIT_REV
46 | #define VERSION_GIT_REV "undefined"
47 | #endif
48 |
49 | #endif /* VERSION_H */
50 |
--------------------------------------------------------------------------------